From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A1242A0350; Mon, 22 Jun 2020 02:45:32 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 004771C0D5; Mon, 22 Jun 2020 02:45:24 +0200 (CEST) Received: from mail-lf1-f68.google.com (mail-lf1-f68.google.com [209.85.167.68]) by dpdk.org (Postfix) with ESMTP id DE4BE1C0C6 for ; Mon, 22 Jun 2020 02:45:21 +0200 (CEST) Received: by mail-lf1-f68.google.com with SMTP id d7so8581170lfi.12 for ; Sun, 21 Jun 2020 17:45:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=MW4P6D7SYuHlkfSy11QyjlwaRcZXvS6JHqp9XnibcUg=; b=WVRCC18lVJLLTIso8Zdlrsu+fVFWPEbkU9ys0+X4YH6wFVbOaidZ7MrX5mCJTzRkle wgQPH50eEs8swR6b/HzxxuFY73bViaHXNgYzxzfc9nIwpRuwuBMBNOa+wCapDSTgIgOI Boo3hgP1j4CYGi+k+qwjdvWkwjseDzplYtTN7e0Zk3HVDr/hQyJuTjfF0gQg5detwljL 4u1Orl/6eRK2GFbtCkqGQ1SnF0JJp+Fkk6yC6669kyfUZQEZRE0tbwQqNaE8IG1MzZS6 B5HdpQ3yhYRKdGm9s0VXjDvctHYqeWkPzv3Ft/KOAIAmFbU909fb6gfpKTuseRbNmEIx Eh/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=MW4P6D7SYuHlkfSy11QyjlwaRcZXvS6JHqp9XnibcUg=; b=sV5McHlNfYP6ps9Xo8SUjVvYLjL4n0ZeVDhEsoQJMbwYeALh42EMMUQEP4jkK5I5fv l5AbG0dX5vLBkJVHyj7c7mAfLN5DFgICRkKHzTzIBEZempuG3qvgaqolHvmgh+vvWzkz K2YY2WBuvkAFCxm8vWRhr4aMDs4WpnG6jICaygkX86LT1TDNuGW9d3t+5neDKLSBDLOc dqdNbSIk0uc2WKvLqgmbkdbFetIXaS/trrNRD3GzDMHpB3ygrbY/gDGvty9vBnR0H4UU GacBgBQLCdxClzqMBlCSzPLhsLAtt6vw/WkH/32TH2MfnKxpAZLZeLKCTCX9fUyRs912 /H7w== X-Gm-Message-State: AOAM533jpLWOItRF1boACMS3Nti7HIpvo6muY5Gq3g5kY+GHFiCeBKiz XNR6Cq5bV0rak01HRGuMCUtfZyEiUHo= X-Google-Smtp-Source: ABdhPJy3I95feA7CPHNr6hT8F0wL9iNGMR2IaveNrINI29FDghJ82HpvU+uwUb98q5gCofE7gNH3aQ== X-Received: by 2002:ac2:48b8:: with SMTP id u24mr2929413lfg.145.1592786721293; Sun, 21 Jun 2020 17:45:21 -0700 (PDT) Received: from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru. [37.110.65.23]) by smtp.gmail.com with ESMTPSA id q11sm3067009lfe.34.2020.06.21.17.45.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 21 Jun 2020 17:45:20 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: Neil Horman , Bruce Richardson , Thomas Monjalon , robin.jarry@6wind.com, Dmitry Kozlyuk Date: Mon, 22 Jun 2020 03:45:02 +0300 Message-Id: <20200622004503.29036-2-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200622004503.29036-1-dmitry.kozliuk@gmail.com> References: <20200622004503.29036-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [RFC PATCH 1/2] pmdinfogen: prototype in Python X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" * No user-friendly error handling and no bounds checking yet. * No support for >65K sections case (is it needed?). * The order of definitions is reversed. Signed-off-by: Dmitry Kozlyuk --- buildtools/elf.py | 194 +++++++++++++++++++++++++++++++++++++++ buildtools/pmdinfogen.py | 144 +++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 buildtools/elf.py create mode 100755 buildtools/pmdinfogen.py diff --git a/buildtools/elf.py b/buildtools/elf.py new file mode 100644 index 000000000..4085d547b --- /dev/null +++ b/buildtools/elf.py @@ -0,0 +1,194 @@ +import ctypes + + +class ElfIdent(ctypes.Structure): + _pack_ = True + _fields_ = [ + ("magic", ctypes.c_char * 4), + ("class_", ctypes.c_uint8), + ("data", ctypes.c_uint8), + ("version", ctypes.c_uint8), + ("os_abi", ctypes.c_uint8), + ("abi_version", ctypes.c_uint8), + ("pad", ctypes.c_uint8 * 7), + ] + + @property + def is_magic_ok(self): + return self.magic.value == b"\x7fELF" + + @property + def is_32bit(self): + return self.class_ == 1 + + @property + def is_big_endian(self): + return self.data == 2 + + def define_structures(self): + base_type = ctypes.LittleEndianStructure + if self.is_big_endian: + base = ctypes.BigEndianStructure + + size_type = ctypes.c_uint64 + if self.is_32bit: + size_type = ctypes.c_uint32 + + class FileHeader(base_type): + _pack_ = True + _fields_ = [ + ("e_ident", ElfIdent), + ("e_type", ctypes.c_uint16), + ("e_machine", ctypes.c_uint16), + ("e_version", ctypes.c_uint32), + ("e_entry", size_type), + ("e_phoff", size_type), + ("e_shoff", size_type), + ("e_flags", ctypes.c_uint32), + ("e_ehsize", ctypes.c_uint16), + ("e_phentsize", ctypes.c_uint16), + ("e_phnum", ctypes.c_uint16), + ("e_shentsize", ctypes.c_uint16), + ("e_shnum", ctypes.c_uint16), + ("e_shstrndx", ctypes.c_uint16), + ] + + class SectionHeader(base_type): + _pack_ = True + _fields_ = [ + ("sh_name", ctypes.c_uint32), + ("sh_type", ctypes.c_uint32), + ("sh_flags", size_type), + ("sh_addr", size_type), + ("sh_offset", size_type), + ("sh_size", size_type), + ("sh_link", ctypes.c_uint32), + ("sh_info", ctypes.c_uint32), + ("sh_addralign", size_type), + ("sh_entsize", size_type), + ] + + class Symbol32(base_type): + _pack_ = True + _fields_ = [ + ("st_name", ctypes.c_uint32), + ("st_value", ctypes.c_uint32), + ("st_size", ctypes.c_uint32), + ("st_info", ctypes.c_uint8), + ("st_other", ctypes.c_uint8), + ("st_shndx", ctypes.c_uint16), + ] + + class Symbol64(base_type): + _pack_ = True + _fields_ = [ + ("st_name", ctypes.c_uint32), + ("st_info", ctypes.c_uint8), + ("st_other", ctypes.c_uint8), + ("st_shndx", ctypes.c_uint16), + ("st_value", ctypes.c_uint64), + ("st_size", ctypes.c_uint64), + ] + + Symbol = Symbol32 if self.is_32bit else Symbol64 + + return FileHeader, SectionHeader, Symbol + + +class Symbol: + def __init__(self, image, elf): + self._image = image + self._elf = elf + + + @property + def address(self): + base = self._image._sections[self._elf.st_shndx].sh_offset + offset = base + self._elf.st_value + memory = ctypes.c_char.from_buffer(self._image._data, offset) + return ctypes.addressof(memory) + + +class Image: + def __init__(self, data): + SHN_UNDEF = 0x0000 + SHN_XINDEX = 0xFFFF + + ident = ElfIdent.from_buffer(data) + ElfFileHeader, ElfSectionHeader, ElfSymbol = ident.define_structures() + + header = ElfFileHeader.from_buffer(data) + + if header.e_shnum == SHN_UNDEF: + section = ElfSectionHeader.from_buffer(data, header.e_shoff) + sections_num = section.sh_size + else: + sections_num = header.e_shnum + sections_desc = ElfSectionHeader * sections_num + sections = sections_desc.from_buffer(data, header.e_shoff) + + if header.e_shstrndx == SHN_XINDEX: + strings_index = sections[0].sh_link + else: + strings_index = header.e_shstrndx + + symtab, strtab = Image._find_symbol_table(data, sections, ElfSymbol) + + self._data = data + self._header = header + self._sections = sections + self._strings = sections[strings_index] + self._symtab = symtab + self._strtab = strtab + + + @staticmethod + def _find_symbol_table(data, sections, symbol_type): + SHT_SYMTAB = 2 + SHT_SYMTAB_SHNDX = 18 + + for section in sections: + if section.sh_type == SHT_SYMTAB: + symbol_count = section.sh_size // ctypes.sizeof(symbol_type) + symtab_desc = symbol_type * symbol_count + symtab_offset = section.sh_offset + symtab = symtab_desc.from_buffer(data, symtab_offset) + + strtab = sections[section.sh_link].sh_offset + + return symtab, strtab + + # TODO: SHT_SYMTAB_SHNDX? + + raise Exception('no symbol table') + + + @property + def is_big_endian(self): + return self._header.e_ident.is_big_endian + + + def find_symbol(self, name: str, start: Symbol = None): + name_size = len(name) + name_desc = ctypes.c_char * name_size + + i = 0 + if start: + table_address = ctypes.addressof(self._symtab) + start_address = ctypes.addressof(start._elf) + i = (start_address - table_address) // ctypes.sizeof(start._elf) + 1 + + while i < len(self._symtab): + symbol = self._symtab[i] + + name_offset = self._strtab + symbol.st_name + if name_offset + name_size > len(self._data): + break + + symbol_name = name_desc.from_buffer(self._data, name_offset).value + if symbol_name == name.encode(): + return Symbol(self, symbol) + + i += 1 + + return None diff --git a/buildtools/pmdinfogen.py b/buildtools/pmdinfogen.py new file mode 100755 index 000000000..74d2e5285 --- /dev/null +++ b/buildtools/pmdinfogen.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 + +import argparse +import ctypes +import elf +import json +import mmap +import os +import sys +import tempfile + + +def define_rte_pci_id(is_big_endian): + base_type = ctypes.LittleEndianStructure + if is_big_endian: + base_type = ctypes.BigEndianStructure + + class rte_pci_id(base_type): + _pack_ = True + _fields_ = [ + ("class_id", ctypes.c_uint32), + ("vendor_id", ctypes.c_uint16), + ("device_id", ctypes.c_uint16), + ("subsystem_vendor_id", ctypes.c_uint16), + ("subsystem_device_id", ctypes.c_uint16), + ] + + return rte_pci_id + + +class Driver: + OPTIONS = [ + ("params", "_param_string_export"), + ("kmod", "_kmod_dep_export"), + ] + + def __init__(self, name, options): + self.name = name + for key, value in options.items(): + setattr(self, key, value) + self.pci_ids = [] + + @classmethod + def load(cls, image, symbol): + name = ctypes.string_at(symbol.address).decode() + + options = {} + for key, suffix in cls.OPTIONS: + option_symbol = image.find_symbol(f"__{name}{suffix}") + if option_symbol: + value = ctypes.string_at(option_symbol.address).decode() + options[key] = value + + driver = cls(name, options) + + pci_table_name_symbol = image.find_symbol(f"__{name}_pci_tbl_export") + if not pci_table_name_symbol: + return driver + + pci_table_name = ctypes.string_at(pci_table_name_symbol.address).decode() + + pci_table_symbol = image.find_symbol(pci_table_name) + if not pci_table_symbol: + raise Exception('PCI table declared but not defined') + + rte_pci_id = define_rte_pci_id(image.is_big_endian) + + pci_id = rte_pci_id.from_address(pci_table_symbol.address) + while pci_id.device_id: + driver.pci_ids.append( + [ + pci_id.vendor_id, + pci_id.device_id, + pci_id.subsystem_vendor_id, + pci_id.subsystem_device_id, + ] + ) + pci_id = rte_pci_id.from_address( + ctypes.addressof(pci_id) + ctypes.sizeof(pci_id) + ) + + return driver + + def dump(self, file): + dumped = json.dumps(self.__dict__) + escaped = dumped.replace('"', '\\"') + print( + f"const char {self.name}_pmd_info[] __attribute__((used)) = " + f'"PMD_INFO_STRING= {escaped}";', + file=file, + ) + + +def get_symbols_by_prefix(image, name): + symbol = image.find_symbol(name) + while symbol: + yield symbol + symbol = image.find_symbol(name, symbol) + + +def load_drivers(image): + drivers = [] + for symbol in get_symbols_by_prefix(image, "this_pmd_name"): + drivers.append(Driver.load(image, symbol)) + return drivers + + +def dump_drivers(drivers, file): + for driver in drivers: + driver.dump(file) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("input", help="input object file path") + parser.add_argument("output", help="output C file path") + return parser.parse_args() + + +def map_input(path): + if path == '-': + fd, name = tempfile.mkstemp() + else: + fd = os.open(path, os.O_RDONLY) + return mmap.mmap(fd, 0, access=mmap.ACCESS_COPY) + + +def open_output(path): + if path == '-': + return sys.stdout + return open(path, 'w') + + +def main(): + args = parse_args() + memory = map_input(args.input) + image = elf.Image(memory) + drivers = load_drivers(image) + output = open_output(args.output) + dump_drivers(drivers, output) + + +if __name__ == "__main__": + main() -- 2.25.4