From patchwork Wed Jul 8 00:53:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Kozlyuk X-Patchwork-Id: 73481 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 73C7AA00BE; Wed, 8 Jul 2020 02:54:20 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id EF24B1DD31; Wed, 8 Jul 2020 02:54:17 +0200 (CEST) Received: from mail-lf1-f49.google.com (mail-lf1-f49.google.com [209.85.167.49]) by dpdk.org (Postfix) with ESMTP id 09BAA1DCFE for ; Wed, 8 Jul 2020 02:54:13 +0200 (CEST) Received: by mail-lf1-f49.google.com with SMTP id o4so25900844lfi.7 for ; Tue, 07 Jul 2020 17:54:12 -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=vv/p3hiG61PjzDvtM8llR7UP/N4ZMnzJB1B1s57Uapg=; b=YTNLhpdcUgfICD1d4IIQ6jlawUWmP743Nn8IH5Wbboq6iPcPIHlbVmT+TG1IUbo/9B C7P/kCu8Z9kTT6YevLwUkhhDT4/UyC3O0ww1gA/OupA9/1WzUa6kxkgflXi1XMEMkHya bhuhQhW1/eDSYLZDr4+98TgYD05C5DzbuPmdtSnNoa6Gow46r3Id53ogApJt5teSUuQD 6/nQnpT4vb54TjUKY+3glxfjgp5TcPQyIE5Tt+fVYbEpJ+NWuUxepSc7guWXuKpPpXSR m1MdcyPYludn5W3FuHIKt6G8VuwP2nSVcanXU+t8QRy+T/9sJKzqSmsKQ93Y8JjAzfWq B+OA== 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=vv/p3hiG61PjzDvtM8llR7UP/N4ZMnzJB1B1s57Uapg=; b=esMRg1MgGp/vDjCOoaQWrfy4KaScWCfw+Qcrg+Mfwx45zKQyDPEwtrIP3rGlughJt8 krMGQPaT2K4FP8rrj7aW/BSQvM4l6f5nPJNpbgPiPDGLF09agsp/MnRgJlcqvgvqEjor 0WY6Veucxd4OCo9KhKgE2Fbjfwzk8PRencUqmxjkD1zAJVloFAnK7eidzsE4DC+FuXJ2 VSpqUx3pSpl/0S3nM7ix163ApXw/Xv/6jsjlZ8wr1X9nb9HWxrEF3c0bmty7x6rDmUbK 9hhrf/mPI1OeY6wdbReRzUiYN118ruml1v37jaEaFIaWiE3fms1Nf5YGrQv10iL6tLF2 Xk1Q== X-Gm-Message-State: AOAM532CeQV8Hu3bJctj6flnsDpYPv3o9OASJCKU3XKmmm6B87Cs3KBI wapoQKOhkIsuQYcuI00ep9an8AGhNGvPVQ== X-Google-Smtp-Source: ABdhPJwRuuGPQxMWYdyZ9Z443WJN+hOLCPVm6JTU1IoeG1qLRsi42gfwAyaxkpjRmVA/WDgk3ldLqQ== X-Received: by 2002:ac2:5a5e:: with SMTP id r30mr34881003lfn.30.1594169652171; Tue, 07 Jul 2020 17:54:12 -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 h22sm515986ljg.1.2020.07.07.17.54.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Jul 2020 17:54:11 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: Neil Horman , Bruce Richardson , Thomas Monjalon , robin.jarry@6wind.com, Jie Zhou , Tal Shnaiderman , Dmitry Kozlyuk Date: Wed, 8 Jul 2020 03:53:52 +0300 Message-Id: <20200708005355.7102-2-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200708005355.7102-1-dmitry.kozliuk@gmail.com> References: <20200702000232.10761-1-dmitry.kozliuk@gmail.com> <20200708005355.7102-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v3 1/4] pmdinfogen: add Python implementation 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" Using a high-level, interpreted language simplifies maintenance and build process. Furthermore, ELF handling is delegated to pyelftools package. Original logic is kept, the copyright recognizes that. Signed-off-by: Dmitry Kozlyuk --- buildtools/pmdinfogen.py | 194 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100755 buildtools/pmdinfogen.py diff --git a/buildtools/pmdinfogen.py b/buildtools/pmdinfogen.py new file mode 100755 index 000000000..c32654a4a --- /dev/null +++ b/buildtools/pmdinfogen.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2016 Neil Horman +# Copyright (c) 2020 Dmitry Kozlyuk + +import argparse +import ctypes +import json +import sys +import tempfile + +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection + + +class ELFSymbol: + def __init__(self, image, symbol): + self._image = image + self._symbol = symbol + + @property + def size(self): + return self._symbol["st_size"] + + @property + def value(self): + data = self._image._image.get_section(self._symbol["st_shndx"]).data() + base = self._symbol["st_value"] + return data[base : base + self.size] + + @property + def string_value(self): + value = self.value + if len(value): + return value[:-1].decode() + return "" + + +class ELFImage: + def __init__(self, data): + self._image = ELFFile(data) + self._symtab = self._image.get_section_by_name(".symtab") + if not isinstance(self._symtab, SymbolTableSection): + raise Exception(".symtab section is not a symbol table") + + @property + def is_big_endian(self): + return not self._image.little_endian + + def find_by_name(self, name): + symbol = self._symtab.get_symbol_by_name(name) + if symbol: + return ELFSymbol(self, symbol[0]) + + def find_by_prefix(self, prefix): + for i in range(self._symtab.num_symbols()): + symbol = self._symtab.get_symbol(i) + if symbol.name.startswith(prefix): + yield ELFSymbol(self, symbol) + + +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 = symbol.string_value + + options = {} + for key, suffix in cls.OPTIONS: + option_symbol = image.find_by_name("__%s%s" % (name, suffix)) + if option_symbol: + value = option_symbol.string_value + options[key] = value + + driver = cls(name, options) + + pci_table_name_symbol = image.find_by_name("__%s_pci_tbl_export" % name) + if pci_table_name_symbol: + driver._load_pci_ids(image, pci_table_name_symbol) + + return driver + + def _load_pci_ids(self, image, table_name_symbol): + table_name = table_name_symbol.string_value + table_symbol = image.find_by_name(table_name) + if not table_symbol: + raise Exception("PCI table declared but not defined: %d" % table_name) + + rte_pci_id = define_rte_pci_id(image.is_big_endian) + + pci_id_size = ctypes.sizeof(rte_pci_id) + if table_symbol.size % pci_id_size != 0: + raise Exception( + "PCI table size (%d) is not a multiple of rte_pci_id size (%d)" + % (table_symbol.size, pci_id_size) + ) + + pci_ids_desc = rte_pci_id * (table_symbol.size // pci_id_size) + pci_ids = pci_ids_desc.from_buffer_copy(table_symbol.value) + for pci_id in pci_ids: + if not pci_id.device_id: + break + self.pci_ids.append( + [ + pci_id.vendor_id, + pci_id.device_id, + pci_id.subsystem_vendor_id, + pci_id.subsystem_device_id, + ] + ) + + def dump(self, file): + dumped = json.dumps(self.__dict__) + escaped = dumped.replace('"', '\\"') + print( + 'const char %s_pmd_info[] __attribute__((used)) = "PMD_INFO_STRING= %s";' + % (self.name, escaped), + file=file, + ) + + +def load_drivers(image): + drivers = [] + for symbol in image.find_by_prefix("this_pmd_name"): + drivers.append(Driver.load(image, symbol)) + return drivers + + +def dump_drivers(drivers, file): + # Keep legacy order of definitions. + for driver in reversed(drivers): + driver.dump(file) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("input", help="input object file path or '-' for stdin") + parser.add_argument("output", help="output C file path or '-' for stdout") + return parser.parse_args() + + +def open_input(path): + if path == "-": + temp = tempfile.TemporaryFile() + temp.write(sys.stdin.buffer.read()) + return temp + return open(path, "rb") + + +def open_output(path): + if path == "-": + return sys.stdout + return open(path, "w") + + +def main(): + args = parse_args() + infile = open_input(args.input) + image = ELFImage(infile) + drivers = load_drivers(image) + output = open_output(args.output) + dump_drivers(drivers, output) + + +if __name__ == "__main__": + main()