get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 12889,
    "url": "https://patches.dpdk.org/api/patches/12889/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1463605687-649-5-git-send-email-nhorman@tuxdriver.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": "<1463605687-649-5-git-send-email-nhorman@tuxdriver.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1463605687-649-5-git-send-email-nhorman@tuxdriver.com",
    "date": "2016-05-18T21:08:07",
    "name": "[dpdk-dev,PATCHv2,4/4] pmdinfo.py: Add tool to query binaries for hw and other support information",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "87fea8be8851bf0c8acdc396faea331f4f61c75a",
    "submitter": {
        "id": 32,
        "url": "https://patches.dpdk.org/api/people/32/?format=api",
        "name": "Neil Horman",
        "email": "nhorman@tuxdriver.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/1463605687-649-5-git-send-email-nhorman@tuxdriver.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/12889/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/12889/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 26E969611;\n\tWed, 18 May 2016 23:09:08 +0200 (CEST)",
            "from smtp.tuxdriver.com (charlotte.tuxdriver.com [70.61.120.58])\n\tby dpdk.org (Postfix) with ESMTP id A47C495D0\n\tfor <dev@dpdk.org>; Wed, 18 May 2016 23:09:06 +0200 (CEST)",
            "from hmsreliant.think-freely.org\n\t([2001:470:8:a08:7aac:c0ff:fec2:933b] helo=localhost)\n\tby smtp.tuxdriver.com with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.63)\n\t(envelope-from <nhorman@tuxdriver.com>)\n\tid 1b38iB-0001Jg-S6; Wed, 18 May 2016 17:09:04 -0400"
        ],
        "From": "Neil Horman <nhorman@tuxdriver.com>",
        "To": "dev@dpdk.org",
        "Cc": "Neil Horman <nhorman@tuxdriver.com>,\n\tBruce Richardson <bruce.richardson@intel.com>,\n\tThomas Monjalon <thomas.monjalon@6wind.com>,\n\tStephen Hemminger <stephen@networkplumber.org>,\n\tPanu Matilainen <pmatilai@redhat.com>",
        "Date": "Wed, 18 May 2016 17:08:07 -0400",
        "Message-Id": "<1463605687-649-5-git-send-email-nhorman@tuxdriver.com>",
        "X-Mailer": "git-send-email 2.5.5",
        "In-Reply-To": "<1463605687-649-1-git-send-email-nhorman@tuxdriver.com>",
        "References": "<1463431287-4551-1-git-send-email-nhorman@tuxdriver.com>\n\t<1463605687-649-1-git-send-email-nhorman@tuxdriver.com>",
        "X-Spam-Score": "-1.0 (-)",
        "X-Spam-Status": "No",
        "Subject": "[dpdk-dev] [PATCHv2 4/4] pmdinfo.py: Add tool to query binaries for\n\thw and other support information",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This tool searches for the primer sting PMD_DRIVER_INFO= in any ELF binary,\nand, if found parses the remainder of the string as a json encoded string,\noutputting the results in either a human readable or raw, script parseable\nformat\n\nNote that, in the case of dynamically linked applications, pmdinfo.py will scan\nfor implicitly linked PMDs by searching the specified binaries .dynamic section\nfor DT_NEEDED entries that contain the substring librte_pmd.  The DT_RUNPATH,\nLD_LIBRARY_PATH, /usr/lib and /lib are searched for these libraries, in that\norder\n\nIf a file is specified with no path, it is assumed to be a PMD DSO, and the\nLD_LIBRARY_PATH, /usr/lib/ and /lib is searched for it\n\nCurrently the tool can output data in 3 formats:\n\na) raw, suitable for scripting, where the raw JSON strings are dumped out\nb) table format (default) where hex pci ids are dumped in a table format\nc) pretty, where a user supplied pci.ids file is used to print out vendor and\ndevice strings\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Bruce Richardson <bruce.richardson@intel.com>\nCC: Thomas Monjalon <thomas.monjalon@6wind.com>\nCC: Stephen Hemminger <stephen@networkplumber.org>\nCC: Panu Matilainen <pmatilai@redhat.com>\n---\n tools/pmdinfo.py | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 457 insertions(+)\n create mode 100755 tools/pmdinfo.py",
    "diff": "diff --git a/tools/pmdinfo.py b/tools/pmdinfo.py\nnew file mode 100755\nindex 0000000..e1cc4ae\n--- /dev/null\n+++ b/tools/pmdinfo.py\n@@ -0,0 +1,457 @@\n+#!/usr/bin/python\n+#-------------------------------------------------------------------------------\n+# scripts/pmd_hw_support.py\n+#\n+# Utility to dump PMD_INFO_STRING support from an object file\n+#\n+#-------------------------------------------------------------------------------\n+import os, sys\n+from optparse import OptionParser\n+import string\n+import json\n+\n+# For running from development directory. It should take precedence over the\n+# installed pyelftools.\n+sys.path.insert(0, '.')\n+\n+\n+from elftools import __version__\n+from elftools.common.exceptions import ELFError\n+from elftools.common.py3compat import (\n+        ifilter, byte2int, bytes2str, itervalues, str2bytes)\n+from elftools.elf.elffile import ELFFile\n+from elftools.elf.dynamic import DynamicSection, DynamicSegment\n+from elftools.elf.enums import ENUM_D_TAG\n+from elftools.elf.segments import InterpSegment\n+from elftools.elf.sections import SymbolTableSection\n+from elftools.elf.gnuversions import (\n+    GNUVerSymSection, GNUVerDefSection,\n+    GNUVerNeedSection,\n+    )\n+from elftools.elf.relocation import RelocationSection\n+from elftools.elf.descriptions import (\n+    describe_ei_class, describe_ei_data, describe_ei_version,\n+    describe_ei_osabi, describe_e_type, describe_e_machine,\n+    describe_e_version_numeric, describe_p_type, describe_p_flags,\n+    describe_sh_type, describe_sh_flags,\n+    describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,\n+    describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,\n+    describe_ver_flags,\n+    )\n+from elftools.elf.constants import E_FLAGS\n+from elftools.dwarf.dwarfinfo import DWARFInfo\n+from elftools.dwarf.descriptions import (\n+    describe_reg_name, describe_attr_value, set_global_machine_arch,\n+    describe_CFI_instructions, describe_CFI_register_rule,\n+    describe_CFI_CFA_rule,\n+    )\n+from elftools.dwarf.constants import (\n+    DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file)\n+from elftools.dwarf.callframe import CIE, FDE\n+\n+raw_output = False\n+pcidb = None\n+\n+#===========================================\n+\n+class Vendor:\n+    \"\"\"\n+    Class for vendors. This is the top level class\n+    for the devices belong to a specific vendor.\n+    self.devices is the device dictionary\n+    subdevices are in each device.\n+    \"\"\"\n+    def __init__(self, vendorStr):\n+        \"\"\"\n+        Class initializes with the raw line from pci.ids\n+        Parsing takes place inside __init__\n+        \"\"\"\n+        self.ID = vendorStr.split()[0]\n+        self.name = vendorStr.replace(\"%s \" % self.ID,\"\").rstrip()\n+        self.devices = {}\n+\n+    def addDevice(self, deviceStr):\n+        \"\"\"\n+        Adds a device to self.devices\n+        takes the raw line from pci.ids\n+        \"\"\"\n+        s = deviceStr.strip()\n+        devID = s.split()[0]\n+        if devID in self.devices:\n+            pass\n+        else:\n+            self.devices[devID] = Device(deviceStr)\n+\n+    def report(self):\n+        print self.ID, self.name\n+        for id, dev in self.devices.items():\n+            dev.report()\n+\n+    def find_device(self, devid):\n+        # convert to a hex string and remove 0x\n+        devid = hex(devid)[2:]\n+        try:\n+            return self.devices[devid]\n+        except:\n+            return Device(\"%s (Unknown Device %s)\" % (devid, devid)) \n+\n+class Device:\n+    def __init__(self, deviceStr):\n+        \"\"\"\n+        Class for each device.\n+        Each vendor has its own devices dictionary.\n+        \"\"\"\n+        s = deviceStr.strip()\n+        self.ID = s.split()[0]\n+        self.name = s.replace(\"%s  \" % self.ID,\"\")\n+        self.subdevices = {}\n+\n+    def report(self):\n+        print \"\\t%s\\t%s\" % (self.ID, self.name)\n+        for subID, subdev in self.subdevices.items():\n+            subdev.report()\n+\n+    def addSubDevice(self, subDeviceStr):\n+        \"\"\"\n+        Adds a subvendor, subdevice to device.\n+        Uses raw line from pci.ids\n+        \"\"\"\n+        s = subDeviceStr.strip()\n+        spl = s.split()\n+        subVendorID  = spl[0]\n+        subDeviceID  = spl[1]\n+        subDeviceName = s.split(\"  \")[-1]\n+        devID = \"%s:%s\" % (subVendorID,subDeviceID)\n+        self.subdevices[devID] = SubDevice(subVendorID,subDeviceID,subDeviceName)\n+\n+    def find_subid(self, subven, subdev):\n+        subven = hex(subven)[2:]\n+        subdev = hex(subdev)[2:]\n+        devid =\"%s:%s\" % (subven, subdev)\n+\n+        try:\n+            return self.subdevices[devid]\n+        except:\n+            if (subven == \"ffff\" and subdev == \"ffff\"):\n+                return SubDevice(\"ffff\", \"ffff\", \"(All Subdevices)\");\n+            else:\n+                return SubDevice(subven, subdev, \"(Unknown Subdevice)\")\n+        \n+\n+class SubDevice:\n+    \"\"\"\n+    Class for subdevices.\n+    \"\"\"\n+    def __init__(self, vendor, device, name):\n+        \"\"\"\n+        Class initializes with vendorid, deviceid and name\n+        \"\"\"\n+        self.vendorID = vendor\n+        self.deviceID = device\n+        self.name = name\n+\n+    def report(self):\n+        print \"\\t\\t%s\\t%s\\t%s\" % (self.vendorID, self.deviceID,self.name)\n+\n+class PCIIds:\n+    \"\"\"\n+    Top class for all pci.ids entries.\n+    All queries will be asked to this class.\n+    PCIIds.vendors[\"0e11\"].devices[\"0046\"].subdevices[\"0e11:4091\"].name  =  \"Smart Array 6i\"\n+    \"\"\"\n+    def __init__(self, filename):\n+        \"\"\"\n+        Prepares the directories.\n+        Checks local data file.\n+        Tries to load from local, if not found, downloads from web\n+        \"\"\"\n+        self.version = \"\"\n+        self.date = \"\"\n+        self.vendors = {}\n+        self.contents = None\n+        self.readLocal(filename)\n+        self.parse()\n+\n+    def reportVendors(self):\n+        \"\"\"Reports the vendors\n+        \"\"\"\n+        for vid, v in self.vendors.items():\n+            print v.ID, v.name\n+\n+    def report(self, vendor = None):\n+        \"\"\"\n+        Reports everything for all vendors or a specific vendor\n+        PCIIds.report()  reports everything\n+        PCIIDs.report(\"0e11\") reports only \"Compaq Computer Corporation\"\n+        \"\"\"\n+        if vendor != None:\n+            self.vendors[vendor].report()\n+        else:\n+            for vID, v in self.vendors.items():\n+                v.report()\n+\n+    def find_vendor(self, vid):\n+        # convert vid to a hex string and remove the 0x\n+        vid = hex(vid)[2:]\n+\n+        try:\n+            return self.vendors[vid]\n+        except: \n+            return Vendor(\"%s (Unknown Vendor %s)\" % (vid, vid))\n+\n+    def findDate(self, content):\n+        for l in content:\n+            if l.find(\"Date:\") > -1:\n+                return l.split()[-2].replace(\"-\", \"\")\n+        return None\n+\n+    def parse(self):\n+        if len(self.contents) < 1:\n+            print \"data/%s-pci.ids not found\" % self.date\n+        else:\n+            vendorID = \"\"\n+            deviceID = \"\"\n+            for l in self.contents:\n+                if l[0] == \"#\":\n+                    continue\n+                elif len(l.strip()) == 0:\n+                    continue\n+                else:\n+                    if l.find(\"\\t\\t\") == 0:\n+                        self.vendors[vendorID].devices[deviceID].addSubDevice(l)\n+                    elif l.find(\"\\t\") == 0:\n+                        deviceID = l.strip().split()[0]\n+                        self.vendors[vendorID].addDevice(l)\n+                    else:\n+                        vendorID = l.split()[0]\n+                        self.vendors[vendorID] = Vendor(l)\n+\n+    def readLocal(self, filename):\n+        \"\"\"\n+        Reads the local file\n+        \"\"\"\n+        self.contents = open(filename).readlines()\n+        self.date = self.findDate(self.contents)\n+\n+    def loadLocal(self):\n+        \"\"\"\n+        Loads database from local. If there is no file,\n+        it creates a new one from web\n+        \"\"\"\n+        self.date = idsfile[0].split(\"/\")[1].split(\"-\")[0]\n+        self.readLocal()\n+\n+\n+\n+#=======================================\n+\n+def search_file(filename, search_path):\n+    \"\"\" Given a search path, find file with requested name \"\"\"\n+    for path in string.split(search_path, \":\"):\n+        candidate = os.path.join(path, filename)\n+        if os.path.exists(candidate): return os.path.abspath(candidate)\n+    return None\n+\n+class ReadElf(object):\n+    \"\"\" display_* methods are used to emit output into the output stream\n+    \"\"\"\n+    def __init__(self, file, output):\n+        \"\"\" file:\n+                stream object with the ELF file to read\n+\n+            output:\n+                output stream to write to\n+        \"\"\"\n+        self.elffile = ELFFile(file)\n+        self.output = output\n+\n+        # Lazily initialized if a debug dump is requested\n+        self._dwarfinfo = None\n+\n+        self._versioninfo = None\n+\n+    def _section_from_spec(self, spec):\n+        \"\"\" Retrieve a section given a \"spec\" (either number or name).\n+            Return None if no such section exists in the file.\n+        \"\"\"\n+        try:\n+            num = int(spec)\n+            if num < self.elffile.num_sections():\n+                return self.elffile.get_section(num)\n+            else:\n+                return None\n+        except ValueError:\n+            # Not a number. Must be a name then\n+            return self.elffile.get_section_by_name(str2bytes(spec))\n+\n+    def pretty_print_pmdinfo(self, pmdinfo):\n+        global pcidb\n+\n+        for i in pmdinfo[\"pci_ids\"]:\n+            vendor = pcidb.find_vendor(i[0])\n+            device = vendor.find_device(i[1])\n+            subdev = device.find_subid(i[2], i[3])\n+            print(\"%s (%s) : %s (%s) %s\" % (vendor.name, vendor.ID, device.name, device.ID, subdev.name))\n+   \n+    def parse_pmd_info_string(self, mystring):\n+        global raw_output\n+        global pcidb\n+\n+        optional_pmd_info = [{'id': 'params', 'tag' : 'PMD PARAMETERS'}]\n+\n+        i = mystring.index(\"=\");\n+        mystring = mystring[i+2:]\n+        pmdinfo = json.loads(mystring)\n+\n+        if raw_output:\n+            print(pmdinfo)\n+            return\n+\n+        print(\"PMD NAME: \" + pmdinfo[\"name\"])\n+        print(\"PMD TYPE: \" + pmdinfo[\"type\"])\n+        for i in optional_pmd_info:\n+            try:\n+                print(\"%s: %s\" % (i['tag'], pmdinfo[i['id']]))\n+            except KeyError as e:\n+                continue\n+\n+        if (pmdinfo[\"type\"] == \"PMD_PDEV\"):\n+            print(\"PMD HW SUPPORT:\")\n+            if pcidb != None:\n+                self.pretty_print_pmdinfo(pmdinfo)\n+            else:\n+                print(\"VENDOR\\t DEVICE\\t SUBVENDOR\\t SUBDEVICE\")\n+                for i in pmdinfo[\"pci_ids\"]:\n+                    print(\"0x%04x\\t 0x%04x\\t 0x%04x\\t\\t 0x%04x\" % (i[0], i[1], i[2], i[3]))\n+\n+        print(\"\")\n+\n+\n+    def display_pmd_info_strings(self, section_spec):\n+        \"\"\" Display a strings dump of a section. section_spec is either a\n+            section number or a name.\n+        \"\"\"\n+        section = self._section_from_spec(section_spec)\n+        if section is None:\n+            return\n+\n+\n+        data = section.data()\n+        dataptr = 0\n+\n+        while dataptr < len(data):\n+            while ( dataptr < len(data) and\n+                    not (32 <= byte2int(data[dataptr]) <= 127)):\n+                dataptr += 1\n+\n+            if dataptr >= len(data):\n+                break\n+\n+            endptr = dataptr\n+            while endptr < len(data) and byte2int(data[endptr]) != 0:\n+                endptr += 1\n+\n+            mystring = bytes2str(data[dataptr:endptr])\n+            rc = mystring.find(\"PMD_INFO_STRING\")\n+            if (rc != -1):\n+                self.parse_pmd_info_string(mystring)\n+\n+            dataptr = endptr\n+\n+    def get_dt_runpath(self, dynsec):\n+        for tag in dynsec.iter_tags():\n+            if tag.entry.d_tag == 'DT_RUNPATH':\n+                return tag.runpath\n+        return \"\"\n+\n+\n+    def process_dt_needed_entries(self):\n+        \"\"\" Look to see if there are any DT_NEEDED entries in the binary\n+            And process those if there are\n+        \"\"\"\n+        global raw_output\n+        runpath = \"\"\n+        ldlibpath = os.environ.get('LD_LIBRARY_PATH')\n+        if (ldlibpath == None):\n+            ldlibpath = \"\"\n+\n+        dynsec = self._section_from_spec(\".dynamic\")\n+        try:\n+            runpath = self.get_dt_runpath(dynsec)\n+        except AttributeError:\n+            # dynsec is None, just return\n+            return\n+\n+        for tag in dynsec.iter_tags():\n+            if tag.entry.d_tag == 'DT_NEEDED':\n+                rc = tag.needed.find(\"librte_pmd\")\n+                if (rc != -1):\n+                    library = search_file(tag.needed,\n+                            runpath + \":\" + ldlibpath +\n+                            \":/usr/lib:/lib\")\n+                    if (library != None):\n+                        if (raw_output == False):\n+                            print(\"Scanning %s for pmd information\" % library)\n+                        with open(library, 'rb') as file:\n+                            libelf = ReadElf(file, sys.stdout)\n+                            libelf.process_dt_needed_entries()\n+                            libelf.display_pmd_info_strings(\".rodata\")\n+                            file.close()\n+\n+\n+def main(stream=None):\n+    global raw_output\n+    global pcidb\n+\n+    optparser = OptionParser(\n+            usage='usage: %prog [-h|-r] <elf-file>',\n+            description=\"Dump pmd hardware support info\",\n+            add_help_option=True,\n+            prog='pmdinfo.py')\n+    optparser.add_option('-r', '--raw',\n+            action='store_true', dest='raw_output',\n+            help='Dump raw json strings')\n+    optparser.add_option(\"-d\", \"--pcidb\", dest=\"pcifile\",\n+            help=\"\", metavar=\"FILE\")\n+\n+    options, args = optparser.parse_args()\n+\n+    if options.raw_output:\n+        raw_output = True\n+\n+    if options.pcifile:\n+        pcidb = PCIIds(options.pcifile)\n+        if pcidb == None:\n+            print(\"Pci DB file not found\")\n+            exit(1)\n+   \n+    ldlibpath = os.environ.get('LD_LIBRARY_PATH')\n+    if (ldlibpath == None):\n+        ldlibpath = \"\"\n+\n+    if (os.path.exists(args[0]) == True):\n+        myelffile = args[0]\n+    else:\n+        myelffile = search_file(args[0], ldlibpath + \":/usr/lib:/lib\")\n+\n+    if (myelffile == None):\n+        print(\"File not found\")\n+        sys.exit(1)\n+\n+    with open(myelffile, 'rb') as file:\n+        try:\n+            readelf = ReadElf(file, sys.stdout)\n+            readelf.process_dt_needed_entries()\n+            readelf.display_pmd_info_strings(\".rodata\") \n+            sys.exit(0)\n+ \n+        except ELFError as ex:\n+            sys.stderr.write('ELF error: %s\\n' % ex)\n+            sys.exit(1)\n+\n+\n+#-------------------------------------------------------------------------------\n+if __name__ == '__main__':\n+    main()\n+\n+\n",
    "prefixes": [
        "dpdk-dev",
        "PATCHv2",
        "4/4"
    ]
}