get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 13425,
    "url": "https://patches.dpdk.org/api/patches/13425/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1465494421-6210-6-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": "<1465494421-6210-6-git-send-email-nhorman@tuxdriver.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1465494421-6210-6-git-send-email-nhorman@tuxdriver.com",
    "date": "2016-06-09T17:47:00",
    "name": "[dpdk-dev,PATCHv7,5/6] pmdinfo.py: Add tool to query binaries for hw and other support information",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "e7b2e3ca85114941f8e75f10eac71f00b9d47284",
    "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/1465494421-6210-6-git-send-email-nhorman@tuxdriver.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/13425/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/13425/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 62FD22B87;\n\tThu,  9 Jun 2016 19:47:40 +0200 (CEST)",
            "from smtp.tuxdriver.com (charlotte.tuxdriver.com [70.61.120.58])\n\tby dpdk.org (Postfix) with ESMTP id 22A062B83\n\tfor <dev@dpdk.org>; Thu,  9 Jun 2016 19:47:39 +0200 (CEST)",
            "from [107.15.76.160] (helo=localhost)\n\tby smtp.tuxdriver.com with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.63)\n\t(envelope-from <nhorman@tuxdriver.com>)\n\tid 1bB43I-00008I-Ek; Thu, 09 Jun 2016 13:47:36 -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": "Thu,  9 Jun 2016 13:47:00 -0400",
        "Message-Id": "<1465494421-6210-6-git-send-email-nhorman@tuxdriver.com>",
        "X-Mailer": "git-send-email 2.5.5",
        "In-Reply-To": "<1465494421-6210-1-git-send-email-nhorman@tuxdriver.com>",
        "References": "<1463431287-4551-1-git-send-email-nhorman@tuxdriver.com>\n\t<1465494421-6210-1-git-send-email-nhorman@tuxdriver.com>",
        "X-Spam-Score": "-1.0 (-)",
        "X-Spam-Status": "No",
        "Subject": "[dpdk-dev] [PATCHv7 5/6] 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\nscan for implicitly linked PMDs by searching the specified binaries\n.dynamic section for DT_NEEDED entries that contain the substring\nlibrte_pmd.  The DT_RUNPATH, LD_LIBRARY_PATH, /usr/lib and /lib are\nsearched for these libraries, in that order\n\nIf a file is specified with no path, it is assumed to be a PMD DSO, and the\nLD_LIBRARY_PATH, /usr/lib[64]/ and /lib[64] 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\nand device 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 mk/rte.sdkinstall.mk |   2 +\n tools/pmdinfo.py     | 629 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 631 insertions(+)\n create mode 100755 tools/pmdinfo.py",
    "diff": "diff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk\nindex 68e56b6..dc36df5 100644\n--- a/mk/rte.sdkinstall.mk\n+++ b/mk/rte.sdkinstall.mk\n@@ -126,6 +126,8 @@ install-runtime:\n \t$(Q)$(call rte_mkdir,      $(DESTDIR)$(sbindir))\n \t$(Q)$(call rte_symlink,    $(DESTDIR)$(datadir)/tools/dpdk_nic_bind.py, \\\n \t                           $(DESTDIR)$(sbindir)/dpdk_nic_bind)\n+\t$(Q)$(call rte_symlink,    $(DESTDIR)$(datadir)/tools/pmdinfo.py, \\\n+\t\t\t\t   $(DESTDIR)$(bindir)/dpdk-pmdinfo)\n \n install-kmod:\n ifneq ($(wildcard $O/kmod/*),)\ndiff --git a/tools/pmdinfo.py b/tools/pmdinfo.py\nnew file mode 100755\nindex 0000000..e531154\n--- /dev/null\n+++ b/tools/pmdinfo.py\n@@ -0,0 +1,629 @@\n+#!/usr/bin/python\n+# -------------------------------------------------------------------------\n+# scripts/pmdinfo.py\n+#\n+# Utility to dump PMD_INFO_STRING support from an object file\n+#\n+# -------------------------------------------------------------------------\n+import os\n+import 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+\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+\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\" % devid)\n+\n+\n+class Device:\n+\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(\n+            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+\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+\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\"].\\\n+    subdevices[\"0e11:4091\"].name  =  \"Smart Array 6i\"\n+    \"\"\"\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 is not 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\" % (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[\n+                            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+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):\n+            return os.path.abspath(candidate)\n+    return None\n+\n+\n+class ReadElf(object):\n+    \"\"\" display_* methods are used to emit output into the output stream\n+    \"\"\"\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\" %\n+                  (vendor.name, vendor.ID, device.name,\n+                   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+        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 (len(pmdinfo[\"pci_ids\"]) != 0):\n+            print(\"PMD HW SUPPORT:\")\n+            if pcidb is not 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\" %\n+                          (i[0], i[1], i[2], i[3]))\n+\n+        print(\"\")\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+        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 find_librte_eal(self, section):\n+        for tag in section.iter_tags():\n+            if tag.entry.d_tag == 'DT_NEEDED':\n+                if \"librte_eal\" in tag.needed:\n+                    return tag.needed\n+        return None\n+\n+    def search_for_autoload_path(self):\n+        scanelf = self\n+        scanfile = None\n+        library = None\n+\n+        section = self._section_from_spec(\".dynamic\")\n+        try:\n+            eallib = self.find_librte_eal(section)\n+            if eallib is not None:\n+                ldlibpath = os.environ.get('LD_LIBRARY_PATH')\n+                if ldlibpath is None:\n+                    ldlibpath = \"\"\n+                dtr = self.get_dt_runpath(section)\n+                library = search_file(eallib,\n+                                      dtr + \":\" + ldlibpath +\n+                                      \":/usr/lib64:/lib64:/usr/lib:/lib\")\n+                if library is None:\n+                    return (None, None)\n+                if raw_output is False:\n+                    print(\"Scanning for autoload path in %s\" % library)\n+                scanfile = open(library, 'rb')\n+                scanelf = ReadElf(scanfile, sys.stdout)\n+        except AttributeError:\n+            # Not a dynamic binary\n+            pass\n+        except ELFError:\n+            scanfile.close()\n+            return (None, None)\n+\n+        section = scanelf._section_from_spec(\".rodata\")\n+        if section is None:\n+            if scanfile is not None:\n+                scanfile.close()\n+            return (None, None)\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(\"DPDK_PLUGIN_PATH\")\n+            if (rc != -1):\n+                rc = mystring.find(\"=\")\n+                return (mystring[rc + 1:], library)\n+\n+            dataptr = endptr\n+        if scanfile is not None:\n+            scanfile.close()\n+        return (None, None)\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+    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 is 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/lib64:/lib64:/usr/lib:/lib\")\n+                    if library is not None:\n+                        if raw_output is False:\n+                            print(\"Scanning %s for pmd information\" % library)\n+                        with open(library, 'rb') as file:\n+                            try:\n+                                libelf = ReadElf(file, sys.stdout)\n+                            except ELFError as e:\n+                                print(\"%s is no an ELF file\" % library)\n+                                continue\n+                            libelf.process_dt_needed_entries()\n+                            libelf.display_pmd_info_strings(\".rodata\")\n+                            file.close()\n+\n+\n+def scan_autoload_path(autoload_path):\n+    global raw_output\n+\n+    if os.path.exists(autoload_path) is False:\n+        return\n+\n+    try:\n+        dirs = os.listdir(autoload_path)\n+    except OSError as e:\n+        # Couldn't read the directory, give up\n+        return\n+\n+    for d in dirs:\n+        dpath = os.path.join(autoload_path, d)\n+        if os.path.isdir(dpath):\n+            scan_autoload_path(dpath)\n+        if os.path.isfile(dpath):\n+            try:\n+                file = open(dpath, 'rb')\n+                readelf = ReadElf(file, sys.stdout)\n+            except ELFError as e:\n+                # this is likely not an elf file, skip it\n+                continue\n+            except IOError as e:\n+                # No permission to read the file, skip it\n+                continue\n+\n+            if raw_output is False:\n+                print(\"Hw Support for library %s\" % d)\n+            readelf.display_pmd_info_strings(\".rodata\")\n+            file.close()\n+\n+\n+def scan_for_autoload_pmds(dpdk_path):\n+    \"\"\"\n+    search the specified application or path for a pmd autoload path\n+    then scan said path for pmds and report hw support\n+    \"\"\"\n+    global raw_output\n+\n+    if (os.path.isfile(dpdk_path) is False):\n+        if raw_output is False:\n+            print(\"Must specify a file name\")\n+        return\n+\n+    file = open(dpdk_path, 'rb')\n+    try:\n+        readelf = ReadElf(file, sys.stdout)\n+    except ElfError as e:\n+        if raw_output is False:\n+            print(\"Unable to parse %s\" % file)\n+        return\n+\n+    (autoload_path, scannedfile) = readelf.search_for_autoload_path()\n+    if (autoload_path is None or autoload_path is \"\"):\n+        if (raw_output is False):\n+            print(\"No autoload path configured in %s\" % dpdk_path)\n+        return\n+    if (raw_output is False):\n+        if (scannedfile is None):\n+            scannedfile = dpdk_path\n+        print(\"Found autoload path %s in %s\" % (autoload_path, scannedfile))\n+\n+    file.close()\n+    if (raw_output is False):\n+        print(\"Discovered Autoload HW Support:\")\n+    scan_autoload_path(autoload_path)\n+    return\n+\n+\n+def main(stream=None):\n+    global raw_output\n+    global pcidb\n+\n+    optparser = OptionParser(\n+        usage='usage: %prog [-hrtp] [-d <pci id file] <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=\"specify a pci database \"\n+                              \"to get vendor names from\",\n+                         default=\"/usr/share/hwdata/pci.ids\", metavar=\"FILE\")\n+    optparser.add_option(\"-t\", \"--table\", dest=\"tblout\",\n+                         help=\"output information on hw support as a hex table\",\n+                         action='store_true')\n+    optparser.add_option(\"-p\", \"--plugindir\", dest=\"pdir\",\n+                         help=\"scan dpdk for autoload plugins\",\n+                         action='store_true')\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 is None:\n+            print(\"Pci DB file not found\")\n+            exit(1)\n+\n+    if options.tblout:\n+        options.pcifile = None\n+        pcidb = None\n+\n+    if (len(args) == 0):\n+        optparser.print_usage()\n+        exit(1)\n+\n+    if options.pdir is True:\n+        exit(scan_for_autoload_pmds(args[0]))\n+\n+    ldlibpath = os.environ.get('LD_LIBRARY_PATH')\n+    if (ldlibpath is None):\n+        ldlibpath = \"\"\n+\n+    if (os.path.exists(args[0]) is True):\n+        myelffile = args[0]\n+    else:\n+        myelffile = search_file(\n+            args[0], ldlibpath + \":/usr/lib64:/lib64:/usr/lib:/lib\")\n+\n+    if (myelffile is 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",
    "prefixes": [
        "dpdk-dev",
        "PATCHv7",
        "5/6"
    ]
}