16c4bf8f4SDmitry Kozlyuk#!/usr/bin/env python3 26c4bf8f4SDmitry Kozlyuk# SPDX-License-Identifier: BSD-3-Clause 36c4bf8f4SDmitry Kozlyuk# Copyright (c) 2016 Neil Horman <nhorman@tuxdriver.com> 46c4bf8f4SDmitry Kozlyuk# Copyright (c) 2020 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> 56c4bf8f4SDmitry Kozlyuk 66c4bf8f4SDmitry Kozlyukimport argparse 76c4bf8f4SDmitry Kozlyukimport ctypes 86c4bf8f4SDmitry Kozlyukimport json 9*e1d8a879SDavid Marchandimport re 106c4bf8f4SDmitry Kozlyukimport sys 116c4bf8f4SDmitry Kozlyukimport tempfile 126c4bf8f4SDmitry Kozlyuk 135031436fSDmitry Kozlyuktry: 1465ef14c5SDmitry Kozlyuk import elftools 156c4bf8f4SDmitry Kozlyuk from elftools.elf.elffile import ELFFile 166c4bf8f4SDmitry Kozlyuk from elftools.elf.sections import SymbolTableSection 175031436fSDmitry Kozlyukexcept ImportError: 185031436fSDmitry Kozlyuk pass 195031436fSDmitry Kozlyuk 205031436fSDmitry Kozlyukimport coff 216c4bf8f4SDmitry Kozlyuk 226c4bf8f4SDmitry Kozlyuk 236c4bf8f4SDmitry Kozlyukclass ELFSymbol: 246c4bf8f4SDmitry Kozlyuk def __init__(self, image, symbol): 256c4bf8f4SDmitry Kozlyuk self._image = image 266c4bf8f4SDmitry Kozlyuk self._symbol = symbol 276c4bf8f4SDmitry Kozlyuk 286c4bf8f4SDmitry Kozlyuk @property 296c4bf8f4SDmitry Kozlyuk def string_value(self): 305031436fSDmitry Kozlyuk size = self._symbol["st_size"] 315031436fSDmitry Kozlyuk value = self.get_value(0, size) 328050b615SDmitry Kozlyuk return coff.decode_asciiz(value) # not COFF-specific 336c4bf8f4SDmitry Kozlyuk 345031436fSDmitry Kozlyuk def get_value(self, offset, size): 355031436fSDmitry Kozlyuk section = self._symbol["st_shndx"] 365031436fSDmitry Kozlyuk data = self._image.get_section(section).data() 375031436fSDmitry Kozlyuk base = self._symbol["st_value"] + offset 385031436fSDmitry Kozlyuk return data[base : base + size] 395031436fSDmitry Kozlyuk 406c4bf8f4SDmitry Kozlyuk 416c4bf8f4SDmitry Kozlyukclass ELFImage: 426c4bf8f4SDmitry Kozlyuk def __init__(self, data): 4365ef14c5SDmitry Kozlyuk version = tuple(int(c) for c in elftools.__version__.split(".")) 4465ef14c5SDmitry Kozlyuk self._legacy_elftools = version < (0, 24) 4565ef14c5SDmitry Kozlyuk 466c4bf8f4SDmitry Kozlyuk self._image = ELFFile(data) 4765ef14c5SDmitry Kozlyuk 4865ef14c5SDmitry Kozlyuk section = b".symtab" if self._legacy_elftools else ".symtab" 4965ef14c5SDmitry Kozlyuk self._symtab = self._image.get_section_by_name(section) 506c4bf8f4SDmitry Kozlyuk if not isinstance(self._symtab, SymbolTableSection): 516c4bf8f4SDmitry Kozlyuk raise Exception(".symtab section is not a symbol table") 526c4bf8f4SDmitry Kozlyuk 536c4bf8f4SDmitry Kozlyuk @property 546c4bf8f4SDmitry Kozlyuk def is_big_endian(self): 556c4bf8f4SDmitry Kozlyuk return not self._image.little_endian 566c4bf8f4SDmitry Kozlyuk 576c4bf8f4SDmitry Kozlyuk def find_by_name(self, name): 5865ef14c5SDmitry Kozlyuk symbol = self._get_symbol_by_name(name) 595031436fSDmitry Kozlyuk return ELFSymbol(self._image, symbol[0]) if symbol else None 606c4bf8f4SDmitry Kozlyuk 6165ef14c5SDmitry Kozlyuk def _get_symbol_by_name(self, name): 6265ef14c5SDmitry Kozlyuk if not self._legacy_elftools: 6365ef14c5SDmitry Kozlyuk return self._symtab.get_symbol_by_name(name) 6465ef14c5SDmitry Kozlyuk name = name.encode("utf-8") 6565ef14c5SDmitry Kozlyuk for symbol in self._symtab.iter_symbols(): 6665ef14c5SDmitry Kozlyuk if symbol.name == name: 6765ef14c5SDmitry Kozlyuk return [symbol] 6865ef14c5SDmitry Kozlyuk return None 6965ef14c5SDmitry Kozlyuk 70*e1d8a879SDavid Marchand def find_by_pattern(self, pattern): 71*e1d8a879SDavid Marchand pattern = pattern.encode("utf-8") if self._legacy_elftools else pattern 726c4bf8f4SDmitry Kozlyuk for i in range(self._symtab.num_symbols()): 736c4bf8f4SDmitry Kozlyuk symbol = self._symtab.get_symbol(i) 74*e1d8a879SDavid Marchand if re.match(pattern, symbol.name): 755031436fSDmitry Kozlyuk yield ELFSymbol(self._image, symbol) 765031436fSDmitry Kozlyuk 775031436fSDmitry Kozlyuk 785031436fSDmitry Kozlyukclass COFFSymbol: 795031436fSDmitry Kozlyuk def __init__(self, image, symbol): 805031436fSDmitry Kozlyuk self._image = image 815031436fSDmitry Kozlyuk self._symbol = symbol 825031436fSDmitry Kozlyuk 835031436fSDmitry Kozlyuk def get_value(self, offset, size): 845031436fSDmitry Kozlyuk value = self._symbol.get_value(offset) 855031436fSDmitry Kozlyuk return value[:size] if value else value 865031436fSDmitry Kozlyuk 875031436fSDmitry Kozlyuk @property 885031436fSDmitry Kozlyuk def string_value(self): 895031436fSDmitry Kozlyuk value = self._symbol.get_value(0) 905031436fSDmitry Kozlyuk return coff.decode_asciiz(value) if value else '' 915031436fSDmitry Kozlyuk 925031436fSDmitry Kozlyuk 935031436fSDmitry Kozlyukclass COFFImage: 945031436fSDmitry Kozlyuk def __init__(self, data): 955031436fSDmitry Kozlyuk self._image = coff.Image(data) 965031436fSDmitry Kozlyuk 975031436fSDmitry Kozlyuk @property 985031436fSDmitry Kozlyuk def is_big_endian(self): 995031436fSDmitry Kozlyuk return False 1005031436fSDmitry Kozlyuk 101*e1d8a879SDavid Marchand def find_by_pattern(self, pattern): 1025031436fSDmitry Kozlyuk for symbol in self._image.symbols: 103*e1d8a879SDavid Marchand if re.match(pattern, symbol.name): 1045031436fSDmitry Kozlyuk yield COFFSymbol(self._image, symbol) 1055031436fSDmitry Kozlyuk 1065031436fSDmitry Kozlyuk def find_by_name(self, name): 1075031436fSDmitry Kozlyuk for symbol in self._image.symbols: 1085031436fSDmitry Kozlyuk if symbol.name == name: 1095031436fSDmitry Kozlyuk return COFFSymbol(self._image, symbol) 1105031436fSDmitry Kozlyuk return None 1116c4bf8f4SDmitry Kozlyuk 1126c4bf8f4SDmitry Kozlyuk 1136c4bf8f4SDmitry Kozlyukdef define_rte_pci_id(is_big_endian): 1146c4bf8f4SDmitry Kozlyuk base_type = ctypes.LittleEndianStructure 1156c4bf8f4SDmitry Kozlyuk if is_big_endian: 1166c4bf8f4SDmitry Kozlyuk base_type = ctypes.BigEndianStructure 1176c4bf8f4SDmitry Kozlyuk 1186c4bf8f4SDmitry Kozlyuk class rte_pci_id(base_type): 1196c4bf8f4SDmitry Kozlyuk _pack_ = True 1206c4bf8f4SDmitry Kozlyuk _fields_ = [ 1216c4bf8f4SDmitry Kozlyuk ("class_id", ctypes.c_uint32), 1226c4bf8f4SDmitry Kozlyuk ("vendor_id", ctypes.c_uint16), 1236c4bf8f4SDmitry Kozlyuk ("device_id", ctypes.c_uint16), 1246c4bf8f4SDmitry Kozlyuk ("subsystem_vendor_id", ctypes.c_uint16), 1256c4bf8f4SDmitry Kozlyuk ("subsystem_device_id", ctypes.c_uint16), 1266c4bf8f4SDmitry Kozlyuk ] 1276c4bf8f4SDmitry Kozlyuk 1286c4bf8f4SDmitry Kozlyuk return rte_pci_id 1296c4bf8f4SDmitry Kozlyuk 1306c4bf8f4SDmitry Kozlyuk 1316c4bf8f4SDmitry Kozlyukclass Driver: 1326c4bf8f4SDmitry Kozlyuk OPTIONS = [ 1336c4bf8f4SDmitry Kozlyuk ("params", "_param_string_export"), 1346c4bf8f4SDmitry Kozlyuk ("kmod", "_kmod_dep_export"), 1356c4bf8f4SDmitry Kozlyuk ] 1366c4bf8f4SDmitry Kozlyuk 1376c4bf8f4SDmitry Kozlyuk def __init__(self, name, options): 1386c4bf8f4SDmitry Kozlyuk self.name = name 1396c4bf8f4SDmitry Kozlyuk for key, value in options.items(): 1406c4bf8f4SDmitry Kozlyuk setattr(self, key, value) 1416c4bf8f4SDmitry Kozlyuk self.pci_ids = [] 1426c4bf8f4SDmitry Kozlyuk 1436c4bf8f4SDmitry Kozlyuk @classmethod 1446c4bf8f4SDmitry Kozlyuk def load(cls, image, symbol): 1456c4bf8f4SDmitry Kozlyuk name = symbol.string_value 1466c4bf8f4SDmitry Kozlyuk 1476c4bf8f4SDmitry Kozlyuk options = {} 1486c4bf8f4SDmitry Kozlyuk for key, suffix in cls.OPTIONS: 1496c4bf8f4SDmitry Kozlyuk option_symbol = image.find_by_name("__%s%s" % (name, suffix)) 1506c4bf8f4SDmitry Kozlyuk if option_symbol: 1516c4bf8f4SDmitry Kozlyuk value = option_symbol.string_value 1526c4bf8f4SDmitry Kozlyuk options[key] = value 1536c4bf8f4SDmitry Kozlyuk 1546c4bf8f4SDmitry Kozlyuk driver = cls(name, options) 1556c4bf8f4SDmitry Kozlyuk 1566c4bf8f4SDmitry Kozlyuk pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name) 1576c4bf8f4SDmitry Kozlyuk if pci_table_name_symbol: 1586c4bf8f4SDmitry Kozlyuk driver.pci_ids = cls._load_pci_ids(image, pci_table_name_symbol) 1596c4bf8f4SDmitry Kozlyuk 1606c4bf8f4SDmitry Kozlyuk return driver 1616c4bf8f4SDmitry Kozlyuk 1626c4bf8f4SDmitry Kozlyuk @staticmethod 1636c4bf8f4SDmitry Kozlyuk def _load_pci_ids(image, table_name_symbol): 1646c4bf8f4SDmitry Kozlyuk table_name = table_name_symbol.string_value 1656c4bf8f4SDmitry Kozlyuk table_symbol = image.find_by_name(table_name) 1666c4bf8f4SDmitry Kozlyuk if not table_symbol: 1676c4bf8f4SDmitry Kozlyuk raise Exception("PCI table declared but not defined: %d" % table_name) 1686c4bf8f4SDmitry Kozlyuk 1696c4bf8f4SDmitry Kozlyuk rte_pci_id = define_rte_pci_id(image.is_big_endian) 1706c4bf8f4SDmitry Kozlyuk 1716c4bf8f4SDmitry Kozlyuk result = [] 1725031436fSDmitry Kozlyuk while True: 1735031436fSDmitry Kozlyuk size = ctypes.sizeof(rte_pci_id) 1745031436fSDmitry Kozlyuk offset = size * len(result) 1755031436fSDmitry Kozlyuk data = table_symbol.get_value(offset, size) 1765031436fSDmitry Kozlyuk if not data: 1775031436fSDmitry Kozlyuk break 1785031436fSDmitry Kozlyuk pci_id = rte_pci_id.from_buffer_copy(data) 1796c4bf8f4SDmitry Kozlyuk if not pci_id.device_id: 1806c4bf8f4SDmitry Kozlyuk break 1815031436fSDmitry Kozlyuk result.append( 1825031436fSDmitry Kozlyuk [ 1836c4bf8f4SDmitry Kozlyuk pci_id.vendor_id, 1846c4bf8f4SDmitry Kozlyuk pci_id.device_id, 1856c4bf8f4SDmitry Kozlyuk pci_id.subsystem_vendor_id, 1866c4bf8f4SDmitry Kozlyuk pci_id.subsystem_device_id, 1875031436fSDmitry Kozlyuk ] 1885031436fSDmitry Kozlyuk ) 1896c4bf8f4SDmitry Kozlyuk return result 1906c4bf8f4SDmitry Kozlyuk 1916c4bf8f4SDmitry Kozlyuk def dump(self, file): 1926c4bf8f4SDmitry Kozlyuk dumped = json.dumps(self.__dict__) 1936c4bf8f4SDmitry Kozlyuk escaped = dumped.replace('"', '\\"') 1946c4bf8f4SDmitry Kozlyuk print( 1956c4bf8f4SDmitry Kozlyuk 'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";' 1966c4bf8f4SDmitry Kozlyuk % (self.name, escaped), 1976c4bf8f4SDmitry Kozlyuk file=file, 1986c4bf8f4SDmitry Kozlyuk ) 1996c4bf8f4SDmitry Kozlyuk 2006c4bf8f4SDmitry Kozlyuk 2016c4bf8f4SDmitry Kozlyukdef load_drivers(image): 2026c4bf8f4SDmitry Kozlyuk drivers = [] 203*e1d8a879SDavid Marchand for symbol in image.find_by_pattern("^this_pmd_name[0-9]+$"): 2046c4bf8f4SDmitry Kozlyuk drivers.append(Driver.load(image, symbol)) 2056c4bf8f4SDmitry Kozlyuk return drivers 2066c4bf8f4SDmitry Kozlyuk 2076c4bf8f4SDmitry Kozlyuk 2086c4bf8f4SDmitry Kozlyukdef dump_drivers(drivers, file): 2096c4bf8f4SDmitry Kozlyuk # Keep legacy order of definitions. 2106c4bf8f4SDmitry Kozlyuk for driver in reversed(drivers): 2116c4bf8f4SDmitry Kozlyuk driver.dump(file) 2126c4bf8f4SDmitry Kozlyuk 2136c4bf8f4SDmitry Kozlyuk 2146c4bf8f4SDmitry Kozlyukdef parse_args(): 2156c4bf8f4SDmitry Kozlyuk parser = argparse.ArgumentParser() 2165031436fSDmitry Kozlyuk parser.add_argument("format", help="object file format, 'elf' or 'coff'") 2170fe5c4e5SDmitry Kozlyuk parser.add_argument( 2180fe5c4e5SDmitry Kozlyuk "input", nargs='+', help="input object file path or '-' for stdin" 2190fe5c4e5SDmitry Kozlyuk ) 2206c4bf8f4SDmitry Kozlyuk parser.add_argument("output", help="output C file path or '-' for stdout") 2216c4bf8f4SDmitry Kozlyuk return parser.parse_args() 2226c4bf8f4SDmitry Kozlyuk 2236c4bf8f4SDmitry Kozlyuk 2246c4bf8f4SDmitry Kozlyukdef open_input(path): 2256c4bf8f4SDmitry Kozlyuk if path == "-": 2266c4bf8f4SDmitry Kozlyuk temp = tempfile.TemporaryFile() 2276c4bf8f4SDmitry Kozlyuk temp.write(sys.stdin.buffer.read()) 2286c4bf8f4SDmitry Kozlyuk return temp 2296c4bf8f4SDmitry Kozlyuk return open(path, "rb") 2306c4bf8f4SDmitry Kozlyuk 2316c4bf8f4SDmitry Kozlyuk 2325031436fSDmitry Kozlyukdef read_input(path): 2335031436fSDmitry Kozlyuk if path == "-": 2345031436fSDmitry Kozlyuk return sys.stdin.buffer.read() 2355031436fSDmitry Kozlyuk with open(path, "rb") as file: 2365031436fSDmitry Kozlyuk return file.read() 2375031436fSDmitry Kozlyuk 2385031436fSDmitry Kozlyuk 2395031436fSDmitry Kozlyukdef load_image(fmt, path): 2405031436fSDmitry Kozlyuk if fmt == "elf": 2415031436fSDmitry Kozlyuk return ELFImage(open_input(path)) 2425031436fSDmitry Kozlyuk if fmt == "coff": 2435031436fSDmitry Kozlyuk return COFFImage(read_input(path)) 2445031436fSDmitry Kozlyuk raise Exception("unsupported object file format") 2455031436fSDmitry Kozlyuk 2465031436fSDmitry Kozlyuk 2476c4bf8f4SDmitry Kozlyukdef open_output(path): 2486c4bf8f4SDmitry Kozlyuk if path == "-": 2496c4bf8f4SDmitry Kozlyuk return sys.stdout 2506c4bf8f4SDmitry Kozlyuk return open(path, "w") 2516c4bf8f4SDmitry Kozlyuk 2526c4bf8f4SDmitry Kozlyuk 253e6e9730cSDmitry Kozlyukdef write_header(output): 254e6e9730cSDmitry Kozlyuk output.write( 255e6e9730cSDmitry Kozlyuk "static __attribute__((unused)) const char *generator = \"%s\";\n" % sys.argv[0] 256e6e9730cSDmitry Kozlyuk ) 257e6e9730cSDmitry Kozlyuk 258e6e9730cSDmitry Kozlyuk 2596c4bf8f4SDmitry Kozlyukdef main(): 2606c4bf8f4SDmitry Kozlyuk args = parse_args() 2610fe5c4e5SDmitry Kozlyuk if args.input.count('-') > 1: 2620fe5c4e5SDmitry Kozlyuk raise Exception("'-' input cannot be used multiple times") 2635031436fSDmitry Kozlyuk if args.format == "elf" and "ELFFile" not in globals(): 2645031436fSDmitry Kozlyuk raise Exception("elftools module not found") 2655031436fSDmitry Kozlyuk 2666c4bf8f4SDmitry Kozlyuk output = open_output(args.output) 267e6e9730cSDmitry Kozlyuk write_header(output) 2680fe5c4e5SDmitry Kozlyuk for path in args.input: 2690fe5c4e5SDmitry Kozlyuk image = load_image(args.format, path) 2700fe5c4e5SDmitry Kozlyuk drivers = load_drivers(image) 2716c4bf8f4SDmitry Kozlyuk dump_drivers(drivers, output) 2726c4bf8f4SDmitry Kozlyuk 2736c4bf8f4SDmitry Kozlyuk 2746c4bf8f4SDmitry Kozlyukif __name__ == "__main__": 2756c4bf8f4SDmitry Kozlyuk main() 276