Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/12889/?format=api
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" ] }{ "id": 12889, "url": "