]>
git.proxmox.com Git - ceph.git/blob - ceph/src/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.
20 #include <rte_common.h>
21 #include "pmdinfogen.h"
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
;
44 fd
= open(filename
, O_RDONLY
);
51 map
= mmap(NULL
, *size
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
55 if (map
== MAP_FAILED
)
61 * Return a copy of the next line in a mmap'ed file.
62 * spaces in the beginning of the line is trimmed away.
63 * Return a pointer to a static buffer.
65 static void release_file(void *file
, unsigned long size
)
71 static void *get_sym_value(struct elf_info
*info
, const Elf_Sym
*sym
)
73 return RTE_PTR_ADD(info
->hdr
,
74 info
->sechdrs
[sym
->st_shndx
].sh_offset
+ sym
->st_value
);
77 static Elf_Sym
*find_sym_in_symtab(struct elf_info
*info
,
78 const char *name
, Elf_Sym
*last
)
84 idx
= info
->symtab_start
;
86 for (; idx
< info
->symtab_stop
; idx
++) {
87 const char *n
= sym_name(info
, idx
);
88 if (!strncmp(n
, name
, strlen(name
)))
94 static int parse_elf(struct elf_info
*info
, const char *filename
)
101 unsigned int symtab_idx
= ~0U, symtab_shndx_idx
= ~0U;
103 hdr
= grab_file(filename
, &info
->size
);
109 if (info
->size
< sizeof(*hdr
)) {
110 /* file too small, assume this is an empty .o file */
113 /* Is this a valid ELF file? */
114 if ((hdr
->e_ident
[EI_MAG0
] != ELFMAG0
) ||
115 (hdr
->e_ident
[EI_MAG1
] != ELFMAG1
) ||
116 (hdr
->e_ident
[EI_MAG2
] != ELFMAG2
) ||
117 (hdr
->e_ident
[EI_MAG3
] != ELFMAG3
)) {
118 /* Not an ELF file - silently ignore it */
122 if (!hdr
->e_ident
[EI_DATA
]) {
127 endian
= hdr
->e_ident
[EI_DATA
];
129 /* Fix endianness in ELF header */
130 hdr
->e_type
= TO_NATIVE(endian
, 16, hdr
->e_type
);
131 hdr
->e_machine
= TO_NATIVE(endian
, 16, hdr
->e_machine
);
132 hdr
->e_version
= TO_NATIVE(endian
, 32, hdr
->e_version
);
133 hdr
->e_entry
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_entry
);
134 hdr
->e_phoff
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_phoff
);
135 hdr
->e_shoff
= TO_NATIVE(endian
, ADDR_SIZE
, hdr
->e_shoff
);
136 hdr
->e_flags
= TO_NATIVE(endian
, 32, hdr
->e_flags
);
137 hdr
->e_ehsize
= TO_NATIVE(endian
, 16, hdr
->e_ehsize
);
138 hdr
->e_phentsize
= TO_NATIVE(endian
, 16, hdr
->e_phentsize
);
139 hdr
->e_phnum
= TO_NATIVE(endian
, 16, hdr
->e_phnum
);
140 hdr
->e_shentsize
= TO_NATIVE(endian
, 16, hdr
->e_shentsize
);
141 hdr
->e_shnum
= TO_NATIVE(endian
, 16, hdr
->e_shnum
);
142 hdr
->e_shstrndx
= TO_NATIVE(endian
, 16, hdr
->e_shstrndx
);
144 sechdrs
= RTE_PTR_ADD(hdr
, hdr
->e_shoff
);
145 info
->sechdrs
= sechdrs
;
147 /* Check if file offset is correct */
148 if (hdr
->e_shoff
> info
->size
) {
149 fprintf(stderr
, "section header offset=%lu in file '%s' "
150 "is bigger than filesize=%lu\n",
151 (unsigned long)hdr
->e_shoff
,
152 filename
, info
->size
);
156 if (hdr
->e_shnum
== SHN_UNDEF
) {
158 * There are more than 64k sections,
159 * read count from .sh_size.
161 info
->num_sections
= TO_NATIVE(endian
, 32, sechdrs
[0].sh_size
);
163 info
->num_sections
= hdr
->e_shnum
;
165 if (hdr
->e_shstrndx
== SHN_XINDEX
)
166 info
->secindex_strings
=
167 TO_NATIVE(endian
, 32, sechdrs
[0].sh_link
);
169 info
->secindex_strings
= hdr
->e_shstrndx
;
171 /* Fix endianness in section headers */
172 for (i
= 0; i
< info
->num_sections
; i
++) {
174 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_name
);
176 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_type
);
177 sechdrs
[i
].sh_flags
=
178 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_flags
);
180 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_addr
);
181 sechdrs
[i
].sh_offset
=
182 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_offset
);
184 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_size
);
186 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_link
);
188 TO_NATIVE(endian
, 32, sechdrs
[i
].sh_info
);
189 sechdrs
[i
].sh_addralign
=
190 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_addralign
);
191 sechdrs
[i
].sh_entsize
=
192 TO_NATIVE(endian
, ADDR_SIZE
, sechdrs
[i
].sh_entsize
);
194 /* Find symbol table. */
195 for (i
= 1; i
< info
->num_sections
; i
++) {
196 int nobits
= sechdrs
[i
].sh_type
== SHT_NOBITS
;
198 if (!nobits
&& sechdrs
[i
].sh_offset
> info
->size
) {
199 fprintf(stderr
, "%s is truncated. "
200 "sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n",
201 filename
, (unsigned long)sechdrs
[i
].sh_offset
,
206 if (sechdrs
[i
].sh_type
== SHT_SYMTAB
) {
207 unsigned int sh_link_idx
;
209 info
->symtab_start
= RTE_PTR_ADD(hdr
,
210 sechdrs
[i
].sh_offset
);
211 info
->symtab_stop
= RTE_PTR_ADD(hdr
,
212 sechdrs
[i
].sh_offset
+ sechdrs
[i
].sh_size
);
213 sh_link_idx
= sechdrs
[i
].sh_link
;
214 info
->strtab
= RTE_PTR_ADD(hdr
,
215 sechdrs
[sh_link_idx
].sh_offset
);
218 /* 32bit section no. table? ("more than 64k sections") */
219 if (sechdrs
[i
].sh_type
== SHT_SYMTAB_SHNDX
) {
220 symtab_shndx_idx
= i
;
221 info
->symtab_shndx_start
= RTE_PTR_ADD(hdr
,
222 sechdrs
[i
].sh_offset
);
223 info
->symtab_shndx_stop
= RTE_PTR_ADD(hdr
,
224 sechdrs
[i
].sh_offset
+ sechdrs
[i
].sh_size
);
227 if (!info
->symtab_start
)
228 fprintf(stderr
, "%s has no symtab?\n", filename
);
230 /* Fix endianness in symbols */
231 for (sym
= info
->symtab_start
; sym
< info
->symtab_stop
; sym
++) {
232 sym
->st_shndx
= TO_NATIVE(endian
, 16, sym
->st_shndx
);
233 sym
->st_name
= TO_NATIVE(endian
, 32, sym
->st_name
);
234 sym
->st_value
= TO_NATIVE(endian
, ADDR_SIZE
, sym
->st_value
);
235 sym
->st_size
= TO_NATIVE(endian
, ADDR_SIZE
, sym
->st_size
);
238 if (symtab_shndx_idx
!= ~0U) {
240 if (symtab_idx
!= sechdrs
[symtab_shndx_idx
].sh_link
)
242 "%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
243 filename
, sechdrs
[symtab_shndx_idx
].sh_link
,
246 for (p
= info
->symtab_shndx_start
; p
< info
->symtab_shndx_stop
;
248 *p
= TO_NATIVE(endian
, 32, *p
);
254 static void parse_elf_finish(struct elf_info
*info
)
256 struct pmd_driver
*tmp
, *idx
= info
->drivers
;
257 release_file(info
->hdr
, info
->size
);
270 static const struct opt_tag opt_tags
[] = {
271 {"_param_string_export", "params"},
274 static int complete_pmd_entry(struct elf_info
*info
, struct pmd_driver
*drv
)
278 char tmpsymname
[128];
281 drv
->name
= get_sym_value(info
, drv
->name_sym
);
283 for (i
= 0; i
< PMD_OPT_MAX
; i
++) {
284 memset(tmpsymname
, 0, 128);
285 sprintf(tmpsymname
, "__%s%s", drv
->name
, opt_tags
[i
].suffix
);
286 tmpsym
= find_sym_in_symtab(info
, tmpsymname
, NULL
);
289 drv
->opt_vals
[i
] = get_sym_value(info
, tmpsym
);
292 memset(tmpsymname
, 0, 128);
293 sprintf(tmpsymname
, "__%s_pci_tbl_export", drv
->name
);
295 tmpsym
= find_sym_in_symtab(info
, tmpsymname
, NULL
);
299 * If this returns NULL, then this is a PMD_VDEV, because
300 * it has no pci table reference
307 tname
= get_sym_value(info
, tmpsym
);
308 tmpsym
= find_sym_in_symtab(info
, tname
, NULL
);
312 drv
->pci_tbl
= (struct rte_pci_id
*)get_sym_value(info
, tmpsym
);
319 static int locate_pmd_entries(struct elf_info
*info
)
321 Elf_Sym
*last
= NULL
;
322 struct pmd_driver
*new;
324 info
->drivers
= NULL
;
327 new = calloc(sizeof(struct pmd_driver
), 1);
328 new->name_sym
= find_sym_in_symtab(info
, "this_pmd_name", last
);
329 last
= new->name_sym
;
333 if (complete_pmd_entry(info
, new)) {
335 "Failed to complete pmd entry\n");
338 new->next
= info
->drivers
;
347 static void output_pmd_info_string(struct elf_info
*info
, char *outfile
)
350 struct pmd_driver
*drv
;
351 struct rte_pci_id
*pci_ids
;
354 ofd
= fopen(outfile
, "w+");
356 fprintf(stderr
, "Unable to open output file\n");
363 fprintf(ofd
, "const char %s_pmd_info[] __attribute__((used)) = "
364 "\"PMD_INFO_STRING= {",
366 fprintf(ofd
, "\\\"name\\\" : \\\"%s\\\", ", drv
->name
);
368 for (idx
= 0; idx
< PMD_OPT_MAX
; idx
++) {
369 if (drv
->opt_vals
[idx
])
370 fprintf(ofd
, "\\\"%s\\\" : \\\"%s\\\", ",
371 opt_tags
[idx
].json_id
,
375 pci_ids
= drv
->pci_tbl
;
376 fprintf(ofd
, "\\\"pci_ids\\\" : [");
378 while (pci_ids
&& pci_ids
->device_id
) {
379 fprintf(ofd
, "[%d, %d, %d, %d]",
380 pci_ids
->vendor_id
, pci_ids
->device_id
,
381 pci_ids
->subsystem_vendor_id
,
382 pci_ids
->subsystem_device_id
);
384 if (pci_ids
->device_id
)
389 fprintf(ofd
, "]}\";\n");
396 int main(int argc
, char **argv
)
398 struct elf_info info
;
403 "usage: %s <object file> <c output file>\n",
407 parse_elf(&info
, argv
[1]);
409 locate_pmd_entries(&info
);
412 output_pmd_info_string(&info
, argv
[2]);
415 fprintf(stderr
, "No drivers registered\n");
418 parse_elf_finish(&info
);