[dpdk-dev] [PATCH v9 4/7] pmdinfogen: parse driver to generate code to export

Thomas Monjalon thomas.monjalon at 6wind.com
Mon Jul 4 03:14:02 CEST 2016


From: Neil Horman <nhorman at tuxdriver.com>

dpdk-pmdinfogen is a tool used to parse object files and build JSON
strings for use in later determining hardware support in a DSO or
application binary.
dpdk-pmdinfogen looks for the non-exported symbol names rte_pmd_name<n>
(where n is a integer counter) and <name>_pci_table_export.
It records the name of each of these tuples, using the later to find
the symbolic name of the PCI table for physical devices that the object
supports.  With this information, it outputs a C file with a single line
of the form:

static char *<name>_pmd_info[] __attribute__((used)) = " \
	PMD_INFO_STRING=<json_string>";

Where <name> is the arbitrary name of the PMD, and <json_string> is the
JSON encoded string that hold relevant PMD information, including the PMD
name, type and optional array of PCI device/vendor IDs that the driver
supports.

This C file is suitable for compiling to object code, then relocatably
linking into the parent file from which the C was generated.  This creates
an entry in the string table of the object that can inform a later tool
about hardware support.

Note 1: When installed as part of a SDK package, dpdk-pmdinfogen should
        be built for the SDK target. It is not handled currently.
Note 2: Some generated files are not cleaned by "make clean".

Signed-off-by: Neil Horman <nhorman at tuxdriver.com>
Acked-by: Panu Matilainen <pmatilai at redhat.com>
Acked-by: Remy Horton <remy.horton at intel.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon at 6wind.com>
---
 GNUmakefile                                    |   2 +-
 MAINTAINERS                                    |   4 +
 GNUmakefile => buildtools/Makefile             |  17 +-
 GNUmakefile => buildtools/pmdinfogen/Makefile  |  21 +-
 buildtools/pmdinfogen/pmdinfogen.c             | 451 +++++++++++++++++++++++++
 buildtools/pmdinfogen/pmdinfogen.h             |  99 ++++++
 doc/guides/prog_guide/dev_kit_build_system.rst |  15 +-
 mk/rte.sdkbuild.mk                             |   2 +-
 mk/rte.sdkinstall.mk                           |   3 +
 9 files changed, 587 insertions(+), 27 deletions(-)
 copy GNUmakefile => buildtools/Makefile (87%)
 copy GNUmakefile => buildtools/pmdinfogen/Makefile (84%)
 create mode 100644 buildtools/pmdinfogen/pmdinfogen.c
 create mode 100644 buildtools/pmdinfogen/pmdinfogen.h

diff --git a/GNUmakefile b/GNUmakefile
index b59e4b6..00fe0db 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -40,6 +40,6 @@ export RTE_SDK
 # directory list
 #
 
-ROOTDIRS-y := lib drivers app
+ROOTDIRS-y := buildtools lib drivers app
 
 include $(RTE_SDK)/mk/rte.sdkroot.mk
diff --git a/MAINTAINERS b/MAINTAINERS
index a59191e..1a8a3b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -68,6 +68,10 @@ F: lib/librte_compat/
 F: doc/guides/rel_notes/deprecation.rst
 F: scripts/validate-abi.sh
 
+Driver information
+M: Neil Horman <nhorman at tuxdriver.com>
+F: buildtools/pmdinfogen/
+
 
 Environment Abstraction Layer
 -----------------------------
diff --git a/GNUmakefile b/buildtools/Makefile
similarity index 87%
copy from GNUmakefile
copy to buildtools/Makefile
index b59e4b6..35a42ff 100644
--- a/GNUmakefile
+++ b/buildtools/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2016 Neil Horman. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -29,17 +29,8 @@
 #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#
-# Head Makefile for compiling rte SDK
-#
-
-RTE_SDK := $(CURDIR)
-export RTE_SDK
-
-#
-# directory list
-#
+include $(RTE_SDK)/mk/rte.vars.mk
 
