]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/buildtools/pmdinfogen/pmdinfogen.c
1 /* Postprocess pmd object files to export hw support
3 * Copyright 2016 Neil Horman <nhorman@tuxdriver.com>
4 * Based in part on modpost.c from the linux kernel
6 * This software may be used and distributed according to the terms
7 * of the GNU General Public License V2, incorporated herein by reference.
19 #include <rte_common.h>
20 #include "pmdinfogen.h"
28 static int use_stdin
, use_stdout
;
30 static const char *sym_name(struct elf_info
*elf
, Elf_Sym
*sym
)
33 return elf
->strtab
+ sym
->st_name
;
38 static void *grab_file(const char *filename
, unsigned long *size
)
41 void *map
= MAP_FAILED
;
45 fd
= open(filename
, O_RDONLY
);
49 /* from stdin, use a temporary file to mmap */
59 fd
= dup(fileno(infile
));
64 n
= read(STDIN_FILENO
, buffer
, sizeof(buffer
));
66 if (write(fd
, buffer
, n
) != n
)
68 n
= read(STDIN_FILENO
, buffer
, sizeof(buffer
));
76 map
= mmap(NULL
, *size
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
80 if (map
== MAP_FAILED
)
86 * Return a copy of the next line in a mmap'ed file.
87 * spaces in the beginning of the line is trimmed away.
88 * Return a pointer to a static buffer.
90 static void release_file(void *file
, unsigned long size
)
96 static void *get_sym_value(struct elf_info
*info
, const Elf_Sym
*sym
)
98 return RTE_PTR_ADD(info
->hdr
,
99 info
->sechdrs
[sym
->st_shndx
].sh_offset
+ sym
->st_value
);
102 static Elf_Sym
*find_sym_in_symtab(struct elf_info
*info
,
103 const char *name
, Elf_Sym
*last
)
109 idx
= info
->symtab_start
;
111 for (; idx
< info
->symtab_stop
; idx
++) {
112 const char *n
= sym_name(info
, idx
);
113 if (!strncmp(n
, name
, strlen(name
)))
119 static int parse_elf(struct elf_info
*info
, const char *filename
)
126 unsigned int symtab_idx
= ~0U, symtab_shndx_idx
= ~0U;
128 hdr
= grab_file(filename
, &info
->size
);
134 if (info
->size
< sizeof(*hdr
)) {
135 /* file too small, assume this is an empty .o file */
138 /* Is this a valid ELF file? */
139 if ((hdr
->e_ident
[EI_MAG0
] != ELFMAG0
) ||
140 (hdr
->e_ident
[EI_MAG1
] != ELFMAG1
) ||
141 (hdr
->e_ident
[EI_MAG2
] != ELFMAG2
) ||
142 (hdr
->e_ident
[EI_MAG3
] != ELFMAG3
)) {
143 /* Not an ELF file - silently ignore it */
147 if (!hdr
->e_ident
[EI_DATA
]) {
152 endian
= hdr
->e_ident
[EI_DATA
];
154 /* Fix endianness in ELF header */
155 hdr
->e_type
= TO_NATIVE(endian
, 16, hdr
->e_type
);
156 hdr
->e_machine
= TO_NATIVE(endian
, 16, hdr
->e_machine
);
157 hdr
->e_version
= TO_NATIVE(endian
, 32, hdr
->e_version
);
158 hdr
->e_entry
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_entry
);
159 hdr
->e_phoff
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_phoff
);
160 hdr
->e_shoff
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_shoff
);
161 hdr
->e_flags
= TO_NATIVE(endian
, 32, hdr
->e_flags
);
162 hdr
->e_ehsize
= TO_NATIVE(endian
, 16, hdr
->e_ehsize
);
163 hdr
->e_phentsize
= TO_NATIVE(endian
, 16, hdr
->e_phentsize
);
164 hdr
->e_phnum
= TO_NATIVE(endian
, 16, hdr
->e_phnum
);
165 hdr
->e_shentsize
= TO_NATIVE(endian
, 16, hdr
->e_shentsize
);
166 hdr
->e_shnum
= TO_NATIVE(endian
, 16, hdr
->e_shnum
);
167 hdr
->e_shstrndx
= TO_NATIVE(endian
, 16, hdr
->e_shstrndx
);
169 sechdrs
= RTE_PTR_ADD(hdr
, hdr
->e_shoff
);
170 info
->sechdrs
= sechdrs
;
172 /* Check if file offset is correct */
173 if (hdr
->e_shoff
> info
->size
) {
174 fprintf(stderr
, "section header offset=%lu in file '%s' "
175 "is bigger than filesize=%lu\n",
176 (unsigned long)hdr
->e_shoff
,
177 filename
, info
->size
);
181 if (hdr
->e_shnum
== SHN_UNDEF
) {
183 * There are more than 64k sections,
184 * read count from .sh_size.
187 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[0].sh_size
);
189 info
->num_sections
= hdr
->e_shnum
;
191 if (hdr
->e_shstrndx
== SHN_XINDEX
)
192 info
->secindex_strings
=
193 TO_NATIVE(endian
, 32, sechdrs
[0].sh_link
);
195 info
->secindex_strings
= hdr
->e_shstrndx
;
197 /* Fix endianness in section headers */
198 for (i
= 0; i
< info
->num_sections
; i
++) {
200 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_name
);
202 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_type
);
203 sechdrs
[i
].sh_flags
=
204 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_flags
);
206 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_addr
);
207 sechdrs
[i
].sh_offset
=
208 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_offset
);
210 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_size
);
212 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_link
);
214 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_info
);
215 sechdrs
[i
].sh_addralign
=
216 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_addralign
);
217 sechdrs
[i
].sh_entsize
=
218 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_entsize
);
220 /* Find symbol table. */
221 for (i
= 1; i
< info
->num_sections
; i
++) {
222 int nobits
= sechdrs
[i
].sh_type
== SHT_NOBITS
;
224 if (!nobits
&& sechdrs
[i
].sh_offset
> info
->size
) {
225 fprintf(stderr
, "%s is truncated. "
226 "sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n",
227 filename
, (unsigned long)sechdrs
[i
].sh_offset
,
232 if (sechdrs
[i
].sh_type
== SHT_SYMTAB
) {
233 unsigned int sh_link_idx
;
235 info
->symtab_start
= RTE_PTR_ADD(hdr
,
236 sechdrs
[i
].sh_offset
);
237 info
->symtab_stop
= RTE_PTR_ADD(hdr
,
238 sechdrs
[i
].sh_offset
+ sechdrs
[i
].sh_size
);
239 sh_link_idx
= sechdrs
[i
].sh_link
;
240 info
->strtab
= RTE_PTR_ADD(hdr
,
241 sechdrs
[sh_link_idx
].sh_offset
);
244 /* 32bit section no. table? ("more than 64k sections") */
245 if (sechdrs
[i
].sh_type
== SHT_SYMTAB_SHNDX
) {
246 symtab_shndx_idx
= i
;
247 info
->symtab_shndx_start
= RTE_PTR_ADD(hdr
,
248 sechdrs
[i
].sh_offset
);
249 info
->symtab_shndx_stop
= RTE_PTR_ADD(hdr
,
250 sechdrs
[i
].sh_offset
+ sechdrs
[i
].sh_size
);
253 if (!info
->symtab_start
)
254 fprintf(stderr
, "%s has no symtab?\n", filename
);
256 /* Fix endianness in symbols */
257 for (sym
= info
->symtab_start
; sym
< info
->symtab_stop
; sym
++) {
258 sym
->st_shndx
= TO_NATIVE(endian
, 16, sym
->st_shndx
);
259 sym
->st_name
= TO_NATIVE(endian
, 32, sym
->st_name
);
260 sym
->st_value
= TO_NATIVE(endian
, ADDR_SIZE
, sym
->st_value
);
261 sym
->st_size
= TO_NATIVE(endian
, ADDR_SIZE
, sym
->st_size
);
265 if (symtab_shndx_idx
!= ~0U) {
267 if (symtab_idx
!= sechdrs
[symtab_shndx_idx
].sh_link
)
269 "%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
270 filename
, sechdrs
[symtab_shndx_idx
].sh_link
,
273 for (p
= info
->symtab_shndx_start
; p
< info
->symtab_shndx_stop
;
275 *p
= TO_NATIVE(endian
, 32, *p
);
281 static void parse_elf_finish(struct elf_info
*info
)
283 struct pmd_driver
*tmp
, *idx
= info
->drivers
;
284 release_file(info
->hdr
, info
->size
);
297 static const struct opt_tag opt_tags
[] = {
298 {"_param_string_export", "params"},
299 {"_kmod_dep_export", "kmod"},
302 static int complete_pmd_entry(struct elf_info
*info
, struct pmd_driver
*drv
)
306 char tmpsymname
[128];
309 drv
->name
= get_sym_value(info
, drv
->name_sym
);
311 for (i
= 0; i
< PMD_OPT_MAX
; i
++) {
312 memset(tmpsymname
, 0, 128);
313 sprintf(tmpsymname
, "__%s%s", drv
->name
, opt_tags
[i
].suffix
);
314 tmpsym
= find_sym_in_symtab(info
, tmpsymname
, NULL
);
317 drv
->opt_vals
[i
] = get_sym_value(info
, tmpsym
);
320 memset(tmpsymname
, 0, 128);
321 sprintf(tmpsymname
, "__%s_pci_tbl_export", drv
->name
);
323 tmpsym
= find_sym_in_symtab(info
, tmpsymname
, NULL
);
327 * If this returns NULL, then this is a PMD_VDEV, because
328 * it has no pci table reference
335 tname
= get_sym_value(info
, tmpsym
);
336 tmpsym
= find_sym_in_symtab(info
, tname
, NULL
);
340 drv
->pci_tbl
= (struct rte_pci_id
*)get_sym_value(info
, tmpsym
);
347 static int locate_pmd_entries(struct elf_info
*info
)
349 Elf_Sym
*last
= NULL
;
350 struct pmd_driver
*new;
352 info
->drivers
= NULL
;
355 new = calloc(sizeof(struct pmd_driver
), 1);
357 fprintf(stderr
, "Failed to calloc memory\n");
360 new->name_sym
= find_sym_in_symtab(info
, "this_pmd_name", last
);
361 last
= new->name_sym
;
365 if (complete_pmd_entry(info
, new)) {
367 "Failed to complete pmd entry\n");
370 new->next
= info
->drivers
;
379 static void output_pmd_info_string(struct elf_info
*info
, char *outfile
)
382 struct pmd_driver
*drv
;
383 struct rte_pci_id
*pci_ids
;
389 ofd
= fopen(outfile
, "w+");
391 fprintf(stderr
, "Unable to open output file\n");
399 fprintf(ofd
, "const char %s_pmd_info[] __attribute__((used)) = "
400 "\"PMD_INFO_STRING= {",
402 fprintf(ofd
, "\\\"name\\\" : \\\"%s\\\", ", drv
->name
);
404 for (idx
= 0; idx
< PMD_OPT_MAX
; idx
++) {
405 if (drv
->opt_vals
[idx
])
406 fprintf(ofd
, "\\\"%s\\\" : \\\"%s\\\", ",
407 opt_tags
[idx
].json_id
,
411 pci_ids
= drv
->pci_tbl
;
412 fprintf(ofd
, "\\\"pci_ids\\\" : [");
414 while (pci_ids
&& pci_ids
->device_id
) {
415 fprintf(ofd
, "[%d, %d, %d, %d]",
416 pci_ids
->vendor_id
, pci_ids
->device_id
,
417 pci_ids
->subsystem_vendor_id
,
418 pci_ids
->subsystem_device_id
);
420 if (pci_ids
->device_id
)
425 fprintf(ofd
, "]}\";\n");
432 int main(int argc
, char **argv
)
434 struct elf_info info
= {0};
439 "usage: %s <object file> <c output file>\n",
443 use_stdin
= !strcmp(argv
[1], "-");
444 use_stdout
= !strcmp(argv
[2], "-");
445 parse_elf(&info
, argv
[1]);
447 if (locate_pmd_entries(&info
) < 0)
451 output_pmd_info_string(&info
, argv
[2]);
454 fprintf(stderr
, "No drivers registered\n");
457 parse_elf_finish(&info
);