get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/86142/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 86142,
    "url": "https://patches.dpdk.org/api/patches/86142/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210108024723.26210-2-dmitry.kozliuk@gmail.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210108024723.26210-2-dmitry.kozliuk@gmail.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210108024723.26210-2-dmitry.kozliuk@gmail.com",
    "date": "2021-01-08T02:47:20",
    "name": "[v2,1/4] pmdinfogen: support COFF",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "5d931e1664f4cfa7e44f52c879df1668d183f351",
    "submitter": {
        "id": 1581,
        "url": "https://patches.dpdk.org/api/people/1581/?format=api",
        "name": "Dmitry Kozlyuk",
        "email": "dmitry.kozliuk@gmail.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210108024723.26210-2-dmitry.kozliuk@gmail.com/mbox/",
    "series": [
        {
            "id": 14587,
            "url": "https://patches.dpdk.org/api/series/14587/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=14587",
            "date": "2021-01-08T02:47:19",
            "name": "pmdinfogen: support Windows",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/14587/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/86142/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/86142/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (xvm-189-124.dc0.ghst.net [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 258EBA0524;\n\tFri,  8 Jan 2021 03:47:43 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id DCC58140DD0;\n\tFri,  8 Jan 2021 03:47:36 +0100 (CET)",
            "from mail-lf1-f51.google.com (mail-lf1-f51.google.com\n [209.85.167.51])\n by mails.dpdk.org (Postfix) with ESMTP id B8310140DB4\n for <dev@dpdk.org>; Fri,  8 Jan 2021 03:47:35 +0100 (CET)",
            "by mail-lf1-f51.google.com with SMTP id 23so19487784lfg.10\n for <dev@dpdk.org>; Thu, 07 Jan 2021 18:47:35 -0800 (PST)",
            "from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru.\n [37.110.65.23])\n by smtp.gmail.com with ESMTPSA id i19sm1733599ljj.26.2021.01.07.18.47.34\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 07 Jan 2021 18:47:34 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n h=from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding;\n bh=th0aCz+hOrNzE/+zodKztsegy9THJ+QqOEZKcblfXmc=;\n b=FywfHagyuyqpLr4GLJAWHz3BWRihjYRtKuJ99k392IbDPiCHRHPwV+r+KoCJHPxAKE\n HvL6PjNfM49Nw6mvB6w94Nw29DnA/6brop3rT4lW+VXybFSWiqtGSjO9Wp8sbwi2mmSH\n fRnmexMXHv15cIIiko2SNjDXZ8b0xBC8i54ObmM5j4Fjqu4tA/lsO+Y8btKO+bHBECXP\n m6xb2724wk0Odvz9xN1x9a3npPIFfLs0nJM3P4hOll0Exy1yAZ7DHapCWWNYpx976a/0\n lMfpMzN3vIAyr7JROGJZiKkyW6PVAlLEvs89aAKkeFOrbDDtsS6dkgMDoS3TpjmZUIqV\n MrlQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20161025;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=th0aCz+hOrNzE/+zodKztsegy9THJ+QqOEZKcblfXmc=;\n b=DfJD6YsdW3k/5w28UlNO9TTYyKyhHI4J/1gMfaqj40eJyBKD5Z01IbeXxMbJijj5cQ\n dg7uOAJ7iu96jasUpkFe5GDVJpDb+YtsV/pa5HE8SPO0GCWAM3Nejvvc3zrQ9LrdP8wz\n 93ZPrg4GaxWz5j2nGCAWB2h4Vuq0Wz43ZJuV2bGAe08mCj5HPEJpMHK8eyPLa+FQb6qi\n cDUyww46X47oHWLeagZBoVqc5oEUwR6Iem3F/Ubc4sgIP1yD3ypRSYhXBC4agVN0DTXO\n bxPjfUUkHhVN6stG/FrP2MZuTTkqegld7nK7ZowgU66hpWHR9xVtFk4G72MmJOmSteTM\n JD3w==",
        "X-Gm-Message-State": "AOAM532XqXDInoeBUQV2yw56vM9hbVZeglPKVSix9z8L1OpfhF+3Yvmv\n WXQIQuoKG/jhJ9TV62+rq4dSvO3wzF+Xs/xi",
        "X-Google-Smtp-Source": "\n ABdhPJx4JbYHWaXlOdE3JQHBnM5qcfMulkcxvs7U1tu6YkdZrT4Pt+W+jhARlii6ZSmWIkhTLt7PLA==",
        "X-Received": "by 2002:a2e:b4d3:: with SMTP id r19mr543720ljm.419.1610074054961;\n Thu, 07 Jan 2021 18:47:34 -0800 (PST)",
        "From": "Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>",
        "To": "dev@dpdk.org",
        "Cc": "Narcisa Ana Maria Vasile <navasile@linux.microsoft.com>,\n Pallavi Kadam <pallavi.kadam@intel.com>,\n Dmitry Malloy <dmitrym@microsoft.com>,\n Bruce Richardson <bruce.richardson@intel.com>,\n Neil Horman <nhorman@tuxdriver.com>,\n Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>",
        "Date": "Fri,  8 Jan 2021 05:47:20 +0300",
        "Message-Id": "<20210108024723.26210-2-dmitry.kozliuk@gmail.com>",
        "X-Mailer": "git-send-email 2.29.2",
        "In-Reply-To": "<20210108024723.26210-1-dmitry.kozliuk@gmail.com>",
        "References": "<20201212233447.23154-1-dmitry.kozliuk@gmail.com>\n <20210108024723.26210-1-dmitry.kozliuk@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v2 1/4] pmdinfogen: support COFF",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Common Object File Format (COFF) is used on Windows in place of ELF.\n\nAdd COFF parser to pmdinfogen. Also add an argument to specify input\nfile format, which is selected at configure time based on the target.\n\nSigned-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>\n---\nDepends-on: series-13153 (\"pmdinfogen: rewrite in Python\")\n\n buildtools/coff.py       | 154 +++++++++++++++++++++++++++++++++++++++\n buildtools/meson.build   |   7 ++\n buildtools/pmdinfogen.py | 117 +++++++++++++++++++++--------\n 3 files changed, 248 insertions(+), 30 deletions(-)\n create mode 100644 buildtools/coff.py",
    "diff": "diff --git a/buildtools/coff.py b/buildtools/coff.py\nnew file mode 100644\nindex 000000000..86fb0602b\n--- /dev/null\n+++ b/buildtools/coff.py\n@@ -0,0 +1,154 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright (c) 2020 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>\n+\n+import ctypes\n+\n+# x86_64 little-endian\n+COFF_MAGIC = 0x8664\n+\n+# Names up to this length are stored immediately in symbol table entries.\n+COFF_NAMELEN = 8\n+\n+# Special \"section numbers\" changing the meaning of symbol table entry.\n+COFF_SN_UNDEFINED = 0\n+COFF_SN_ABSOLUTE = -1\n+COFF_SN_DEBUG = -2\n+\n+\n+class CoffFileHeader(ctypes.LittleEndianStructure):\n+    _pack_ = True\n+    _fields_ = [\n+        (\"magic\", ctypes.c_uint16),\n+        (\"section_count\", ctypes.c_uint16),\n+        (\"timestamp\", ctypes.c_uint32),\n+        (\"symbol_table_offset\", ctypes.c_uint32),\n+        (\"symbol_count\", ctypes.c_uint32),\n+        (\"optional_header_size\", ctypes.c_uint16),\n+        (\"flags\", ctypes.c_uint16),\n+    ]\n+\n+\n+class CoffName(ctypes.Union):\n+    class Reference(ctypes.LittleEndianStructure):\n+        _pack_ = True\n+        _fields_ = [\n+            (\"zeroes\", ctypes.c_uint32),\n+            (\"offset\", ctypes.c_uint32),\n+        ]\n+\n+    Immediate = ctypes.c_char * 8\n+\n+    _pack_ = True\n+    _fields_ = [\n+        (\"immediate\", Immediate),\n+        (\"reference\", Reference),\n+    ]\n+\n+\n+class CoffSection(ctypes.LittleEndianStructure):\n+    _pack_ = True\n+    _fields_ = [\n+        (\"name\", CoffName),\n+        (\"physical_address\", ctypes.c_uint32),\n+        (\"physical_address\", ctypes.c_uint32),\n+        (\"size\", ctypes.c_uint32),\n+        (\"data_offset\", ctypes.c_uint32),\n+        (\"relocations_offset\", ctypes.c_uint32),\n+        (\"line_numbers_offset\", ctypes.c_uint32),\n+        (\"relocation_count\", ctypes.c_uint16),\n+        (\"line_number_count\", ctypes.c_uint16),\n+        (\"flags\", ctypes.c_uint32),\n+    ]\n+\n+\n+class CoffSymbol(ctypes.LittleEndianStructure):\n+    _pack_ = True\n+    _fields_ = [\n+        (\"name\", CoffName),\n+        (\"value\", ctypes.c_uint32),\n+        (\"section_number\", ctypes.c_int16),\n+        (\"type\", ctypes.c_uint16),\n+        (\"storage_class\", ctypes.c_uint8),\n+        (\"auxiliary_count\", ctypes.c_uint8),\n+    ]\n+\n+\n+class Symbol:\n+    def __init__(self, image, symbol: CoffSymbol):\n+        self._image = image\n+        self._coff = symbol\n+\n+    @property\n+    def name(self):\n+        if self._coff.name.reference.zeroes:\n+            return decode_asciiz(bytes(self._coff.name.immediate))\n+\n+        offset = self._coff.name.reference.offset\n+        offset -= ctypes.sizeof(ctypes.c_uint32)\n+        return self._image.get_string(offset)\n+\n+    def get_value(self, offset):\n+        section_number = self._coff.section_number\n+\n+        if section_number == COFF_SN_UNDEFINED:\n+            return None\n+\n+        if section_number == COFF_SN_DEBUG:\n+            return None\n+\n+        if section_number == COFF_SN_ABSOLUTE:\n+            return bytes(ctypes.c_uint32(self._coff.value))\n+\n+        section_data = self._image.get_section_data(section_number)\n+        section_offset = self._coff.value + offset\n+        return section_data[section_offset:]\n+\n+\n+class Image:\n+    def __init__(self, data):\n+        header = CoffFileHeader.from_buffer_copy(data)\n+        header_size = ctypes.sizeof(header) + header.optional_header_size\n+\n+        sections_desc = CoffSection * header.section_count\n+        sections = sections_desc.from_buffer_copy(data, header_size)\n+\n+        symbols_desc = CoffSymbol * header.symbol_count\n+        symbols = symbols_desc.from_buffer_copy(data, header.symbol_table_offset)\n+\n+        strings_offset = header.symbol_table_offset + ctypes.sizeof(symbols)\n+        strings = Image._parse_strings(data[strings_offset:])\n+\n+        self._data = data\n+        self._header = header\n+        self._sections = sections\n+        self._symbols = symbols\n+        self._strings = strings\n+\n+    @staticmethod\n+    def _parse_strings(data):\n+        full_size = ctypes.c_uint32.from_buffer_copy(data)\n+        header_size = ctypes.sizeof(full_size)\n+        return data[header_size : full_size.value]\n+\n+    @property\n+    def symbols(self):\n+        i = 0\n+        while i < self._header.symbol_count:\n+            symbol = self._symbols[i]\n+            yield Symbol(self, symbol)\n+            i += symbol.auxiliary_count + 1\n+\n+    def get_section_data(self, number):\n+        # section numbers are 1-based\n+        section = self._sections[number - 1]\n+        base = section.data_offset\n+        return self._data[base : base + section.size]\n+\n+    def get_string(self, offset):\n+        return decode_asciiz(self._strings[offset:])\n+\n+\n+def decode_asciiz(data):\n+    index = data.find(b'\\x00')\n+    end = index if index >= 0 else len(data)\n+    return data[:end].decode()\ndiff --git a/buildtools/meson.build b/buildtools/meson.build\nindex dd4c0f640..23cefd4be 100644\n--- a/buildtools/meson.build\n+++ b/buildtools/meson.build\n@@ -17,7 +17,14 @@ else\n endif\n map_to_win_cmd = py3 + files('map_to_win.py')\n sphinx_wrapper = py3 + files('call-sphinx-build.py')\n+\n+# select object file format\n pmdinfogen = py3 + files('pmdinfogen.py')\n+if host_machine.system() == 'windows'\n+\tpmdinfogen += 'coff'\n+else\n+\tpmdinfogen += 'elf'\n+endif\n \n # TODO: starting from Meson 0.51.0 use\n # \tpython3 = import('python').find_installation('python',\ndiff --git a/buildtools/pmdinfogen.py b/buildtools/pmdinfogen.py\nindex 0cca47ff1..474168f21 100755\n--- a/buildtools/pmdinfogen.py\n+++ b/buildtools/pmdinfogen.py\n@@ -9,8 +9,13 @@\n import sys\n import tempfile\n \n-from elftools.elf.elffile import ELFFile\n-from elftools.elf.sections import SymbolTableSection\n+try:\n+    from elftools.elf.elffile import ELFFile\n+    from elftools.elf.sections import SymbolTableSection\n+except ImportError:\n+    pass\n+\n+import coff\n \n \n class ELFSymbol:\n@@ -18,21 +23,18 @@ def __init__(self, image, symbol):\n         self._image = image\n         self._symbol = symbol\n \n-    @property\n-    def size(self):\n-        return self._symbol[\"st_size\"]\n-\n-    @property\n-    def value(self):\n-        data = self._image.get_section_data(self._symbol[\"st_shndx\"])\n-        base = self._symbol[\"st_value\"]\n-        return data[base:base + self.size]\n-\n     @property\n     def string_value(self):\n-        value = self.value\n+        size = self._symbol[\"st_size\"]\n+        value = self.get_value(0, size)\n         return value[:-1].decode() if value else \"\"\n \n+    def get_value(self, offset, size):\n+        section = self._symbol[\"st_shndx\"]\n+        data = self._image.get_section(section).data()\n+        base = self._symbol[\"st_value\"] + offset\n+        return data[base : base + size]\n+\n \n class ELFImage:\n     def __init__(self, data):\n@@ -45,18 +47,50 @@ def __init__(self, data):\n     def is_big_endian(self):\n         return not self._image.little_endian\n \n-    def get_section_data(self, name):\n-        return self._image.get_section(name).data()\n-\n     def find_by_name(self, name):\n         symbol = self._symtab.get_symbol_by_name(name)\n-        return ELFSymbol(self, symbol[0]) if symbol else None\n+        return ELFSymbol(self._image, symbol[0]) if symbol else None\n \n     def find_by_prefix(self, prefix):\n         for i in range(self._symtab.num_symbols()):\n             symbol = self._symtab.get_symbol(i)\n             if symbol.name.startswith(prefix):\n-                yield ELFSymbol(self, symbol)\n+                yield ELFSymbol(self._image, symbol)\n+\n+\n+class COFFSymbol:\n+    def __init__(self, image, symbol):\n+        self._image = image\n+        self._symbol = symbol\n+\n+    def get_value(self, offset, size):\n+        value = self._symbol.get_value(offset)\n+        return value[:size] if value else value\n+\n+    @property\n+    def string_value(self):\n+        value = self._symbol.get_value(0)\n+        return coff.decode_asciiz(value) if value else ''\n+\n+\n+class COFFImage:\n+    def __init__(self, data):\n+        self._image = coff.Image(data)\n+\n+    @property\n+    def is_big_endian(self):\n+        return False\n+\n+    def find_by_prefix(self, prefix):\n+        for symbol in self._image.symbols:\n+            if symbol.name.startswith(prefix):\n+                yield COFFSymbol(self._image, symbol)\n+\n+    def find_by_name(self, name):\n+        for symbol in self._image.symbols:\n+            if symbol.name == name:\n+                return COFFSymbol(self._image, symbol)\n+        return None\n \n \n def define_rte_pci_id(is_big_endian):\n@@ -117,19 +151,24 @@ def _load_pci_ids(image, table_name_symbol):\n \n         rte_pci_id = define_rte_pci_id(image.is_big_endian)\n \n-        pci_id_size = ctypes.sizeof(rte_pci_id)\n-        pci_ids_desc = rte_pci_id * (table_symbol.size // pci_id_size)\n-        pci_ids = pci_ids_desc.from_buffer_copy(table_symbol.value)\n         result = []\n-        for pci_id in pci_ids:\n+        while True:\n+            size = ctypes.sizeof(rte_pci_id)\n+            offset = size * len(result)\n+            data = table_symbol.get_value(offset, size)\n+            if not data:\n+                break\n+            pci_id = rte_pci_id.from_buffer_copy(data)\n             if not pci_id.device_id:\n                 break\n-            result.append([\n-                pci_id.vendor_id,\n-                pci_id.device_id,\n-                pci_id.subsystem_vendor_id,\n-                pci_id.subsystem_device_id,\n-                ])\n+            result.append(\n+                [\n+                    pci_id.vendor_id,\n+                    pci_id.device_id,\n+                    pci_id.subsystem_vendor_id,\n+                    pci_id.subsystem_device_id,\n+                ]\n+            )\n         return result\n \n     def dump(self, file):\n@@ -157,6 +196,7 @@ def dump_drivers(drivers, file):\n \n def parse_args():\n     parser = argparse.ArgumentParser()\n+    parser.add_argument(\"format\", help=\"object file format, 'elf' or 'coff'\")\n     parser.add_argument(\"input\", help=\"input object file path or '-' for stdin\")\n     parser.add_argument(\"output\", help=\"output C file path or '-' for stdout\")\n     return parser.parse_args()\n@@ -170,6 +210,21 @@ def open_input(path):\n     return open(path, \"rb\")\n \n \n+def read_input(path):\n+    if path == \"-\":\n+        return sys.stdin.buffer.read()\n+    with open(path, \"rb\") as file:\n+        return file.read()\n+\n+\n+def load_image(fmt, path):\n+    if fmt == \"elf\":\n+        return ELFImage(open_input(path))\n+    if fmt == \"coff\":\n+        return COFFImage(read_input(path))\n+    raise Exception(\"unsupported object file format\")\n+\n+\n def open_output(path):\n     if path == \"-\":\n         return sys.stdout\n@@ -178,8 +233,10 @@ def open_output(path):\n \n def main():\n     args = parse_args()\n-    infile = open_input(args.input)\n-    image = ELFImage(infile)\n+    if args.format == \"elf\" and \"ELFFile\" not in globals():\n+        raise Exception(\"elftools module not found\")\n+\n+    image = load_image(args.format, args.input)\n     drivers = load_drivers(image)\n     output = open_output(args.output)\n     dump_drivers(drivers, output)\n",
    "prefixes": [
        "v2",
        "1/4"
    ]
}