-ROOTDIRS-y := lib drivers app
+DIRS-y += pmdinfogen
 
-include $(RTE_SDK)/mk/rte.sdkroot.mk
+include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/GNUmakefile b/buildtools/pmdinfogen/Makefile
similarity index 84%
copy from GNUmakefile
copy to buildtools/pmdinfogen/Makefile
index b59e4b6..327927e 100644
--- a/GNUmakefile
+++ b/buildtools/pmdinfogen/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2016 Neil Horman. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -29,17 +29,16 @@
 #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#
-# Head Makefile for compiling rte SDK
-#
+include $(RTE_SDK)/mk/rte.vars.mk
 
-RTE_SDK := $(CURDIR)
-export RTE_SDK
+HOSTAPP_DIR = buildtools
+HOSTAPP = dpdk-pmdinfogen
 
-#
-# directory list
-#
+SRCS-y += pmdinfogen.c
+
+HOST_CFLAGS += $(WERROR_FLAGS) -g
+HOST_CFLAGS += -I$(RTE_OUTPUT)/include
 
-ROOTDIRS-y := lib drivers app
+DEPDIRS-y += lib/librte_eal
 
-include $(RTE_SDK)/mk/rte.sdkroot.mk
+include $(RTE_SDK)/mk/rte.hostapp.mk
diff --git a/buildtools/pmdinfogen/pmdinfogen.c b/buildtools/pmdinfogen/pmdinfogen.c
new file mode 100644
index 0000000..101bce1
--- /dev/null
+++ b/buildtools/pmdinfogen/pmdinfogen.c
@@ -0,0 +1,451 @@
+/* Postprocess pmd object files to export hw support
+ *
+ * Copyright 2016 Neil Horman <nhorman at tuxdriver.com>
+ * Based in part on modpost.c from the linux kernel
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License V2, incorporated herein by reference.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <rte_common.h>
+#include "pmdinfogen.h"
+
+#ifdef RTE_ARCH_64
+#define ADDR_SIZE 64
+#else
+#define ADDR_SIZE 32
+#endif
+
+
+static void *
+grab_file(const char *filename, unsigned long *size)
+{
+	struct stat st;
+	void *map = MAP_FAILED;
+	int fd;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return NULL;
+	if (fstat(fd, &st))
+		goto failed;
+
+	*size = st.st_size;
+	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+failed:
+	close(fd);
+	if (map == MAP_FAILED)
+		return NULL;
+	return map;
+}
+
+/*
+ * Return a copy of the next line in a mmap'ed file.
+ * spaces in the beginning of the line is trimmed away.
+ * Return a pointer to a static buffer.
+ */
+static void
+release_file(void *file, unsigned long size)
+{
+	munmap(file, size);
+}
+
+/*
+ * Note, it seems odd that we have both a CONVERT_NATIVE and a TO_NATIVE macro
+ * below.  We do this because the values passed to TO_NATIVE may themselves be
+ * macros and need both macros here to get expanded.  Specifically its the width
+ * variable we are concerned with, because it needs to get expanded prior to
+ * string concatenation
+ */
+#define CONVERT_NATIVE(fend, width, x) ({ \
+typeof(x) ___x; \
+if ((fend) == ELFDATA2LSB) \
+	___x = rte_le_to_cpu_##width(x); \
+else \
+	___x = rte_be_to_cpu_##width(x); \
+	___x; \
+})
+
+#define TO_NATIVE(fend, width, x) CONVERT_NATIVE(fend, width, x)
+
+static int
+parse_elf(struct elf_info *info, const char *filename)
+{
+	unsigned int i;
+	Elf_Ehdr *hdr;
+	Elf_Shdr *sechdrs;
+	Elf_Sym  *sym;
+	int endian;
+	unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
+
+	hdr = grab_file(filename, &info->size);
+	if (!hdr) {
+		perror(filename);
+		return -ENOENT;
+	}
+	info->hdr = hdr;
+	if (info->size < sizeof(*hdr)) {
+		/* file too small, assume this is an empty .o file */
+		return 0;
+	}
+	/* Is this a valid ELF file? */
+	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+		/* Not an ELF file - silently ignore it */
+		return 0;
+	}
+
+	if (!hdr->e_ident[EI_DATA]) {
+		/* Unknown endian */
+		return 0;
+	}
+
+	endian = hdr->e_ident[EI_DATA];
+
+	/* Fix endianness in ELF header */
+	hdr->e_type      = TO_NATIVE(endian, 16, hdr->e_type);
+	hdr->e_machine   = TO_NATIVE(endian, 16, hdr->e_machine);
+	hdr->e_version   = TO_NATIVE(endian, 32, hdr->e_version);
+	hdr->e_entry     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_entry);
+	hdr->e_phoff     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_phoff);
+	hdr->e_shoff     = TO_NATIVE(endian, ADDR_SIZE, hdr->e_shoff);
+	hdr->e_flags     = TO_NATIVE(endian, 32, hdr->e_flags);
+	hdr->e_ehsize    = TO_NATIVE(endian, 16, hdr->e_ehsize);
+	hdr->e_phentsize = TO_NATIVE(endian, 16, hdr->e_phentsize);
+	hdr->e_phnum     = TO_NATIVE(endian, 16, hdr->e_phnum);
+	hdr->e_shentsize = TO_NATIVE(endian, 16, hdr->e_shentsize);
+	hdr->e_shnum     = TO_NATIVE(endian, 16, hdr->e_shnum);
+	hdr->e_shstrndx  = TO_NATIVE(endian, 16, hdr->e_shstrndx);
+
+	sechdrs = RTE_PTR_ADD(hdr, hdr->e_shoff);
+	info->sechdrs = sechdrs;
+
+	/* Check if file offset is correct */
+	if (hdr->e_shoff > info->size) {
+		fprintf(stderr, "section header offset=%lu in file '%s' "
+			"is bigger than filesize=%lu\n",
+			(unsigned long)hdr->e_shoff,
+			filename, info->size);
+		return 0;
+	}
+
+	if (hdr->e_shnum == SHN_UNDEF) {
+		/*
+		 * There are more than 64k sections,
+		 * read count from .sh_size.
+		 */
+		info->num_sections = TO_NATIVE(endian, 32, sechdrs[0].sh_size);
+	} else {
+		info->num_sections = hdr->e_shnum;
+	}
+	if (hdr->e_shstrndx == SHN_XINDEX)
+		info->secindex_strings =
+			TO_NATIVE(endian, 32, sechdrs[0].sh_link);
+	else
+		info->secindex_strings = hdr->e_shstrndx;
+
+	/* Fix endianness in section headers */
+	for (i = 0; i < info->num_sections; i++) {
+		sechdrs[i].sh_name      =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_name);
+		sechdrs[i].sh_type      =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_type);
+		sechdrs[i].sh_flags     =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_flags);
+		sechdrs[i].sh_addr      =
+			TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addr);
+		sechdrs[i].sh_offset    =
+			TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_offset);
+		sechdrs[i].sh_size      =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_size);
+		sechdrs[i].sh_link      =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_link);
+		sechdrs[i].sh_info      =
+			TO_NATIVE(endian, 32, sechdrs[i].sh_info);
+		sechdrs[i].sh_addralign =
+			TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_addralign);
+		sechdrs[i].sh_entsize   =
+			TO_NATIVE(endian, ADDR_SIZE, sechdrs[i].sh_entsize);
+	}
+	/* Find symbol table. */
+	for (i = 1; i < info->num_sections; i++) {
+		int nobits = sechdrs[i].sh_type == SHT_NOBITS;
+
+		if (!nobits && sechdrs[i].sh_offset > info->size) {
+			fprintf(stderr, "%s is truncated. "
+				"sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n",
+				filename, (unsigned long)sechdrs[i].sh_offset,
+				sizeof(*hdr));
+			return 0;
+		}
+
+		if (sechdrs[i].sh_type == SHT_SYMTAB) {
+			unsigned int sh_link_idx;
+			symtab_idx = i;
+			info->symtab_start = RTE_PTR_ADD(hdr,
+				sechdrs[i].sh_offset);
+			info->symtab_stop  = RTE_PTR_ADD(hdr,
+				sechdrs[i].sh_offset + sechdrs[i].sh_size);
+			sh_link_idx = sechdrs[i].sh_link;
+			info->strtab       = RTE_PTR_ADD(hdr,
+				sechdrs[sh_link_idx].sh_offset);
+		}
+
+		/* 32bit section no. table? ("more than 64k sections") */
+		if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+			symtab_shndx_idx = i;
+			info->symtab_shndx_start = RTE_PTR_ADD(hdr,
+				sechdrs[i].sh_offset);
+			info->symtab_shndx_stop  = RTE_PTR_ADD(hdr,
+				sechdrs[i].sh_offset + sechdrs[i].sh_size);
+		}
+	}
+	if (!info->symtab_start)
+		fprintf(stderr, "%s has no symtab?\n", filename);
+
+	/* Fix endianness in symbols */
+	for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
+		sym->st_shndx = TO_NATIVE(endian, 16, sym->st_shndx);
+		sym->st_name  = TO_NATIVE(endian, 32, sym->st_name);
+		sym->st_value = TO_NATIVE(endian, ADDR_SIZE, sym->st_value);
+		sym->st_size  = TO_NATIVE(endian, ADDR_SIZE, sym->st_size);
+	}
+
+	if (symtab_shndx_idx != ~0U) {
+		Elf32_Word *p;
+		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
+			fprintf(stderr,
+				"%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+				filename, sechdrs[symtab_shndx_idx].sh_link,
+				symtab_idx);
+		/* Fix endianness */
+		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; p++)
+			*p = TO_NATIVE(endian, 32, *p);
+	}
+
+	return 1;
+}
+
+static void
+parse_elf_finish(struct elf_info *info)
+{
+	struct pmd_driver *tmp, *idx = info->drivers;
+	release_file(info->hdr, info->size);
+	while (idx) {
+		tmp = idx->next;
+		free(idx);
+		idx = tmp;
+	}
+}
+
+static const char *
+get_sym_name(struct elf_info *elf, Elf_Sym *sym)
+{
+	if (sym)
+		return elf->strtab + sym->st_name;
+	else
+		return "(unknown)";
+}
+
+static void *
+get_sym_value(struct elf_info *info, const Elf_Sym *sym)
+{
+	return RTE_PTR_ADD(info->hdr,
+		info->sechdrs[sym->st_shndx].sh_offset + sym->st_value);
+}
+
+static Elf_Sym *
+find_sym_in_symtab(struct elf_info *info, const char *name, Elf_Sym *last)
+{
+	Elf_Sym *idx;
+	if (last)
+		idx = last+1;
+	else
+		idx = info->symtab_start;
+
+	for (; idx < info->symtab_stop; idx++) {
+		const char *n = get_sym_name(info, idx);
+		if (!strncmp(n, name, strlen(name)))
+			return idx;
+	}
+	return NULL;
+}
+
+struct opt_tag {
+	const char *suffix;
+	const char *json_id;
+};
+
+static const struct opt_tag opt_tags[] = {
+	{"_param_string_export", "params"},
+};
+
+static int
+complete_pmd_entry(struct elf_info *info, struct pmd_driver *drv)
+{
+	const char *tname;
+	int i;
+	char tmpsymname[128];
+	Elf_Sym *tmpsym;
+
+	drv->name = get_sym_value(info, drv->name_sym);
+
+	for (i = 0; i < PMD_OPT_MAX; i++) {
+		memset(tmpsymname, 0, 128);
+		sprintf(tmpsymname, "__%s%s", drv->name, opt_tags[i].suffix);
+		tmpsym = find_sym_in_symtab(info, tmpsymname, NULL);
+		if (!tmpsym)
+			continue;
+		drv->opt_vals[i] = get_sym_value(info, tmpsym);
+	}
+
+	memset(tmpsymname, 0, 128);
+	sprintf(tmpsymname, "__%s_pci_table_export", drv->name);
+
+	tmpsym = find_sym_in_symtab(info, tmpsymname, NULL);
+
+	/*
+	 * If this returns NULL, then this is a PMD_VDEV, because
+	 * it has no pci table reference
+	 */
+	if (!tmpsym) {
+		drv->pci_tbl = NULL;
+		return 0;
+	}
+
+	tname = get_sym_value(info, tmpsym);
+	tmpsym = find_sym_in_symtab(info, tname, NULL);
+	if (!tmpsym) {
+		fprintf(stderr, "No symbol %s\n", tname);
+		return -ENOENT;
+	}
+
+	drv->pci_tbl = (struct rte_pci_id *)get_sym_value(info, tmpsym);
+	if (!drv->pci_tbl) {
+		fprintf(stderr, "Failed to get PCI table %s\n", tname);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int
+locate_pmd_entries(struct elf_info *info)
+{
+	Elf_Sym *last = NULL;
+	struct pmd_driver *new;
+
+	info->drivers = NULL;
+
+	do {
+		new = calloc(sizeof(struct pmd_driver), 1);
+		new->name_sym = find_sym_in_symtab(info, "rte_pmd_name", last);
+		last = new->name_sym;
+		if (!new->name_sym)
+			free(new);
+		else {
+			if (complete_pmd_entry(info, new)) {
+				fprintf(stderr, "Failed to complete pmd entry\n");
+				free(new);
+				return -ENOENT;
+			} else {
+				new->next = info->drivers;
+				info->drivers = new;
+			}
+		}
+	} while (last);
+
+	return 0;
+}
+
+static void
+output_pmd_info_string(struct elf_info *info, char *outfile)
+{
+	FILE *ofd;
+	struct pmd_driver *drv;
+	struct rte_pci_id *pci_ids;
+	int idx = 0;
+
+	ofd = fopen(outfile, "w+");
+	if (!ofd) {
+		fprintf(stderr, "Unable to open output file\n");
+		return;
+	}
+
+	drv = info->drivers;
+
+	while (drv) {
+		fprintf(ofd, "const char %s_pmd_info[] __attribute__((used)) = "
+			"\"PMD_INFO_STRING= {",
+			drv->name);
+		fprintf(ofd, "\\\"name\\\" : \\\"%s\\\", ", drv->name);
+
+		for (idx = 0; idx < PMD_OPT_MAX; idx++) {
+			if (drv->opt_vals[idx])
+				fprintf(ofd, "\\\"%s\\\" : \\\"%s\\\", ",
+					opt_tags[idx].json_id,
+					drv->opt_vals[idx]);
+		}
+
+		pci_ids = drv->pci_tbl;
+		fprintf(ofd, "\\\"pci_ids\\\" : [");
+
+		while (pci_ids && pci_ids->device_id) {
+			fprintf(ofd, "[%d, %d, %d, %d]",
+				pci_ids->vendor_id, pci_ids->device_id,
+				pci_ids->subsystem_vendor_id,
+				pci_ids->subsystem_device_id);
+			pci_ids++;
+			if (pci_ids->device_id)
+				fprintf(ofd, ",");
+			else
+				fprintf(ofd, " ");
+		}
+		fprintf(ofd, "]}\";");
+		drv = drv->next;
+	}
+
+	fclose(ofd);
+}
+
+int main(int argc, char **argv)
+{
+	struct elf_info info;
+	int rc;
+
+	if (argc < 3) {
+		fprintf(stderr,
+			"usage: dpdk-pmdinfogen <object file> <c output file>\n");
+		exit(127);
+	}
+
+	rc = parse_elf(&info, argv[1]);
+	if (rc < 0)
+		exit(-rc);
+
+	rc = locate_pmd_entries(&info);
+	if (rc < 0)
+		goto error;
+
+	if (info.drivers) {
+		output_pmd_info_string(&info, argv[2]);
+		rc = 0;
+	} else {
+		rc = -1;
+		fprintf(stderr, "No drivers registered\n");
+	}
+
+error:
+	parse_elf_finish(&info);
+	exit(-rc);
+}
diff --git a/buildtools/pmdinfogen/pmdinfogen.h b/buildtools/pmdinfogen/pmdinfogen.h
new file mode 100644
index 0000000..7e57702
--- /dev/null
+++ b/buildtools/pmdinfogen/pmdinfogen.h
@@ -0,0 +1,99 @@
+/* Postprocess pmd object files to export hw support
+ *
+ * Copyright 2016 Neil Horman <nhorman at tuxdriver.com>
+ * Based in part on modpost.c from the linux kernel
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License V2, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf.h>
+#include <rte_config.h>
+#include <rte_pci.h>
+#include <rte_byteorder.h>
+
+/* On BSD-alike OSes elf.h defines these according to host's word size */
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef ELF_R_SYM
+#undef ELF_R_TYPE
+
+/*
+ * Define ELF64_* to ELF_*, the latter being defined in both 32 and 64 bit
+ * flavors in elf.h.  This makes our code a bit more generic between arches
+ * and allows us to support 32 bit code in the future should we ever want to
+ */
+#ifdef RTE_ARCH_64
+#define Elf_Ehdr    Elf64_Ehdr
+#define Elf_Shdr    Elf64_Shdr
+#define Elf_Sym     Elf64_Sym
+#define Elf_Addr    Elf64_Addr
+#define Elf_Sword   Elf64_Sxword
+#define Elf_Section Elf64_Half
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_ST_TYPE ELF64_ST_TYPE
+
+#define Elf_Rel     Elf64_Rel
+#define Elf_Rela    Elf64_Rela
+#define ELF_R_SYM   ELF64_R_SYM
+#define ELF_R_TYPE  ELF64_R_TYPE
+#else
+#define Elf_Ehdr    Elf32_Ehdr
+#define Elf_Shdr    Elf32_Shdr
+#define Elf_Sym     Elf32_Sym
+#define Elf_Addr    Elf32_Addr
+#define Elf_Sword   Elf32_Sxword
+#define Elf_Section Elf32_Half
+#define ELF_ST_BIND ELF32_ST_BIND
+#define ELF_ST_TYPE ELF32_ST_TYPE
+
+#define Elf_Rel     Elf32_Rel
+#define Elf_Rela    Elf32_Rela
+#define ELF_R_SYM   ELF32_R_SYM
+#define ELF_R_TYPE  ELF32_R_TYPE
+#endif
+
+
+enum opt_params {
+	PMD_PARAM_STRING = 0,
+	PMD_OPT_MAX
+};
+
+struct pmd_driver {
+	Elf_Sym *name_sym;
+	const char *name;
+	struct rte_pci_id *pci_tbl;
+	struct pmd_driver *next;
+
+	const char *opt_vals[PMD_OPT_MAX];
+};
+
+struct elf_info {
+	unsigned long size;
+	Elf_Ehdr     *hdr;
+	Elf_Shdr     *sechdrs;
+	Elf_Sym      *symtab_start;
+	Elf_Sym      *symtab_stop;
+	char         *strtab;
+
+	/* support for 32bit section numbers */
+
+	unsigned int num_sections; /* max_secindex + 1 */
+	unsigned int secindex_strings;
+	/* if Nth symbol table entry has .st_shndx = SHN_XINDEX,
+	 * take shndx from symtab_shndx_start[N] instead
+	 */
+	Elf32_Word   *symtab_shndx_start;
+	Elf32_Word   *symtab_shndx_stop;
+
+	struct pmd_driver *drivers;
+};
diff --git a/doc/guides/prog_guide/dev_kit_build_system.rst b/doc/guides/prog_guide/dev_kit_build_system.rst
index dedd18a..fa34fe0 100644
--- a/doc/guides/prog_guide/dev_kit_build_system.rst
+++ b/doc/guides/prog_guide/dev_kit_build_system.rst
@@ -70,7 +70,7 @@ Each build directory contains include files, libraries, and applications:
     ...
     ~/DEV/DPDK$ ls i686-native-linuxapp-gcc
 
-    app build hostapp include kmod lib Makefile
+    app build buildtools include kmod lib Makefile
 
 
     ~/DEV/DPDK$ ls i686-native-linuxapp-gcc/app/
@@ -307,6 +307,7 @@ Misc
 Internally Generated Build Tools
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+``dpdk-pmdinfogen`` scans an object (.o) file for various well known symbol names.
 These well known symbol names are defined by various macros and used to export
 important information about hardware support and usage for PMD files.  For
 instance the macro:
@@ -321,6 +322,18 @@ Creates the following symbol:
 
    static char rte_pmd_name0[] __attribute__((used)) = "<name>";
 
+Which dpdk-pmdinfogen scans for.  Using this information other relevant bits of
+data can be exported from the object file and used to produce a hardware support
+description, that dpdk-pmdinfogen then encodes into a json formatted string in
+the following format:
+
+.. code-block:: C
+
+   static char <name_pmd_string>="PMD_INFO_STRING=\"{'name' : '<name>', ...}\"";
+
+These strings can then be searched for by external tools to determine the
+hardware support of a given library or application.
+
 .. _Useful_Variables_Provided_by_the_Build_System:
 
 Useful Variables Provided by the Build System
diff --git a/mk/rte.sdkbuild.mk b/mk/rte.sdkbuild.mk
index f1a163a..5edbf50 100644
--- a/mk/rte.sdkbuild.mk
+++ b/mk/rte.sdkbuild.mk
@@ -63,7 +63,7 @@ build: $(ROOTDIRS-y)
 .PHONY: clean
 clean: $(CLEANDIRS)
 	@rm -rf $(RTE_OUTPUT)/include $(RTE_OUTPUT)/app \
-		$(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod
+		$(RTE_OUTPUT)/lib $(RTE_OUTPUT)/kmod $(RTE_OUTPUT)/buildtools
 	@[ -d $(RTE_OUTPUT)/include ] || mkdir -p $(RTE_OUTPUT)/include
 	@$(RTE_SDK)/scripts/gen-config-h.sh $(RTE_OUTPUT)/.config \
 		> $(RTE_OUTPUT)/include/rte_config.h
diff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk
index abdab0f..2b92157 100644
--- a/mk/rte.sdkinstall.mk
+++ b/mk/rte.sdkinstall.mk
@@ -141,10 +141,13 @@ install-sdk:
 	$(Q)$(call rte_mkdir,                            $(DESTDIR)$(sdkdir))
 	$(Q)cp -a               $(RTE_SDK)/mk            $(DESTDIR)$(sdkdir)
 	$(Q)cp -a               $(RTE_SDK)/scripts       $(DESTDIR)$(sdkdir)
+	$(Q)cp -a               $O/buildtools            $(DESTDIR)$(sdkdir)
 	$(Q)$(call rte_mkdir,                            $(DESTDIR)$(targetdir))
 	$(Q)cp -a               $O/.config               $(DESTDIR)$(targetdir)
 	$(Q)$(call rte_symlink, $(DESTDIR)$(includedir), $(DESTDIR)$(targetdir)/include)
 	$(Q)$(call rte_symlink, $(DESTDIR)$(libdir),     $(DESTDIR)$(targetdir)/lib)
+	$(Q)$(call rte_symlink, $(DESTDIR)$(sdkdir)/buildtools, \
+	                        $(DESTDIR)$(targetdir)/buildtools)
 
 install-doc:
 ifneq ($(wildcard $O/doc),)
-- 
2.7.0



More information about the dev mailing list