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>
13 from elftools.elf.elffile import ELFFile
14 from elftools.elf.sections import SymbolTableSection
22 def __init__(self, image, symbol):
27 def string_value(self):
28 size = self._symbol["st_size"]
29 value = self.get_value(0, size)
30 return value[:-1].decode() if value else ""
32 def get_value(self, offset, size):
33 section = self._symbol["st_shndx"]
34 data = self._image.get_section(section).data()
35 base = self._symbol["st_value"] + offset
36 return data[base : base + size]
40 def __init__(self, data):
41 self._image = ELFFile(data)
42 self._symtab = self._image.get_section_by_name(".symtab")
43 if not isinstance(self._symtab, SymbolTableSection):
44 raise Exception(".symtab section is not a symbol table")
47 def is_big_endian(self):
48 return not self._image.little_endian
50 def find_by_name(self, name):
51 symbol = self._symtab.get_symbol_by_name(name)
52 return ELFSymbol(self._image, symbol[0]) if symbol else None
54 def find_by_prefix(self, prefix):
55 for i in range(self._symtab.num_symbols()):
56 symbol = self._symtab.get_symbol(i)
57 if symbol.name.startswith(prefix):
58 yield ELFSymbol(self._image, symbol)
62 def __init__(self, image, symbol):
66 def get_value(self, offset, size):
67 value = self._symbol.get_value(offset)
68 return value[:size] if value else value
71 def string_value(self):
72 value = self._symbol.get_value(0)
73 return coff.decode_asciiz(value) if value else ''
77 def __init__(self, data):
78 self._image = coff.Image(data)
81 def is_big_endian(self):
84 def find_by_prefix(self, prefix):
85 for symbol in self._image.symbols:
86 if symbol.name.startswith(prefix):
87 yield COFFSymbol(self._image, symbol)
89 def find_by_name(self, name):
90 for symbol in self._image.symbols:
91 if symbol.name == name:
92 return COFFSymbol(self._image, symbol)
96 def define_rte_pci_id(is_big_endian):
97 base_type = ctypes.LittleEndianStructure
99 base_type = ctypes.BigEndianStructure
101 class rte_pci_id(base_type):
104 ("class_id", ctypes.c_uint32),
105 ("vendor_id", ctypes.c_uint16),
106 ("device_id", ctypes.c_uint16),
107 ("subsystem_vendor_id", ctypes.c_uint16),
108 ("subsystem_device_id", ctypes.c_uint16),
116 ("params", "_param_string_export"),
117 ("kmod", "_kmod_dep_export"),
120 def __init__(self, name, options):
122 for key, value in options.items():
123 setattr(self, key, value)
127 def load(cls, image, symbol):
128 name = symbol.string_value
131 for key, suffix in cls.OPTIONS:
132 option_symbol = image.find_by_name("__%s%s" % (name, suffix))
134 value = option_symbol.string_value
137 driver = cls(name, options)
139 pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name)
140 if pci_table_name_symbol:
141 driver.pci_ids = cls._load_pci_ids(image, pci_table_name_symbol)
146 def _load_pci_ids(image, table_name_symbol):
147 table_name = table_name_symbol.string_value
148 table_symbol = image.find_by_name(table_name)
150 raise Exception("PCI table declared but not defined: %d" % table_name)
152 rte_pci_id = define_rte_pci_id(image.is_big_endian)
156 size = ctypes.sizeof(rte_pci_id)
157 offset = size * len(result)
158 data = table_symbol.get_value(offset, size)
161 pci_id = rte_pci_id.from_buffer_copy(data)
162 if not pci_id.device_id:
168 pci_id.subsystem_vendor_id,
169 pci_id.subsystem_device_id,
174 def dump(self, file):
175 dumped = json.dumps(self.__dict__)
176 escaped = dumped.replace('"', '\\"')
178 'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";'
179 % (self.name, escaped),
184 def load_drivers(image):
186 for symbol in image.find_by_prefix("this_pmd_name"):
187 drivers.append(Driver.load(image, symbol))
191 def dump_drivers(drivers, file):
192 # Keep legacy order of definitions.
193 for driver in reversed(drivers):
198 parser = argparse.ArgumentParser()
199 parser.add_argument("format", help="object file format, 'elf' or 'coff'")
201 "input", nargs='+', help="input object file path or '-' for stdin"
203 parser.add_argument("output", help="output C file path or '-' for stdout")
204 return parser.parse_args()
207 def open_input(path):
209 temp = tempfile.TemporaryFile()
210 temp.write(sys.stdin.buffer.read())
212 return open(path, "rb")
215 def read_input(path):
217 return sys.stdin.buffer.read()
218 with open(path, "rb") as file:
222 def load_image(fmt, path):
224 return ELFImage(open_input(path))
226 return COFFImage(read_input(path))
227 raise Exception("unsupported object file format")
230 def open_output(path):
233 return open(path, "w")
236 def write_header(output):
238 "static __attribute__((unused)) const char *generator = \"%s\";\n" % sys.argv[0]
244 if args.input.count('-') > 1:
245 raise Exception("'-' input cannot be used multiple times")
246 if args.format == "elf" and "ELFFile" not in globals():
247 raise Exception("elftools module not found")
249 output = open_output(args.output)
251 for path in args.input:
252 image = load_image(args.format, path)
253 drivers = load_drivers(image)
254 dump_drivers(drivers, output)
257 if __name__ == "__main__":