2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright (c) 2016 Neil Horman <nhorman@tuxdriver.com>
4 # Copyright (c) 2020 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
14 from elftools.elf.elffile import ELFFile
15 from elftools.elf.sections import SymbolTableSection
23 def __init__(self, image, symbol):
28 def string_value(self):
29 size = self._symbol["st_size"]
30 value = self.get_value(0, size)
31 return coff.decode_asciiz(value) # not COFF-specific
33 def get_value(self, offset, size):
34 section = self._symbol["st_shndx"]
35 data = self._image.get_section(section).data()
36 base = self._symbol["st_value"] + offset
37 return data[base : base + size]
41 def __init__(self, data):
42 version = tuple(int(c) for c in elftools.__version__.split("."))
43 self._legacy_elftools = version < (0, 24)
45 self._image = ELFFile(data)
47 section = b".symtab" if self._legacy_elftools else ".symtab"
48 self._symtab = self._image.get_section_by_name(section)
49 if not isinstance(self._symtab, SymbolTableSection):
50 raise Exception(".symtab section is not a symbol table")
53 def is_big_endian(self):
54 return not self._image.little_endian
56 def find_by_name(self, name):
57 symbol = self._get_symbol_by_name(name)
58 return ELFSymbol(self._image, symbol[0]) if symbol else None
60 def _get_symbol_by_name(self, name):
61 if not self._legacy_elftools:
62 return self._symtab.get_symbol_by_name(name)
63 name = name.encode("utf-8")
64 for symbol in self._symtab.iter_symbols():
65 if symbol.name == name:
69 def find_by_prefix(self, prefix):
70 prefix = prefix.encode("utf-8") if self._legacy_elftools else prefix
71 for i in range(self._symtab.num_symbols()):
72 symbol = self._symtab.get_symbol(i)
73 if symbol.name.startswith(prefix):
74 yield ELFSymbol(self._image, symbol)
78 def __init__(self, image, symbol):
82 def get_value(self, offset, size):
83 value = self._symbol.get_value(offset)
84 return value[:size] if value else value
87 def string_value(self):
88 value = self._symbol.get_value(0)
89 return coff.decode_asciiz(value) if value else ''
93 def __init__(self, data):
94 self._image = coff.Image(data)
97 def is_big_endian(self):
100 def find_by_prefix(self, prefix):
101 for symbol in self._image.symbols:
102 if symbol.name.startswith(prefix):
103 yield COFFSymbol(self._image, symbol)
105 def find_by_name(self, name):
106 for symbol in self._image.symbols:
107 if symbol.name == name:
108 return COFFSymbol(self._image, symbol)
112 def define_rte_pci_id(is_big_endian):
113 base_type = ctypes.LittleEndianStructure
115 base_type = ctypes.BigEndianStructure
117 class rte_pci_id(base_type):
120 ("class_id", ctypes.c_uint32),
121 ("vendor_id", ctypes.c_uint16),
122 ("device_id", ctypes.c_uint16),
123 ("subsystem_vendor_id", ctypes.c_uint16),
124 ("subsystem_device_id", ctypes.c_uint16),
132 ("params", "_param_string_export"),
133 ("kmod", "_kmod_dep_export"),
136 def __init__(self, name, options):
138 for key, value in options.items():
139 setattr(self, key, value)
143 def load(cls, image, symbol):
144 name = symbol.string_value
147 for key, suffix in cls.OPTIONS:
148 option_symbol = image.find_by_name("__%s%s" % (name, suffix))
150 value = option_symbol.string_value
153 driver = cls(name, options)
155 pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name)
156 if pci_table_name_symbol:
157 driver.pci_ids = cls._load_pci_ids(image, pci_table_name_symbol)
162 def _load_pci_ids(image, table_name_symbol):
163 table_name = table_name_symbol.string_value
164 table_symbol = image.find_by_name(table_name)
166 raise Exception("PCI table declared but not defined: %d" % table_name)
168 rte_pci_id = define_rte_pci_id(image.is_big_endian)
172 size = ctypes.sizeof(rte_pci_id)
173 offset = size * len(result)
174 data = table_symbol.get_value(offset, size)
177 pci_id = rte_pci_id.from_buffer_copy(data)
178 if not pci_id.device_id:
184 pci_id.subsystem_vendor_id,
185 pci_id.subsystem_device_id,
190 def dump(self, file):
191 dumped = json.dumps(self.__dict__)
192 escaped = dumped.replace('"', '\\"')
194 'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";'
195 % (self.name, escaped),
200 def load_drivers(image):
202 for symbol in image.find_by_prefix("this_pmd_name"):
203 drivers.append(Driver.load(image, symbol))
207 def dump_drivers(drivers, file):
208 # Keep legacy order of definitions.
209 for driver in reversed(drivers):
214 parser = argparse.ArgumentParser()
215 parser.add_argument("format", help="object file format, 'elf' or 'coff'")
217 "input", nargs='+', help="input object file path or '-' for stdin"
219 parser.add_argument("output", help="output C file path or '-' for stdout")
220 return parser.parse_args()
223 def open_input(path):
225 temp = tempfile.TemporaryFile()
226 temp.write(sys.stdin.buffer.read())
228 return open(path, "rb")
231 def read_input(path):
233 return sys.stdin.buffer.read()
234 with open(path, "rb") as file:
238 def load_image(fmt, path):
240 return ELFImage(open_input(path))
242 return COFFImage(read_input(path))
243 raise Exception("unsupported object file format")
246 def open_output(path):
249 return open(path, "w")
252 def write_header(output):
254 "static __attribute__((unused)) const char *generator = \"%s\";\n" % sys.argv[0]
260 if args.input.count('-') > 1:
261 raise Exception("'-' input cannot be used multiple times")
262 if args.format == "elf" and "ELFFile" not in globals():
263 raise Exception("elftools module not found")
265 output = open_output(args.output)
267 for path in args.input:
268 image = load_image(args.format, path)
269 drivers = load_drivers(image)
270 dump_drivers(drivers, output)
273 if __name__ == "__main__":