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 96c4bf8f4SDmitry Kozlyukimport sys 106c4bf8f4SDmitry Kozlyukimport tempfile 116c4bf8f4SDmitry Kozlyuk 125031436fSDmitry Kozlyuktry: 13*65ef14c5SDmitry Kozlyuk import elftools 146c4bf8f4SDmitry Kozlyuk from elftools.elf.elffile import ELFFile 156c4bf8f4SDmitry Kozlyuk from elftools.elf.sections import SymbolTableSection 165031436fSDmitry Kozlyukexcept ImportError: 175031436fSDmitry Kozlyuk pass 185031436fSDmitry Kozlyuk 195031436fSDmitry Kozlyukimport coff 206c4bf8f4SDmitry Kozlyuk 216c4bf8f4SDmitry Kozlyuk 226c4bf8f4SDmitry Kozlyukclass ELFSymbol: 236c4bf8f4SDmitry Kozlyuk def __init__(self, image, symbol): 246c4bf8f4SDmitry Kozlyuk self._image = image 256c4bf8f4SDmitry Kozlyuk self._symbol = symbol 266c4bf8f4SDmitry Kozlyuk 276c4bf8f4SDmitry Kozlyuk @property 286c4bf8f4SDmitry Kozlyuk def string_value(self): 295031436fSDmitry Kozlyuk size = self._symbol["st_size"] 305031436fSDmitry Kozlyuk value = self.get_value(0, size) 316c4bf8f4SDmitry Kozlyuk return value[:-1].decode() if value else "" 326c4bf8f4SDmitry Kozlyuk 335031436fSDmitry Kozlyuk def get_value(self, offset, size): 345031436fSDmitry Kozlyuk section = self._symbol["st_shndx"] 355031436fSDmitry Kozlyuk data = self._image.get_section(section).data() 365031436fSDmitry Kozlyuk base = self._symbol["st_value"] + offset 375031436fSDmitry Kozlyuk return data[base : base + size] 385031436fSDmitry Kozlyuk 396c4bf8f4SDmitry Kozlyuk 406c4bf8f4SDmitry Kozlyukclass ELFImage: 416c4bf8f4SDmitry Kozlyuk def __init__(self, data): 42*65ef14c5SDmitry Kozlyuk version = tuple(int(c) for c in elftools.__version__.split(".")) 43*65ef14c5SDmitry Kozlyuk self._legacy_elftools = version < (0, 24) 44*65ef14c5SDmitry Kozlyuk 456c4bf8f4SDmitry Kozlyuk self._image = ELFFile(data) 46*65ef14c5SDmitry Kozlyuk 47*65ef14c5SDmitry Kozlyuk section = b".symtab" if self._legacy_elftools else ".symtab" 48*65ef14c5SDmitry Kozlyuk self._symtab = self._image.get_section_by_name(section) 496c4bf8f4SDmitry Kozlyuk if not isinstance(self._symtab, SymbolTableSection): 506c4bf8f4SDmitry Kozlyuk raise Exception(".symtab section is not a symbol table") 516c4bf8f4SDmitry Kozlyuk 526c4bf8f4SDmitry Kozlyuk @property 536c4bf8f4SDmitry Kozlyuk def is_big_endian(self): 546c4bf8f4SDmitry Kozlyuk return not self._image.little_endian 556c4bf8f4SDmitry Kozlyuk 566c4bf8f4SDmitry Kozlyuk def find_by_name(self, name): 57*65ef14c5SDmitry Kozlyuk symbol = self._get_symbol_by_name(name) 585031436fSDmitry Kozlyuk return ELFSymbol(self._image, symbol[0]) if symbol else None 596c4bf8f4SDmitry Kozlyuk 60*65ef14c5SDmitry Kozlyuk def _get_symbol_by_name(self, name): 61*65ef14c5SDmitry Kozlyuk if not self._legacy_elftools: 62*65ef14c5SDmitry Kozlyuk return self._symtab.get_symbol_by_name(name) 63*65ef14c5SDmitry Kozlyuk name = name.encode("utf-8") 64*65ef14c5SDmitry Kozlyuk for symbol in self._symtab.iter_symbols(): 65*65ef14c5SDmitry Kozlyuk if symbol.name == name: 66*65ef14c5SDmitry Kozlyuk return [symbol] 67*65ef14c5SDmitry Kozlyuk return None 68*65ef14c5SDmitry Kozlyuk 696c4bf8f4SDmitry Kozlyuk def find_by_prefix(self, prefix): 70*65ef14c5SDmitry Kozlyuk prefix = prefix.encode("utf-8") if self._legacy_elftools else prefix 716c4bf8f4SDmitry Kozlyuk for i in range(self._symtab.num_symbols()): 726c4bf8f4SDmitry Kozlyuk symbol = self._symtab.get_symbol(i) 736c4bf8f4SDmitry Kozlyuk if symbol.name.startswith(prefix): 745031436fSDmitry Kozlyuk yield ELFSymbol(self._image, symbol) 755031436fSDmitry Kozlyuk 765031436fSDmitry Kozlyuk 775031436fSDmitry Kozlyukclass COFFSymbol: 785031436fSDmitry Kozlyuk def __init__(self, image, symbol): 795031436fSDmitry Kozlyuk self._image = image 805031436fSDmitry Kozlyuk self._symbol = symbol 815031436fSDmitry Kozlyuk 825031436fSDmitry Kozlyuk def get_value(self, offset, size): 835031436fSDmitry Kozlyuk value = self._symbol.get_value(offset) 845031436fSDmitry Kozlyuk return value[:size] if value else value 855031436fSDmitry Kozlyuk 865031436fSDmitry Kozlyuk @property 875031436fSDmitry Kozlyuk def string_value(self): 885031436fSDmitry Kozlyuk value = self._symbol.get_value(0) 895031436fSDmitry Kozlyuk return coff.decode_asciiz(value) if value else '' 905031436fSDmitry Kozlyuk 915031436fSDmitry Kozlyuk 925031436fSDmitry Kozlyukclass COFFImage: 935031436fSDmitry Kozlyuk def __init__(self, data): 945031436fSDmitry Kozlyuk self._image = coff.Image(data) 955031436fSDmitry Kozlyuk 965031436fSDmitry Kozlyuk @property 975031436fSDmitry Kozlyuk def is_big_endian(self): 985031436fSDmitry Kozlyuk return False 995031436fSDmitry Kozlyuk 1005031436fSDmitry Kozlyuk def find_by_prefix(self, prefix): 1015031436fSDmitry Kozlyuk for symbol in self._image.symbols: 1025031436fSDmitry Kozlyuk if symbol.name.startswith(prefix): 1035031436fSDmitry Kozlyuk yield COFFSymbol(self._image, symbol) 1045031436fSDmitry Kozlyuk 1055031436fSDmitry Kozlyuk def find_by_name(self, name): 1065031436fSDmitry Kozlyuk for symbol in self._image.symbols: 1075031436fSDmitry Kozlyuk if symbol.name == name: 1085031436fSDmitry Kozlyuk return COFFSymbol(self._image, symbol) 1095031436fSDmitry Kozlyuk return None 1106c4bf8f4SDmitry Kozlyuk 1116c4bf8f4SDmitry Kozlyuk 1126c4bf8f4SDmitry Kozlyukdef define_rte_pci_id(is_big_endian): 1136c4bf8f4SDmitry Kozlyuk base_type = ctypes.LittleEndianStructure 1146c4bf8f4SDmitry Kozlyuk if is_big_endian: 1156c4bf8f4SDmitry Kozlyuk base_type = ctypes.BigEndianStructure 1166c4bf8f4SDmitry Kozlyuk 1176c4bf8f4SDmitry Kozlyuk class rte_pci_id(base_type): 1186c4bf8f4SDmitry Kozlyuk _pack_ = True 1196c4bf8f4SDmitry Kozlyuk _fields_ = [ 1206c4bf8f4SDmitry Kozlyuk ("class_id", ctypes.c_uint32), 1216c4bf8f4SDmitry Kozlyuk ("vendor_id", ctypes.c_uint16), 1226c4bf8f4SDmitry Kozlyuk ("device_id", ctypes.c_uint16), 1236c4bf8f4SDmitry Kozlyuk ("subsystem_vendor_id", ctypes.c_uint16), 1246c4bf8f4SDmitry Kozlyuk ("subsystem_device_id", ctypes.c_uint16), 1256c4bf8f4SDmitry Kozlyuk ] 1266c4bf8f4SDmitry Kozlyuk 1276c4bf8f4SDmitry Kozlyuk return rte_pci_id 1286c4bf8f4SDmitry Kozlyuk 1296c4bf8f4SDmitry Kozlyuk 1306c4bf8f4SDmitry Kozlyukclass Driver: 1316c4bf8f4SDmitry Kozlyuk OPTIONS = [ 1326c4bf8f4SDmitry Kozlyuk ("params", "_param_string_export"), 1336c4bf8f4SDmitry Kozlyuk ("kmod", "_kmod_dep_export"), 1346c4bf8f4SDmitry Kozlyuk ] 1356c4bf8f4SDmitry Kozlyuk 1366c4bf8f4SDmitry Kozlyuk def __init__(self, name, options): 1376c4bf8f4SDmitry Kozlyuk self.name = name 1386c4bf8f4SDmitry Kozlyuk for key, value in options.items(): 1396c4bf8f4SDmitry Kozlyuk setattr(self, key, value) 1406c4bf8f4SDmitry Kozlyuk self.pci_ids = [] 1416c4bf8f4SDmitry Kozlyuk 1426c4bf8f4SDmitry Kozlyuk @classmethod 1436c4bf8f4SDmitry Kozlyuk def load(cls, image, symbol): 1446c4bf8f4SDmitry Kozlyuk name = symbol.string_value 1456c4bf8f4SDmitry Kozlyuk 1466c4bf8f4SDmitry Kozlyuk options = {} 1476c4bf8f4SDmitry Kozlyuk for key, suffix in cls.OPTIONS: 1486c4bf8f4SDmitry Kozlyuk option_symbol = image.find_by_name("__%s%s" % (name, suffix)) 1496c4bf8f4SDmitry Kozlyuk if option_symbol: 1506c4bf8f4SDmitry Kozlyuk value = option_symbol.string_value 1516c4bf8f4SDmitry Kozlyuk options[key] = value 1526c4bf8f4SDmitry Kozlyuk 1536c4bf8f4SDmitry Kozlyuk driver = cls(name, options) 1546c4bf8f4SDmitry Kozlyuk 1556c4bf8f4SDmitry Kozlyuk pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name) 1566c4bf8f4SDmitry Kozlyuk if pci_table_name_symbol: 1576c4bf8f4SDmitry Kozlyuk driver.pci_ids = cls._load_pci_ids(image, pci_table_name_symbol) 1586c4bf8f4SDmitry Kozlyuk 1596c4bf8f4SDmitry Kozlyuk return driver 1606c4bf8f4SDmitry Kozlyuk 1616c4bf8f4SDmitry Kozlyuk @staticmethod 1626c4bf8f4SDmitry Kozlyuk def _load_pci_ids(image, table_name_symbol): 1636c4bf8f4SDmitry Kozlyuk table_name = table_name_symbol.string_value 1646c4bf8f4SDmitry Kozlyuk table_symbol = image.find_by_name(table_name) 1656c4bf8f4SDmitry Kozlyuk if not table_symbol: 1666c4bf8f4SDmitry Kozlyuk raise Exception("PCI table declared but not defined: %d" % table_name) 1676c4bf8f4SDmitry Kozlyuk 1686c4bf8f4SDmitry Kozlyuk rte_pci_id = define_rte_pci_id(image.is_big_endian) 1696c4bf8f4SDmitry Kozlyuk 1706c4bf8f4SDmitry Kozlyuk result = [] 1715031436fSDmitry Kozlyuk while True: 1725031436fSDmitry Kozlyuk size = ctypes.sizeof(rte_pci_id) 1735031436fSDmitry Kozlyuk offset = size * len(result) 1745031436fSDmitry Kozlyuk data = table_symbol.get_value(offset, size) 1755031436fSDmitry Kozlyuk if not data: 1765031436fSDmitry Kozlyuk break 1775031436fSDmitry Kozlyuk pci_id = rte_pci_id.from_buffer_copy(data) 1786c4bf8f4SDmitry Kozlyuk if not pci_id.device_id: 1796c4bf8f4SDmitry Kozlyuk break 1805031436fSDmitry Kozlyuk result.append( 1815031436fSDmitry Kozlyuk [ 1826c4bf8f4SDmitry Kozlyuk pci_id.vendor_id, 1836c4bf8f4SDmitry Kozlyuk pci_id.device_id, 1846c4bf8f4SDmitry Kozlyuk pci_id.subsystem_vendor_id, 1856c4bf8f4SDmitry Kozlyuk pci_id.subsystem_device_id, 1865031436fSDmitry Kozlyuk ] 1875031436fSDmitry Kozlyuk ) 1886c4bf8f4SDmitry Kozlyuk return result 1896c4bf8f4SDmitry Kozlyuk 1906c4bf8f4SDmitry Kozlyuk def dump(self, file): 1916c4bf8f4SDmitry Kozlyuk dumped = json.dumps(self.__dict__) 1926c4bf8f4SDmitry Kozlyuk escaped = dumped.replace('"', '\\"') 1936c4bf8f4SDmitry Kozlyuk print( 1946c4bf8f4SDmitry Kozlyuk 'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";' 1956c4bf8f4SDmitry Kozlyuk % (self.name, escaped), 1966c4bf8f4SDmitry Kozlyuk file=file, 1976c4bf8f4SDmitry Kozlyuk ) 1986c4bf8f4SDmitry Kozlyuk 1996c4bf8f4SDmitry Kozlyuk 2006c4bf8f4SDmitry Kozlyukdef load_drivers(image): 2016c4bf8f4SDmitry Kozlyuk drivers = [] 2026c4bf8f4SDmitry Kozlyuk for symbol in image.find_by_prefix("this_pmd_name"): 2036c4bf8f4SDmitry Kozlyuk drivers.append(Driver.load(image, symbol)) 2046c4bf8f4SDmitry Kozlyuk return drivers 2056c4bf8f4SDmitry Kozlyuk 2066c4bf8f4SDmitry Kozlyuk 2076c4bf8f4SDmitry Kozlyukdef dump_drivers(drivers, file): 2086c4bf8f4SDmitry Kozlyuk # Keep legacy order of definitions. 2096c4bf8f4SDmitry Kozlyuk for driver in reversed(drivers): 2106c4bf8f4SDmitry Kozlyuk driver.dump(file) 2116c4bf8f4SDmitry Kozlyuk 2126c4bf8f4SDmitry Kozlyuk 2136c4bf8f4SDmitry Kozlyukdef parse_args(): 2146c4bf8f4SDmitry Kozlyuk parser = argparse.ArgumentParser() 2155031436fSDmitry Kozlyuk parser.add_argument("format", help="object file format, 'elf' or 'coff'") 2160fe5c4e5SDmitry Kozlyuk parser.add_argument( 2170fe5c4e5SDmitry Kozlyuk "input", nargs='+', help="input object file path or '-' for stdin" 2180fe5c4e5SDmitry Kozlyuk ) 2196c4bf8f4SDmitry Kozlyuk parser.add_argument("output", help="output C file path or '-' for stdout") 2206c4bf8f4SDmitry Kozlyuk return parser.parse_args() 2216c4bf8f4SDmitry Kozlyuk 2226c4bf8f4SDmitry Kozlyuk 2236c4bf8f4SDmitry Kozlyukdef open_input(path): 2246c4bf8f4SDmitry Kozlyuk if path == "-": 2256c4bf8f4SDmitry Kozlyuk temp = tempfile.TemporaryFile() 2266c4bf8f4SDmitry Kozlyuk temp.write(sys.stdin.buffer.read()) 2276c4bf8f4SDmitry Kozlyuk return temp 2286c4bf8f4SDmitry Kozlyuk return open(path, "rb") 2296c4bf8f4SDmitry Kozlyuk 2306c4bf8f4SDmitry Kozlyuk 2315031436fSDmitry Kozlyukdef read_input(path): 2325031436fSDmitry Kozlyuk if path == "-": 2335031436fSDmitry Kozlyuk return sys.stdin.buffer.read() 2345031436fSDmitry Kozlyuk with open(path, "rb") as file: 2355031436fSDmitry Kozlyuk return file.read() 2365031436fSDmitry Kozlyuk 2375031436fSDmitry Kozlyuk 2385031436fSDmitry Kozlyukdef load_image(fmt, path): 2395031436fSDmitry Kozlyuk if fmt == "elf": 2405031436fSDmitry Kozlyuk return ELFImage(open_input(path)) 2415031436fSDmitry Kozlyuk if fmt == "coff": 2425031436fSDmitry Kozlyuk return COFFImage(read_input(path)) 2435031436fSDmitry Kozlyuk raise Exception("unsupported object file format") 2445031436fSDmitry Kozlyuk 2455031436fSDmitry Kozlyuk 2466c4bf8f4SDmitry Kozlyukdef open_output(path): 2476c4bf8f4SDmitry Kozlyuk if path == "-": 2486c4bf8f4SDmitry Kozlyuk return sys.stdout 2496c4bf8f4SDmitry Kozlyuk return open(path, "w") 2506c4bf8f4SDmitry Kozlyuk 2516c4bf8f4SDmitry Kozlyuk 252e6e9730cSDmitry Kozlyukdef write_header(output): 253e6e9730cSDmitry Kozlyuk output.write( 254e6e9730cSDmitry Kozlyuk "static __attribute__((unused)) const char *generator = \"%s\";\n" % sys.argv[0] 255e6e9730cSDmitry Kozlyuk ) 256e6e9730cSDmitry Kozlyuk 257e6e9730cSDmitry Kozlyuk 2586c4bf8f4SDmitry Kozlyukdef main(): 2596c4bf8f4SDmitry Kozlyuk args = parse_args() 2600fe5c4e5SDmitry Kozlyuk if args.input.count('-') > 1: 2610fe5c4e5SDmitry Kozlyuk raise Exception("'-' input cannot be used multiple times") 2625031436fSDmitry Kozlyuk if args.format == "elf" and "ELFFile" not in globals(): 2635031436fSDmitry Kozlyuk raise Exception("elftools module not found") 2645031436fSDmitry Kozlyuk 2656c4bf8f4SDmitry Kozlyuk output = open_output(args.output) 266e6e9730cSDmitry Kozlyuk write_header(output) 2670fe5c4e5SDmitry Kozlyuk for path in args.input: 2680fe5c4e5SDmitry Kozlyuk image = load_image(args.format, path) 2690fe5c4e5SDmitry Kozlyuk drivers = load_drivers(image) 2706c4bf8f4SDmitry Kozlyuk dump_drivers(drivers, output) 2716c4bf8f4SDmitry Kozlyuk 2726c4bf8f4SDmitry Kozlyuk 2736c4bf8f4SDmitry Kozlyukif __name__ == "__main__": 2746c4bf8f4SDmitry Kozlyuk main() 275