get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/14510/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 14510,
    "url": "https://patches.dpdk.org/api/patches/14510/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com",
    "date": "2016-07-04T01:14:02",
    "name": "[dpdk-dev,v9,4/7] pmdinfogen: parse driver to generate code to export",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "e311a73754d39a7def5b676c75a54a6c8269af39",
    "submitter": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/people/1/?format=api",
        "name": "Thomas Monjalon",
        "email": "thomas.monjalon@6wind.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/14510/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/14510/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id E8E964B79;\n\tMon,  4 Jul 2016 03:14:19 +0200 (CEST)",
            "from mail-wm0-f45.google.com (mail-wm0-f45.google.com\n\t[74.125.82.45]) by dpdk.org (Postfix) with ESMTP id 7FA7347CE\n\tfor <dev@dpdk.org>; Mon,  4 Jul 2016 03:14:18 +0200 (CEST)",
            "by mail-wm0-f45.google.com with SMTP id z126so24032733wme.0\n\tfor <dev@dpdk.org>; Sun, 03 Jul 2016 18:14:18 -0700 (PDT)",
            "from XPS13.localdomain (184.203.134.77.rev.sfr.net.\n\t[77.134.203.184]) by smtp.gmail.com with ESMTPSA id\n\tl4sm5527127wjk.18.2016.07.03.18.14.16\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tSun, 03 Jul 2016 18:14:17 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=JYAvWrcJJcLG/3z+egtkG8epFTV6sQh77GeSGGOvo6g=;\n\tb=x6KlNaxeB05uk3vUwGP7XhFWONTxf9DFxXALr/NXyusn0iMVUFjDhMw28LLmLyDbCy\n\tY0qtvnZJeb3Rs31HOFV/889+a3mEg8PLRv3LaSBDwvLSgtfHxh39MORgCAZt96E1U4D0\n\tuWg+iXPh4ot6uZo1psDz422TsuzdCb0VjYh9/lRc2Ddp4jHYjlTwTt57INtQlwj5OhiI\n\txU52hobD7+vc/A/dxGWfK+GWPsRgVHZI9qzKhJm+AKTCNpT5i+mb1QtmrSOj8AXT2eIl\n\t/kHZXCg6hyj6o+ylBC6w3VgqeA6dzFHvepIyUC4AvvD7MEdiPulg4YdNa8k6d3X2SRkO\n\tkSAw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=JYAvWrcJJcLG/3z+egtkG8epFTV6sQh77GeSGGOvo6g=;\n\tb=I7fvdxxN9StAND1KSnf8JxNPGY7DruBYZ4GeoZBy8vJ5kDCc0VXLnM98Ba2caJlNkY\n\tgoNTdImsHo9VFUYiDs8Ikt7jAO0gkEJm13aKESCg546FjnMdzrjtWWJdOy6Aq3cF5yGz\n\tfnT3Oi/S9/sChOJ+yrife0P9vYEO0bbJziNKG3reFZ+cPSAp+gPu6aM5nLUCpba1Ght1\n\tTz5KciAXUoBixtAbprpsQK9RCZdtJJ8ax7f0UwlnTUKEPjQ5CcEj3FY6hzoci/aR3N8z\n\tP2bx4R+ClShlbSou7QgFzRJZ6Os/qyTuFJcJSOwwx8sg98ulSG0m01nuHRNk2N4sO7du\n\tcGmA==",
        "X-Gm-Message-State": "ALyK8tKytqbdZ213BuHGk82jqDys89DC+17S/n63mWIMgfpNvQdNYLbudjvsRI8SWzDKKesw",
        "X-Received": "by 10.194.117.74 with SMTP id kc10mr3701981wjb.126.1467594858031;\n\tSun, 03 Jul 2016 18:14:18 -0700 (PDT)",
        "From": "Thomas Monjalon <thomas.monjalon@6wind.com>",
        "To": "Neil Horman <nhorman@tuxdriver.com>",
        "Cc": "dev@dpdk.org,\n\tPanu Matilainen <pmatilai@redhat.com>",
        "Date": "Mon,  4 Jul 2016 03:14:02 +0200",
        "Message-Id": "<1467594845-3487-5-git-send-email-thomas.monjalon@6wind.com>",
        "X-Mailer": "git-send-email 2.7.0",
        "In-Reply-To": "<1467594845-3487-1-git-send-email-thomas.monjalon@6wind.com>",
        "References": "<1466189185-21952-1-git-send-email-nhorman@tuxdriver.com>\n\t<1467594845-3487-1-git-send-email-thomas.monjalon@6wind.com>",
        "Subject": "[dpdk-dev] [PATCH v9 4/7] pmdinfogen: parse driver to generate code\n\tto export",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Neil Horman <nhorman@tuxdriver.com>\n\ndpdk-pmdinfogen is a tool used to parse object files and build JSON\nstrings for use in later determining hardware support in a DSO or\napplication binary.\ndpdk-pmdinfogen looks for the non-exported symbol names rte_pmd_name<n>\n(where n is a integer counter) and <name>_pci_table_export.\nIt records the name of each of these tuples, using the later to find\nthe symbolic name of the PCI table for physical devices that the object\nsupports.  With this information, it outputs a C file with a single line\nof the form:\n\nstatic char *<name>_pmd_info[] __attribute__((used)) = \" \\\n\tPMD_INFO_STRING=<json_string>\";\n\nWhere <name> is the arbitrary name of the PMD, and <json_string> is the\nJSON encoded string that hold relevant PMD information, including the PMD\nname, type and optional array of PCI device/vendor IDs that the driver\nsupports.\n\nThis C file is suitable for compiling to object code, then relocatably\nlinking into the parent file from which the C was generated.  This creates\nan entry in the string table of the object that can inform a later tool\nabout hardware support.\n\nNote 1: When installed as part of a SDK package, dpdk-pmdinfogen should\n        be built for the SDK target. It is not handled currently.\nNote 2: Some generated files are not cleaned by \"make clean\".\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nAcked-by: Panu Matilainen <pmatilai@redhat.com>\nAcked-by: Remy Horton <remy.horton@intel.com>\nSigned-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>\n---\n GNUmakefile                                    |   2 +-\n MAINTAINERS                                    |   4 +\n GNUmakefile => buildtools/Makefile             |  17 +-\n GNUmakefile => buildtools/pmdinfogen/Makefile  |  21 +-\n buildtools/pmdinfogen/pmdinfogen.c             | 451 +++++++++++++++++++++++++\n buildtools/pmdinfogen/pmdinfogen.h             |  99 ++++++\n doc/guides/prog_guide/dev_kit_build_system.rst |  15 +-\n mk/rte.sdkbuild.mk                             |   2 +-\n mk/rte.sdkinstall.mk                           |   3 +\n 9 files changed, 587 insertions(+), 27 deletions(-)\n copy GNUmakefile => buildtools/Makefile (87%)\n copy GNUmakefile => buildtools/pmdinfogen/Makefile (84%)\n create mode 100644 buildtools/pmdinfogen/pmdinfogen.c\n create mode 100644 buildtools/pmdinfogen/pmdinfogen.h",
    "diff": "diff --git a/GNUmakefile b/GNUmakefile\nindex b59e4b6..00fe0db 100644\n--- a/GNUmakefile\n+++ b/GNUmakefile\n@@ -40,6 +40,6 @@ export RTE_SDK\n # directory list\n #\n \n-ROOTDIRS-y := lib drivers app\n+ROOTDIRS-y := buildtools lib drivers app\n \n include $(RTE_SDK)/mk/rte.sdkroot.mk\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex a59191e..1a8a3b7 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -68,6 +68,10 @@ F: lib/librte_compat/\n F: doc/guides/rel_notes/deprecation.rst\n F: scripts/validate-abi.sh\n \n+Driver information\n+M: Neil Horman <nhorman@tuxdriver.com>\n+F: buildtools/pmdinfogen/\n+\n \n Environment Abstraction Layer\n -----------------------------\ndiff --git a/GNUmakefile b/buildtools/Makefile\nsimilarity index 87%\ncopy from GNUmakefile\ncopy to buildtools/Makefile\nindex b59e4b6..35a42ff 100644\n--- a/GNUmakefile\n+++ b/buildtools/Makefile\n@@ -1,6 +1,6 @@\n #   BSD LICENSE\n #\n-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+#   Copyright(c) 2016 Neil Horman. All rights reserved.\n #   All rights reserved.\n #\n #   Redistribution and use in source and binary forms, with or without\n@@ -29,17 +29,8 @@\n #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n-#\n-# Head Makefile for compiling rte SDK\n-#\n-\n-RTE_SDK := $(CURDIR)\n-export RTE_SDK\n-\n-#\n-# directory list\n-#\n+include $(RTE_SDK)/mk/rte.vars.mk\n \n-ROOTDIRS-y := lib drivers app\n+DIRS-y += pmdinfogen\n \n-include $(RTE_SDK)/mk/rte.sdkroot.mk\n+include $(RTE_SDK)/mk/rte.subdir.mk\ndiff --git a/GNUmakefile b/buildtools/pmdinfogen/Makefile\nsimilarity index 84%\ncopy from GNUmakefile\ncopy to buildtools/pmdinfogen/Makefile\nindex b59e4b6..327927e 100644\n--- a/GNUmakefile\n+++ b/buildtools/pmdinfogen/Makefile\n@@ -1,6 +1,6 @@\n #   BSD LICENSE\n #\n-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+#   Copyright(c) 2016 Neil Horman. All rights reserved.\n #   All rights reserved.\n #\n #   Redistribution and use in source and binary forms, with or without\n@@ -29,17 +29,16 @@\n #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n-#\n-# Head Makefile for compiling rte SDK\n-#\n+include $(RTE_SDK)/mk/rte.vars.mk\n \n-RTE_SDK := $(CURDIR)\n-export RTE_SDK\n+HOSTAPP_DIR = buildtools\n+HOSTAPP = dpdk-pmdinfogen\n \n-#\n-# directory list\n-#\n+SRCS-y += pmdinfogen.c\n+\n+HOST_CFLAGS += $(WERROR_FLAGS) -g\n+HOST_CFLAGS += -I$(RTE_OUTPUT)/include\n \n-ROOTDIRS-y := lib drivers app\n+DEPDIRS-y += lib/librte_eal\n \n-include $(RTE_SDK)/mk/rte.sdkroot.mk\n+include $(RTE_SDK)/mk/rte.hostapp.mk\ndiff --git a/buildtools/pmdinfogen/pmdinfogen.c b/buildtools/pmdinfogen/pmdinfogen.c\nnew file mode 100644\nindex 0000000..101bce1\n--- /dev/null\n+++ b/buildtools/pmdinfogen/pmdinfogen.c\n@@ -0,0 +1,451 @@\n+/* Postprocess pmd object files to export hw support\n+ *\n+ * Copyright 2016 Neil Horman <nhorman@tuxdriver.com>\n+ * Based in part on modpost.c from the linux kernel\n+ *\n+ * This software may be used and distributed according to the terms\n+ * of the GNU General Public License V2, incorporated herein by reference.\n+ */\n+\n+#define _GNU_SOURCE\n+#include <stdio.h>\n+#include <ctype.h>\n+#include <string.h>\n+#include <limits.h>\n+#include <stdbool.h>\n+#include <errno.h>\n+#include <rte_common.h>\n+#include \"pmdinfogen.h\"\n+\n+#ifdef RTE_ARCH_64\n+#define ADDR_SIZE 64\n+#else\n+#define ADDR_SIZE 32\n+#endif\n+\n+\n+static void *\n+grab_file(const char *filename, unsigned long *size)\n+{\n+\tstruct stat st;\n+\tvoid *map = MAP_FAILED;\n+\tint fd;\n+\n+\tfd = open(filename, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn NULL;\n+\tif (fstat(fd, &st))\n+\t\tgoto failed;\n+\n+\t*size = st.st_size;\n+\tmap = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);\n+\n+failed:\n+\tclose(fd);\n+\tif (map == MAP_FAILED)\n+\t\treturn NULL;\n+\treturn map;\n+}\n+\n+/*\n+ * Return a copy of the next line in a mmap'ed file.\n+ * spaces in the beginning of the line is trimmed away.\n+ * Return a pointer to a static buffer.\n+ */\n+static void\n+release_file(void *file, unsigned long size)\n+{\n+\tmunmap(file, size);\n+}\n+\n+/*\n+ * Note, it seems odd that we have both a CONVERT_NATIVE and a TO_NATIVE macro\n+ * below.  We do this because the values passed to TO_NATIVE may themselves be\n+ * macros and need both macros here to get expanded.  Specifically its the width\n+ * variable we are concerned with, because it needs to get expanded prior to\n+ * string concatenation\n+ */\n+#define CONVERT_NATIVE(fend, width, x) ({ \\\n+typeof(x) ___x; \\\n+if ((fend) == ELFDATA2LSB) \\\n+\t___x = rte_le_to_cpu_##width(x); \\\n+else \\\n+\t___x = rte_be_to_cpu_##width(x); \\\n+\t___x; \\\n+})\n+\n+#define TO_NATIVE(fend, width, x) CONVERT_NATIVE(fend, width, x)\n+\n+static int\n+parse_elf(struct elf_info *info, const char *filename)\n+{\n+\tunsigned int i;\n+\tElf_Ehdr *hdr;\n+\tElf_Shdr *sechdrs;\n+\tElf_Sym  *sym;\n+\tint endian;\n+\tunsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;\n+\n+\thdr = grab_file(filename, &info->size);\n+\tif (!hdr) {\n+\t\tperror(filename);\n+\t\treturn -ENOENT;\n+\t}\n+\tinfo->hdr = hdr;\n+\tif (info->size < sizeof(*hdr)) {\n+\t\t/* file too small, assume this is an empty .o file */\n+\t\treturn 0;\n+\t}\n+\t/* Is this a valid ELF file? */\n+\tif ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||\n+\t    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||\n+\t    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||\n+\t    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {\n+\t\t/* Not an ELF file - silently ignore it */\n+\t\treturn 0;\n+\t}\n+\n+\tif (!hdr->e_ident[EI_DATA]) {\n+\t\t/* Unknown endian */\n+\t\treturn 0;\n+\t}\n+\n+\tendian = hdr->e_ident[EI_DATA];\n+\n+\t/* Fix endianness in ELF header */\n+\thdr->e_type      = TO_NATIVE(endian, 16, hdr->e_type);\n+\thdr->e_machine   = TO_NATIVE(endian, 16, hdr->e_machine);\n+\thdr->e_version   = TO_NATIVE(endian, 32, hdr->e_version);\n+\thdr->e_entry     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_entry);\n+\thdr->e_phoff     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_phoff);\n+\thdr->e_shoff     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_shoff);\n+\thdr->e_flags     = TO_NATIVE(endian, 32, hdr->e_flags);\n+\thdr->e_ehsize    = TO_NATIVE(endian, 16, hdr->e_ehsize);\n+\thdr->e_phentsize = TO_NATIVE(endian, 16, hdr->e_phentsize);\n+\thdr->e_phnum     = TO_NATIVE(endian, 16, hdr->e_phnum);\n+\thdr->e_shentsize = TO_NATIVE(endian, 16, hdr->e_shentsize);\n+\thdr->e_shnum     = TO_NATIVE(endian, 16, hdr->e_shnum);\n+\thdr->e_shstrndx  = TO_NATIVE(endian, 16, hdr->e_shstrndx);\n+\n+\tsechdrs = RTE_PTR_ADD(hdr, hdr->e_shoff);\n+\tinfo->sechdrs = sechdrs;\n+\n+\t/* Check if file offset is correct */\n+\tif (hdr->e_shoff > info->size) {\n+\t\tfprintf(stderr, \"section header offset=%lu in file '%s' \"\n+\t\t\t\"is bigger than filesize=%lu\\n\",\n+\t\t\t(unsigned long)hdr->e_shoff,\n+\t\t\tfilename, info->size);\n+\t\treturn 0;\n+\t}\n+\n+\tif (hdr->e_shnum == SHN_UNDEF) {\n+\t\t/*\n+\t\t * There are more than 64k sections,\n+\t\t * read count from .sh_size.\n+\t\t */\n+\t\tinfo->num_sections = TO_NATIVE(endian, 32, sechdrs[0].sh_size);\n+\t} else {\n+\t\tinfo->num_sections = hdr->e_shnum;\n+\t}\n+\tif (hdr->e_shstrndx == SHN_XINDEX)\n+\t\tinfo->secindex_strings =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[0].sh_link);\n+\telse\n+\t\tinfo->secindex_strings = hdr->e_shstrndx;\n+\n+\t/* Fix endianness in section headers */\n+\tfor (i = 0; i < info->num_sections; i++) {\n+\t\tsechdrs[i].sh_name      =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_name);\n+\t\tsechdrs[i].sh_type      =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_type);\n+\t\tsechdrs[i].sh_flags     =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_flags);\n+\t\tsechdrs[i].sh_addr      =\n+\t\t\tTO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addr);\n+\t\tsechdrs[i].sh_offset    =\n+\t\t\tTO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_offset);\n+\t\tsechdrs[i].sh_size      =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_size);\n+\t\tsechdrs[i].sh_link      =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_link);\n+\t\tsechdrs[i].sh_info      =\n+\t\t\tTO_NATIVE(endian, 32, sechdrs[i].sh_info);\n+\t\tsechdrs[i].sh_addralign =\n+\t\t\tTO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addralign);\n+\t\tsechdrs[i].sh_entsize   =\n+\t\t\tTO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_entsize);\n+\t}\n+\t/* Find symbol table. */\n+\tfor (i = 1; i < info->num_sections; i++) {\n+\t\tint nobits = sechdrs[i].sh_type == SHT_NOBITS;\n+\n+\t\tif (!nobits && sechdrs[i].sh_offset > info->size) {\n+\t\t\tfprintf(stderr, \"%s is truncated. \"\n+\t\t\t\t\"sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\\n\",\n+\t\t\t\tfilename, (unsigned long)sechdrs[i].sh_offset,\n+\t\t\t\tsizeof(*hdr));\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tif (sechdrs[i].sh_type == SHT_SYMTAB) {\n+\t\t\tunsigned int sh_link_idx;\n+\t\t\tsymtab_idx = i;\n+\t\t\tinfo->symtab_start = RTE_PTR_ADD(hdr,\n+\t\t\t\tsechdrs[i].sh_offset);\n+\t\t\tinfo->symtab_stop  = RTE_PTR_ADD(hdr,\n+\t\t\t\tsechdrs[i].sh_offset + sechdrs[i].sh_size);\n+\t\t\tsh_link_idx = sechdrs[i].sh_link;\n+\t\t\tinfo->strtab       = RTE_PTR_ADD(hdr,\n+\t\t\t\tsechdrs[sh_link_idx].sh_offset);\n+\t\t}\n+\n+\t\t/* 32bit section no. table? (\"more than 64k sections\") */\n+\t\tif (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {\n+\t\t\tsymtab_shndx_idx = i;\n+\t\t\tinfo->symtab_shndx_start = RTE_PTR_ADD(hdr,\n+\t\t\t\tsechdrs[i].sh_offset);\n+\t\t\tinfo->symtab_shndx_stop  = RTE_PTR_ADD(hdr,\n+\t\t\t\tsechdrs[i].sh_offset + sechdrs[i].sh_size);\n+\t\t}\n+\t}\n+\tif (!info->symtab_start)\n+\t\tfprintf(stderr, \"%s has no symtab?\\n\", filename);\n+\n+\t/* Fix endianness in symbols */\n+\tfor (sym = info->symtab_start; sym < info->symtab_stop; sym++) {\n+\t\tsym->st_shndx = TO_NATIVE(endian, 16, sym->st_shndx);\n+\t\tsym->st_name  = TO_NATIVE(endian, 32, sym->st_name);\n+\t\tsym->st_value = TO_NATIVE(endian, ADDR_SIZE, sym->st_value);\n+\t\tsym->st_size  = TO_NATIVE(endian, ADDR_SIZE, sym->st_size);\n+\t}\n+\n+\tif (symtab_shndx_idx != ~0U) {\n+\t\tElf32_Word *p;\n+\t\tif (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\\n\",\n+\t\t\t\tfilename, sechdrs[symtab_shndx_idx].sh_link,\n+\t\t\t\tsymtab_idx);\n+\t\t/* Fix endianness */\n+\t\tfor (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; p++)\n+\t\t\t*p = TO_NATIVE(endian, 32, *p);\n+\t}\n+\n+\treturn 1;\n+}\n+\n+static void\n+parse_elf_finish(struct elf_info *info)\n+{\n+\tstruct pmd_driver *tmp, *idx = info->drivers;\n+\trelease_file(info->hdr, info->size);\n+\twhile (idx) {\n+\t\ttmp = idx->next;\n+\t\tfree(idx);\n+\t\tidx = tmp;\n+\t}\n+}\n+\n+static const char *\n+get_sym_name(struct elf_info *elf, Elf_Sym *sym)\n+{\n+\tif (sym)\n+\t\treturn elf->strtab + sym->st_name;\n+\telse\n+\t\treturn \"(unknown)\";\n+}\n+\n+static void *\n+get_sym_value(struct elf_info *info, const Elf_Sym *sym)\n+{\n+\treturn RTE_PTR_ADD(info->hdr,\n+\t\tinfo->sechdrs[sym->st_shndx].sh_offset + sym->st_value);\n+}\n+\n+static Elf_Sym *\n+find_sym_in_symtab(struct elf_info *info, const char *name, Elf_Sym *last)\n+{\n+\tElf_Sym *idx;\n+\tif (last)\n+\t\tidx = last+1;\n+\telse\n+\t\tidx = info->symtab_start;\n+\n+\tfor (; idx < info->symtab_stop; idx++) {\n+\t\tconst char *n = get_sym_name(info, idx);\n+\t\tif (!strncmp(n, name, strlen(name)))\n+\t\t\treturn idx;\n+\t}\n+\treturn NULL;\n+}\n+\n+struct opt_tag {\n+\tconst char *suffix;\n+\tconst char *json_id;\n+};\n+\n+static const struct opt_tag opt_tags[] = {\n+\t{\"_param_string_export\", \"params\"},\n+};\n+\n+static int\n+complete_pmd_entry(struct elf_info *info, struct pmd_driver *drv)\n+{\n+\tconst char *tname;\n+\tint i;\n+\tchar tmpsymname[128];\n+\tElf_Sym *tmpsym;\n+\n+\tdrv->name = get_sym_value(info, drv->name_sym);\n+\n+\tfor (i = 0; i < PMD_OPT_MAX; i++) {\n+\t\tmemset(tmpsymname, 0, 128);\n+\t\tsprintf(tmpsymname, \"__%s%s\", drv->name, opt_tags[i].suffix);\n+\t\ttmpsym = find_sym_in_symtab(info, tmpsymname, NULL);\n+\t\tif (!tmpsym)\n+\t\t\tcontinue;\n+\t\tdrv->opt_vals[i] = get_sym_value(info, tmpsym);\n+\t}\n+\n+\tmemset(tmpsymname, 0, 128);\n+\tsprintf(tmpsymname, \"__%s_pci_table_export\", drv->name);\n+\n+\ttmpsym = find_sym_in_symtab(info, tmpsymname, NULL);\n+\n+\t/*\n+\t * If this returns NULL, then this is a PMD_VDEV, because\n+\t * it has no pci table reference\n+\t */\n+\tif (!tmpsym) {\n+\t\tdrv->pci_tbl = NULL;\n+\t\treturn 0;\n+\t}\n+\n+\ttname = get_sym_value(info, tmpsym);\n+\ttmpsym = find_sym_in_symtab(info, tname, NULL);\n+\tif (!tmpsym) {\n+\t\tfprintf(stderr, \"No symbol %s\\n\", tname);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tdrv->pci_tbl = (struct rte_pci_id *)get_sym_value(info, tmpsym);\n+\tif (!drv->pci_tbl) {\n+\t\tfprintf(stderr, \"Failed to get PCI table %s\\n\", tname);\n+\t\treturn -ENOENT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+locate_pmd_entries(struct elf_info *info)\n+{\n+\tElf_Sym *last = NULL;\n+\tstruct pmd_driver *new;\n+\n+\tinfo->drivers = NULL;\n+\n+\tdo {\n+\t\tnew = calloc(sizeof(struct pmd_driver), 1);\n+\t\tnew->name_sym = find_sym_in_symtab(info, \"rte_pmd_name\", last);\n+\t\tlast = new->name_sym;\n+\t\tif (!new->name_sym)\n+\t\t\tfree(new);\n+\t\telse {\n+\t\t\tif (complete_pmd_entry(info, new)) {\n+\t\t\t\tfprintf(stderr, \"Failed to complete pmd entry\\n\");\n+\t\t\t\tfree(new);\n+\t\t\t\treturn -ENOENT;\n+\t\t\t} else {\n+\t\t\t\tnew->next = info->drivers;\n+\t\t\t\tinfo->drivers = new;\n+\t\t\t}\n+\t\t}\n+\t} while (last);\n+\n+\treturn 0;\n+}\n+\n+static void\n+output_pmd_info_string(struct elf_info *info, char *outfile)\n+{\n+\tFILE *ofd;\n+\tstruct pmd_driver *drv;\n+\tstruct rte_pci_id *pci_ids;\n+\tint idx = 0;\n+\n+\tofd = fopen(outfile, \"w+\");\n+\tif (!ofd) {\n+\t\tfprintf(stderr, \"Unable to open output file\\n\");\n+\t\treturn;\n+\t}\n+\n+\tdrv = info->drivers;\n+\n+\twhile (drv) {\n+\t\tfprintf(ofd, \"const char %s_pmd_info[] __attribute__((used)) = \"\n+\t\t\t\"\\\"PMD_INFO_STRING= {\",\n+\t\t\tdrv->name);\n+\t\tfprintf(ofd, \"\\\\\\\"name\\\\\\\" : \\\\\\\"%s\\\\\\\", \", drv->name);\n+\n+\t\tfor (idx = 0; idx < PMD_OPT_MAX; idx++) {\n+\t\t\tif (drv->opt_vals[idx])\n+\t\t\t\tfprintf(ofd, \"\\\\\\\"%s\\\\\\\" : \\\\\\\"%s\\\\\\\", \",\n+\t\t\t\t\topt_tags[idx].json_id,\n+\t\t\t\t\tdrv->opt_vals[idx]);\n+\t\t}\n+\n+\t\tpci_ids = drv->pci_tbl;\n+\t\tfprintf(ofd, \"\\\\\\\"pci_ids\\\\\\\" : [\");\n+\n+\t\twhile (pci_ids && pci_ids->device_id) {\n+\t\t\tfprintf(ofd, \"[%d, %d, %d, %d]\",\n+\t\t\t\tpci_ids->vendor_id, pci_ids->device_id,\n+\t\t\t\tpci_ids->subsystem_vendor_id,\n+\t\t\t\tpci_ids->subsystem_device_id);\n+\t\t\tpci_ids++;\n+\t\t\tif (pci_ids->device_id)\n+\t\t\t\tfprintf(ofd, \",\");\n+\t\t\telse\n+\t\t\t\tfprintf(ofd, \" \");\n+\t\t}\n+\t\tfprintf(ofd, \"]}\\\";\");\n+\t\tdrv = drv->next;\n+\t}\n+\n+\tfclose(ofd);\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tstruct elf_info info;\n+\tint rc;\n+\n+\tif (argc < 3) {\n+\t\tfprintf(stderr,\n+\t\t\t\"usage: dpdk-pmdinfogen <object file> <c output file>\\n\");\n+\t\texit(127);\n+\t}\n+\n+\trc = parse_elf(&info, argv[1]);\n+\tif (rc < 0)\n+\t\texit(-rc);\n+\n+\trc = locate_pmd_entries(&info);\n+\tif (rc < 0)\n+\t\tgoto error;\n+\n+\tif (info.drivers) {\n+\t\toutput_pmd_info_string(&info, argv[2]);\n+\t\trc = 0;\n+\t} else {\n+\t\trc = -1;\n+\t\tfprintf(stderr, \"No drivers registered\\n\");\n+\t}\n+\n+error:\n+\tparse_elf_finish(&info);\n+\texit(-rc);\n+}\ndiff --git a/buildtools/pmdinfogen/pmdinfogen.h b/buildtools/pmdinfogen/pmdinfogen.h\nnew file mode 100644\nindex 0000000..7e57702\n--- /dev/null\n+++ b/buildtools/pmdinfogen/pmdinfogen.h\n@@ -0,0 +1,99 @@\n+/* Postprocess pmd object files to export hw support\n+ *\n+ * Copyright 2016 Neil Horman <nhorman@tuxdriver.com>\n+ * Based in part on modpost.c from the linux kernel\n+ *\n+ * This software may be used and distributed according to the terms\n+ * of the GNU General Public License V2, incorporated herein by reference.\n+ */\n+\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <stdarg.h>\n+#include <string.h>\n+#include <sys/types.h>\n+#include <sys/stat.h>\n+#include <sys/mman.h>\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <elf.h>\n+#include <rte_config.h>\n+#include <rte_pci.h>\n+#include <rte_byteorder.h>\n+\n+/* On BSD-alike OSes elf.h defines these according to host's word size */\n+#undef ELF_ST_BIND\n+#undef ELF_ST_TYPE\n+#undef ELF_R_SYM\n+#undef ELF_R_TYPE\n+\n+/*\n+ * Define ELF64_* to ELF_*, the latter being defined in both 32 and 64 bit\n+ * flavors in elf.h.  This makes our code a bit more generic between arches\n+ * and allows us to support 32 bit code in the future should we ever want to\n+ */\n+#ifdef RTE_ARCH_64\n+#define Elf_Ehdr    Elf64_Ehdr\n+#define Elf_Shdr    Elf64_Shdr\n+#define Elf_Sym     Elf64_Sym\n+#define Elf_Addr    Elf64_Addr\n+#define Elf_Sword   Elf64_Sxword\n+#define Elf_Section Elf64_Half\n+#define ELF_ST_BIND ELF64_ST_BIND\n+#define ELF_ST_TYPE ELF64_ST_TYPE\n+\n+#define Elf_Rel     Elf64_Rel\n+#define Elf_Rela    Elf64_Rela\n+#define ELF_R_SYM   ELF64_R_SYM\n+#define ELF_R_TYPE  ELF64_R_TYPE\n+#else\n+#define Elf_Ehdr    Elf32_Ehdr\n+#define Elf_Shdr    Elf32_Shdr\n+#define Elf_Sym     Elf32_Sym\n+#define Elf_Addr    Elf32_Addr\n+#define Elf_Sword   Elf32_Sxword\n+#define Elf_Section Elf32_Half\n+#define ELF_ST_BIND ELF32_ST_BIND\n+#define ELF_ST_TYPE ELF32_ST_TYPE\n+\n+#define Elf_Rel     Elf32_Rel\n+#define Elf_Rela    Elf32_Rela\n+#define ELF_R_SYM   ELF32_R_SYM\n+#define ELF_R_TYPE  ELF32_R_TYPE\n+#endif\n+\n+\n+enum opt_params {\n+\tPMD_PARAM_STRING = 0,\n+\tPMD_OPT_MAX\n+};\n+\n+struct pmd_driver {\n+\tElf_Sym *name_sym;\n+\tconst char *name;\n+\tstruct rte_pci_id *pci_tbl;\n+\tstruct pmd_driver *next;\n+\n+\tconst char *opt_vals[PMD_OPT_MAX];\n+};\n+\n+struct elf_info {\n+\tunsigned long size;\n+\tElf_Ehdr     *hdr;\n+\tElf_Shdr     *sechdrs;\n+\tElf_Sym      *symtab_start;\n+\tElf_Sym      *symtab_stop;\n+\tchar         *strtab;\n+\n+\t/* support for 32bit section numbers */\n+\n+\tunsigned int num_sections; /* max_secindex + 1 */\n+\tunsigned int secindex_strings;\n+\t/* if Nth symbol table entry has .st_shndx = SHN_XINDEX,\n+\t * take shndx from symtab_shndx_start[N] instead\n+\t */\n+\tElf32_Word   *symtab_shndx_start;\n+\tElf32_Word   *symtab_shndx_stop;\n+\n+\tstruct pmd_driver *drivers;\n+};\ndiff --git a/doc/guides/prog_guide/dev_kit_build_system.rst b/doc/guides/prog_guide/dev_kit_build_system.rst\nindex dedd18a..fa34fe0 100644\n--- a/doc/guides/prog_guide/dev_kit_build_system.rst\n+++ b/doc/guides/prog_guide/dev_kit_build_system.rst\n@@ -70,7 +70,7 @@ Each build directory contains include files, libraries, and applications:\n     ...\n     ~/DEV/DPDK$ ls i686-native-linuxapp-gcc\n \n-    app build hostapp include kmod lib Makefile\n+    app build buildtools include kmod lib Makefile\n \n \n     ~/DEV/DPDK$ ls i686-native-linuxapp-gcc/app/\n@@ -307,6 +307,7 @@ Misc\n Internally Generated Build Tools\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n \n+``dpdk-pmdinfogen`` scans an object (.o) file for various well known symbol names.\n These well known symbol names are defined by various macros and used to export\n important information about hardware support and usage for PMD files.  For\n instance the macro:\n@@ -321,6 +322,18 @@ Creates the following symbol:\n \n    static char rte_pmd_name0[] __attribute__((used)) = \"<name>\";\n \n+Which dpdk-pmdinfogen scans for.  Using this information other relevant bits of\n+data can be exported from the object file and used to produce a hardware support\n+description, that dpdk-pmdinfogen then encodes into a json formatted string in\n+the following format:\n+\n+.. code-block:: C\n+\n+   static char <name_pmd_string>=\"PMD_INFO_STRING=\\\"{'name' : '<name>', ...}\\\"\";\n+\n+These strings can then be searched for by external tools to determine the\n+hardware support of a given library or application.\n+\n .. _Useful_Variables_Provided_by_the_Build_System:\n \n Useful Variables Provided by the Build System\ndiff --git a/mk/rte.sdkbuild.mk b/mk/rte.sdkbuild.mk\nindex f1a163a..5edbf50 100644\n--- a/mk/rte.sdkbuild.mk\n+++ b/mk/rte.sdkbuild.mk\n@@ -63,7 +63,7 @@ build: $(ROOTDIRS-y)\n .PHONY: clean\n clean: $(CLEANDIRS)\n \t@rm -rf $(RTE_OUTPUT)/include $(RTE_OUTPUT)/app \\\n-\t\t$(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod\n+\t\t$(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod $(RTE_OUTPUT)/buildtools\n \t@[ -d $(RTE_OUTPUT)/include ] || mkdir -p $(RTE_OUTPUT)/include\n \t@$(RTE_SDK)/scripts/gen-config-h.sh $(RTE_OUTPUT)/.config \\\n \t\t> $(RTE_OUTPUT)/include/rte_config.h\ndiff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk\nindex abdab0f..2b92157 100644\n--- a/mk/rte.sdkinstall.mk\n+++ b/mk/rte.sdkinstall.mk\n@@ -141,10 +141,13 @@ install-sdk:\n \t$(Q)$(call rte_mkdir,                            $(DESTDIR)$(sdkdir))\n \t$(Q)cp -a               $(RTE_SDK)/mk            $(DESTDIR)$(sdkdir)\n \t$(Q)cp -a               $(RTE_SDK)/scripts       $(DESTDIR)$(sdkdir)\n+\t$(Q)cp -a               $O/buildtools            $(DESTDIR)$(sdkdir)\n \t$(Q)$(call rte_mkdir,                            $(DESTDIR)$(targetdir))\n \t$(Q)cp -a               $O/.config               $(DESTDIR)$(targetdir)\n \t$(Q)$(call rte_symlink, $(DESTDIR)$(includedir), $(DESTDIR)$(targetdir)/include)\n \t$(Q)$(call rte_symlink, $(DESTDIR)$(libdir),     $(DESTDIR)$(targetdir)/lib)\n+\t$(Q)$(call rte_symlink, $(DESTDIR)$(sdkdir)/buildtools, \\\n+\t                        $(DESTDIR)$(targetdir)/buildtools)\n \n install-doc:\n ifneq ($(wildcard $O/doc),)\n",
    "prefixes": [
        "dpdk-dev",
        "v9",
        "4/7"
    ]
}