1*2d9fd380Sjfb8856606#!/usr/bin/env python3 2d30ea906Sjfb8856606# SPDX-License-Identifier: BSD-3-Clause 3d30ea906Sjfb8856606# Copyright(c) 2016 Neil Horman <[email protected]> 42bfe3f2eSlogwang 52bfe3f2eSlogwang# ------------------------------------------------------------------------- 62bfe3f2eSlogwang# 72bfe3f2eSlogwang# Utility to dump PMD_INFO_STRING support from an object file 82bfe3f2eSlogwang# 92bfe3f2eSlogwang# ------------------------------------------------------------------------- 102bfe3f2eSlogwangimport json 112bfe3f2eSlogwangimport os 122bfe3f2eSlogwangimport platform 132bfe3f2eSlogwangimport sys 14*2d9fd380Sjfb8856606import argparse 152bfe3f2eSlogwangfrom elftools.common.exceptions import ELFError 164418919fSjohnjiangfrom elftools.common.py3compat import byte2int 172bfe3f2eSlogwangfrom elftools.elf.elffile import ELFFile 18*2d9fd380Sjfb8856606 192bfe3f2eSlogwang 202bfe3f2eSlogwang# For running from development directory. It should take precedence over the 212bfe3f2eSlogwang# installed pyelftools. 222bfe3f2eSlogwangsys.path.insert(0, '.') 232bfe3f2eSlogwang 242bfe3f2eSlogwangraw_output = False 252bfe3f2eSlogwangpcidb = None 262bfe3f2eSlogwang 272bfe3f2eSlogwang# =========================================== 282bfe3f2eSlogwang 292bfe3f2eSlogwangclass Vendor: 302bfe3f2eSlogwang """ 312bfe3f2eSlogwang Class for vendors. This is the top level class 322bfe3f2eSlogwang for the devices belong to a specific vendor. 332bfe3f2eSlogwang self.devices is the device dictionary 342bfe3f2eSlogwang subdevices are in each device. 352bfe3f2eSlogwang """ 362bfe3f2eSlogwang 372bfe3f2eSlogwang def __init__(self, vendorStr): 382bfe3f2eSlogwang """ 392bfe3f2eSlogwang Class initializes with the raw line from pci.ids 402bfe3f2eSlogwang Parsing takes place inside __init__ 412bfe3f2eSlogwang """ 422bfe3f2eSlogwang self.ID = vendorStr.split()[0] 432bfe3f2eSlogwang self.name = vendorStr.replace("%s " % self.ID, "").rstrip() 442bfe3f2eSlogwang self.devices = {} 452bfe3f2eSlogwang 462bfe3f2eSlogwang def addDevice(self, deviceStr): 472bfe3f2eSlogwang """ 482bfe3f2eSlogwang Adds a device to self.devices 492bfe3f2eSlogwang takes the raw line from pci.ids 502bfe3f2eSlogwang """ 512bfe3f2eSlogwang s = deviceStr.strip() 522bfe3f2eSlogwang devID = s.split()[0] 532bfe3f2eSlogwang if devID in self.devices: 542bfe3f2eSlogwang pass 552bfe3f2eSlogwang else: 562bfe3f2eSlogwang self.devices[devID] = Device(deviceStr) 572bfe3f2eSlogwang 582bfe3f2eSlogwang def report(self): 592bfe3f2eSlogwang print(self.ID, self.name) 602bfe3f2eSlogwang for id, dev in self.devices.items(): 612bfe3f2eSlogwang dev.report() 622bfe3f2eSlogwang 632bfe3f2eSlogwang def find_device(self, devid): 642bfe3f2eSlogwang # convert to a hex string and remove 0x 652bfe3f2eSlogwang devid = hex(devid)[2:] 662bfe3f2eSlogwang try: 672bfe3f2eSlogwang return self.devices[devid] 682bfe3f2eSlogwang except: 692bfe3f2eSlogwang return Device("%s Unknown Device" % devid) 702bfe3f2eSlogwang 712bfe3f2eSlogwang 722bfe3f2eSlogwangclass Device: 732bfe3f2eSlogwang 742bfe3f2eSlogwang def __init__(self, deviceStr): 752bfe3f2eSlogwang """ 762bfe3f2eSlogwang Class for each device. 772bfe3f2eSlogwang Each vendor has its own devices dictionary. 782bfe3f2eSlogwang """ 792bfe3f2eSlogwang s = deviceStr.strip() 802bfe3f2eSlogwang self.ID = s.split()[0] 812bfe3f2eSlogwang self.name = s.replace("%s " % self.ID, "") 822bfe3f2eSlogwang self.subdevices = {} 832bfe3f2eSlogwang 842bfe3f2eSlogwang def report(self): 852bfe3f2eSlogwang print("\t%s\t%s" % (self.ID, self.name)) 862bfe3f2eSlogwang for subID, subdev in self.subdevices.items(): 872bfe3f2eSlogwang subdev.report() 882bfe3f2eSlogwang 892bfe3f2eSlogwang def addSubDevice(self, subDeviceStr): 902bfe3f2eSlogwang """ 912bfe3f2eSlogwang Adds a subvendor, subdevice to device. 922bfe3f2eSlogwang Uses raw line from pci.ids 932bfe3f2eSlogwang """ 942bfe3f2eSlogwang s = subDeviceStr.strip() 952bfe3f2eSlogwang spl = s.split() 962bfe3f2eSlogwang subVendorID = spl[0] 972bfe3f2eSlogwang subDeviceID = spl[1] 982bfe3f2eSlogwang subDeviceName = s.split(" ")[-1] 992bfe3f2eSlogwang devID = "%s:%s" % (subVendorID, subDeviceID) 1002bfe3f2eSlogwang self.subdevices[devID] = SubDevice( 1012bfe3f2eSlogwang subVendorID, subDeviceID, subDeviceName) 1022bfe3f2eSlogwang 1032bfe3f2eSlogwang def find_subid(self, subven, subdev): 1042bfe3f2eSlogwang subven = hex(subven)[2:] 1052bfe3f2eSlogwang subdev = hex(subdev)[2:] 1062bfe3f2eSlogwang devid = "%s:%s" % (subven, subdev) 1072bfe3f2eSlogwang 1082bfe3f2eSlogwang try: 1092bfe3f2eSlogwang return self.subdevices[devid] 1102bfe3f2eSlogwang except: 1112bfe3f2eSlogwang if (subven == "ffff" and subdev == "ffff"): 1122bfe3f2eSlogwang return SubDevice("ffff", "ffff", "(All Subdevices)") 1132bfe3f2eSlogwang return SubDevice(subven, subdev, "(Unknown Subdevice)") 1142bfe3f2eSlogwang 1152bfe3f2eSlogwang 1162bfe3f2eSlogwangclass SubDevice: 1172bfe3f2eSlogwang """ 1182bfe3f2eSlogwang Class for subdevices. 1192bfe3f2eSlogwang """ 1202bfe3f2eSlogwang 1212bfe3f2eSlogwang def __init__(self, vendor, device, name): 1222bfe3f2eSlogwang """ 1232bfe3f2eSlogwang Class initializes with vendorid, deviceid and name 1242bfe3f2eSlogwang """ 1252bfe3f2eSlogwang self.vendorID = vendor 1262bfe3f2eSlogwang self.deviceID = device 1272bfe3f2eSlogwang self.name = name 1282bfe3f2eSlogwang 1292bfe3f2eSlogwang def report(self): 1302bfe3f2eSlogwang print("\t\t%s\t%s\t%s" % (self.vendorID, self.deviceID, self.name)) 1312bfe3f2eSlogwang 1322bfe3f2eSlogwang 1332bfe3f2eSlogwangclass PCIIds: 1342bfe3f2eSlogwang """ 1352bfe3f2eSlogwang Top class for all pci.ids entries. 1362bfe3f2eSlogwang All queries will be asked to this class. 1372bfe3f2eSlogwang PCIIds.vendors["0e11"].devices["0046"].\ 1382bfe3f2eSlogwang subdevices["0e11:4091"].name = "Smart Array 6i" 1392bfe3f2eSlogwang """ 1402bfe3f2eSlogwang 1412bfe3f2eSlogwang def __init__(self, filename): 1422bfe3f2eSlogwang """ 1432bfe3f2eSlogwang Prepares the directories. 1442bfe3f2eSlogwang Checks local data file. 1452bfe3f2eSlogwang Tries to load from local, if not found, downloads from web 1462bfe3f2eSlogwang """ 1472bfe3f2eSlogwang self.version = "" 1482bfe3f2eSlogwang self.date = "" 1492bfe3f2eSlogwang self.vendors = {} 1502bfe3f2eSlogwang self.contents = None 1512bfe3f2eSlogwang self.readLocal(filename) 1522bfe3f2eSlogwang self.parse() 1532bfe3f2eSlogwang 1542bfe3f2eSlogwang def reportVendors(self): 1552bfe3f2eSlogwang """Reports the vendors 1562bfe3f2eSlogwang """ 1572bfe3f2eSlogwang for vid, v in self.vendors.items(): 1582bfe3f2eSlogwang print(v.ID, v.name) 1592bfe3f2eSlogwang 1602bfe3f2eSlogwang def report(self, vendor=None): 1612bfe3f2eSlogwang """ 1622bfe3f2eSlogwang Reports everything for all vendors or a specific vendor 1632bfe3f2eSlogwang PCIIds.report() reports everything 1642bfe3f2eSlogwang PCIIDs.report("0e11") reports only "Compaq Computer Corporation" 1652bfe3f2eSlogwang """ 1662bfe3f2eSlogwang if vendor is not None: 1672bfe3f2eSlogwang self.vendors[vendor].report() 1682bfe3f2eSlogwang else: 1692bfe3f2eSlogwang for vID, v in self.vendors.items(): 1702bfe3f2eSlogwang v.report() 1712bfe3f2eSlogwang 1722bfe3f2eSlogwang def find_vendor(self, vid): 1732bfe3f2eSlogwang # convert vid to a hex string and remove the 0x 1742bfe3f2eSlogwang vid = hex(vid)[2:] 1752bfe3f2eSlogwang 1762bfe3f2eSlogwang try: 1772bfe3f2eSlogwang return self.vendors[vid] 1782bfe3f2eSlogwang except: 1792bfe3f2eSlogwang return Vendor("%s Unknown Vendor" % (vid)) 1802bfe3f2eSlogwang 1812bfe3f2eSlogwang def findDate(self, content): 1822bfe3f2eSlogwang for l in content: 1832bfe3f2eSlogwang if l.find("Date:") > -1: 1842bfe3f2eSlogwang return l.split()[-2].replace("-", "") 1852bfe3f2eSlogwang return None 1862bfe3f2eSlogwang 1872bfe3f2eSlogwang def parse(self): 188*2d9fd380Sjfb8856606 if not self.contents: 1892bfe3f2eSlogwang print("data/%s-pci.ids not found" % self.date) 1902bfe3f2eSlogwang else: 1912bfe3f2eSlogwang vendorID = "" 1922bfe3f2eSlogwang deviceID = "" 1932bfe3f2eSlogwang for l in self.contents: 1942bfe3f2eSlogwang if l[0] == "#": 1952bfe3f2eSlogwang continue 196*2d9fd380Sjfb8856606 elif not l.strip(): 1972bfe3f2eSlogwang continue 1982bfe3f2eSlogwang else: 1992bfe3f2eSlogwang if l.find("\t\t") == 0: 2002bfe3f2eSlogwang self.vendors[vendorID].devices[ 2012bfe3f2eSlogwang deviceID].addSubDevice(l) 2022bfe3f2eSlogwang elif l.find("\t") == 0: 2032bfe3f2eSlogwang deviceID = l.strip().split()[0] 2042bfe3f2eSlogwang self.vendors[vendorID].addDevice(l) 2052bfe3f2eSlogwang else: 2062bfe3f2eSlogwang vendorID = l.split()[0] 2072bfe3f2eSlogwang self.vendors[vendorID] = Vendor(l) 2082bfe3f2eSlogwang 2092bfe3f2eSlogwang def readLocal(self, filename): 2102bfe3f2eSlogwang """ 2112bfe3f2eSlogwang Reads the local file 2122bfe3f2eSlogwang """ 213*2d9fd380Sjfb8856606 with open(filename, 'r', encoding='utf-8') as f: 2144418919fSjohnjiang self.contents = f.readlines() 2152bfe3f2eSlogwang self.date = self.findDate(self.contents) 2162bfe3f2eSlogwang 2172bfe3f2eSlogwang def loadLocal(self): 2182bfe3f2eSlogwang """ 2192bfe3f2eSlogwang Loads database from local. If there is no file, 2202bfe3f2eSlogwang it creates a new one from web 2212bfe3f2eSlogwang """ 2222bfe3f2eSlogwang self.date = idsfile[0].split("/")[1].split("-")[0] 2232bfe3f2eSlogwang self.readLocal() 2242bfe3f2eSlogwang 2252bfe3f2eSlogwang 2262bfe3f2eSlogwang# ======================================= 2272bfe3f2eSlogwang 2282bfe3f2eSlogwangdef search_file(filename, search_path): 2292bfe3f2eSlogwang """ Given a search path, find file with requested name """ 230*2d9fd380Sjfb8856606 for path in search_path.split(':'): 2312bfe3f2eSlogwang candidate = os.path.join(path, filename) 2322bfe3f2eSlogwang if os.path.exists(candidate): 2332bfe3f2eSlogwang return os.path.abspath(candidate) 2342bfe3f2eSlogwang return None 2352bfe3f2eSlogwang 2362bfe3f2eSlogwang 2372bfe3f2eSlogwangclass ReadElf(object): 2382bfe3f2eSlogwang """ display_* methods are used to emit output into the output stream 2392bfe3f2eSlogwang """ 2402bfe3f2eSlogwang 2412bfe3f2eSlogwang def __init__(self, file, output): 2422bfe3f2eSlogwang """ file: 2432bfe3f2eSlogwang stream object with the ELF file to read 2442bfe3f2eSlogwang 2452bfe3f2eSlogwang output: 2462bfe3f2eSlogwang output stream to write to 2472bfe3f2eSlogwang """ 2482bfe3f2eSlogwang self.elffile = ELFFile(file) 2492bfe3f2eSlogwang self.output = output 2502bfe3f2eSlogwang 2512bfe3f2eSlogwang # Lazily initialized if a debug dump is requested 2522bfe3f2eSlogwang self._dwarfinfo = None 2532bfe3f2eSlogwang 2542bfe3f2eSlogwang self._versioninfo = None 2552bfe3f2eSlogwang 2562bfe3f2eSlogwang def _section_from_spec(self, spec): 2572bfe3f2eSlogwang """ Retrieve a section given a "spec" (either number or name). 2582bfe3f2eSlogwang Return None if no such section exists in the file. 2592bfe3f2eSlogwang """ 2602bfe3f2eSlogwang try: 2612bfe3f2eSlogwang num = int(spec) 2622bfe3f2eSlogwang if num < self.elffile.num_sections(): 2632bfe3f2eSlogwang return self.elffile.get_section(num) 2642bfe3f2eSlogwang return None 2652bfe3f2eSlogwang except ValueError: 2662bfe3f2eSlogwang # Not a number. Must be a name then 2674418919fSjohnjiang section = self.elffile.get_section_by_name(force_unicode(spec)) 2684418919fSjohnjiang if section is None: 2694418919fSjohnjiang # No match with a unicode name. 2704418919fSjohnjiang # Some versions of pyelftools (<= 0.23) store internal strings 2714418919fSjohnjiang # as bytes. Try again with the name encoded as bytes. 2724418919fSjohnjiang section = self.elffile.get_section_by_name(force_bytes(spec)) 2734418919fSjohnjiang return section 2742bfe3f2eSlogwang 2752bfe3f2eSlogwang def pretty_print_pmdinfo(self, pmdinfo): 2762bfe3f2eSlogwang global pcidb 2772bfe3f2eSlogwang 2782bfe3f2eSlogwang for i in pmdinfo["pci_ids"]: 2792bfe3f2eSlogwang vendor = pcidb.find_vendor(i[0]) 2802bfe3f2eSlogwang device = vendor.find_device(i[1]) 2812bfe3f2eSlogwang subdev = device.find_subid(i[2], i[3]) 2822bfe3f2eSlogwang print("%s (%s) : %s (%s) %s" % 2832bfe3f2eSlogwang (vendor.name, vendor.ID, device.name, 2842bfe3f2eSlogwang device.ID, subdev.name)) 2852bfe3f2eSlogwang 2862bfe3f2eSlogwang def parse_pmd_info_string(self, mystring): 2872bfe3f2eSlogwang global raw_output 2882bfe3f2eSlogwang global pcidb 2892bfe3f2eSlogwang 2902bfe3f2eSlogwang optional_pmd_info = [ 2912bfe3f2eSlogwang {'id': 'params', 'tag': 'PMD PARAMETERS'}, 2922bfe3f2eSlogwang {'id': 'kmod', 'tag': 'PMD KMOD DEPENDENCIES'} 2932bfe3f2eSlogwang ] 2942bfe3f2eSlogwang 2952bfe3f2eSlogwang i = mystring.index("=") 2962bfe3f2eSlogwang mystring = mystring[i + 2:] 2972bfe3f2eSlogwang pmdinfo = json.loads(mystring) 2982bfe3f2eSlogwang 2992bfe3f2eSlogwang if raw_output: 3002bfe3f2eSlogwang print(json.dumps(pmdinfo)) 3012bfe3f2eSlogwang return 3022bfe3f2eSlogwang 3032bfe3f2eSlogwang print("PMD NAME: " + pmdinfo["name"]) 3042bfe3f2eSlogwang for i in optional_pmd_info: 3052bfe3f2eSlogwang try: 3062bfe3f2eSlogwang print("%s: %s" % (i['tag'], pmdinfo[i['id']])) 3072bfe3f2eSlogwang except KeyError: 3082bfe3f2eSlogwang continue 3092bfe3f2eSlogwang 310*2d9fd380Sjfb8856606 if pmdinfo["pci_ids"]: 3112bfe3f2eSlogwang print("PMD HW SUPPORT:") 3122bfe3f2eSlogwang if pcidb is not None: 3132bfe3f2eSlogwang self.pretty_print_pmdinfo(pmdinfo) 3142bfe3f2eSlogwang else: 3152bfe3f2eSlogwang print("VENDOR\t DEVICE\t SUBVENDOR\t SUBDEVICE") 3162bfe3f2eSlogwang for i in pmdinfo["pci_ids"]: 3172bfe3f2eSlogwang print("0x%04x\t 0x%04x\t 0x%04x\t\t 0x%04x" % 3182bfe3f2eSlogwang (i[0], i[1], i[2], i[3])) 3192bfe3f2eSlogwang 3202bfe3f2eSlogwang print("") 3212bfe3f2eSlogwang 3222bfe3f2eSlogwang def display_pmd_info_strings(self, section_spec): 3232bfe3f2eSlogwang """ Display a strings dump of a section. section_spec is either a 3242bfe3f2eSlogwang section number or a name. 3252bfe3f2eSlogwang """ 3262bfe3f2eSlogwang section = self._section_from_spec(section_spec) 3272bfe3f2eSlogwang if section is None: 3282bfe3f2eSlogwang return 3292bfe3f2eSlogwang 3302bfe3f2eSlogwang data = section.data() 3312bfe3f2eSlogwang dataptr = 0 3322bfe3f2eSlogwang 3332bfe3f2eSlogwang while dataptr < len(data): 3342bfe3f2eSlogwang while (dataptr < len(data) and 335*2d9fd380Sjfb8856606 not 32 <= byte2int(data[dataptr]) <= 127): 3362bfe3f2eSlogwang dataptr += 1 3372bfe3f2eSlogwang 3382bfe3f2eSlogwang if dataptr >= len(data): 3392bfe3f2eSlogwang break 3402bfe3f2eSlogwang 3412bfe3f2eSlogwang endptr = dataptr 3422bfe3f2eSlogwang while endptr < len(data) and byte2int(data[endptr]) != 0: 3432bfe3f2eSlogwang endptr += 1 3442bfe3f2eSlogwang 3454418919fSjohnjiang # pyelftools may return byte-strings, force decode them 3464418919fSjohnjiang mystring = force_unicode(data[dataptr:endptr]) 3472bfe3f2eSlogwang rc = mystring.find("PMD_INFO_STRING") 348*2d9fd380Sjfb8856606 if rc != -1: 3490c6bd470Sfengbojiang self.parse_pmd_info_string(mystring[rc:]) 3502bfe3f2eSlogwang 3512bfe3f2eSlogwang dataptr = endptr 3522bfe3f2eSlogwang 3532bfe3f2eSlogwang def find_librte_eal(self, section): 3542bfe3f2eSlogwang for tag in section.iter_tags(): 3554418919fSjohnjiang # pyelftools may return byte-strings, force decode them 3564418919fSjohnjiang if force_unicode(tag.entry.d_tag) == 'DT_NEEDED': 3574418919fSjohnjiang if "librte_eal" in force_unicode(tag.needed): 3584418919fSjohnjiang return force_unicode(tag.needed) 3592bfe3f2eSlogwang return None 3602bfe3f2eSlogwang 3612bfe3f2eSlogwang def search_for_autoload_path(self): 3622bfe3f2eSlogwang scanelf = self 3632bfe3f2eSlogwang scanfile = None 3642bfe3f2eSlogwang library = None 3652bfe3f2eSlogwang 3662bfe3f2eSlogwang section = self._section_from_spec(".dynamic") 3672bfe3f2eSlogwang try: 3682bfe3f2eSlogwang eallib = self.find_librte_eal(section) 3692bfe3f2eSlogwang if eallib is not None: 3702bfe3f2eSlogwang ldlibpath = os.environ.get('LD_LIBRARY_PATH') 3712bfe3f2eSlogwang if ldlibpath is None: 3722bfe3f2eSlogwang ldlibpath = "" 3732bfe3f2eSlogwang dtr = self.get_dt_runpath(section) 3742bfe3f2eSlogwang library = search_file(eallib, 3752bfe3f2eSlogwang dtr + ":" + ldlibpath + 3762bfe3f2eSlogwang ":/usr/lib64:/lib64:/usr/lib:/lib") 3772bfe3f2eSlogwang if library is None: 3782bfe3f2eSlogwang return (None, None) 379*2d9fd380Sjfb8856606 if not raw_output: 3802bfe3f2eSlogwang print("Scanning for autoload path in %s" % library) 381*2d9fd380Sjfb8856606 scanfile = open(library, 'rb') 3822bfe3f2eSlogwang scanelf = ReadElf(scanfile, sys.stdout) 3832bfe3f2eSlogwang except AttributeError: 3842bfe3f2eSlogwang # Not a dynamic binary 3852bfe3f2eSlogwang pass 3862bfe3f2eSlogwang except ELFError: 3872bfe3f2eSlogwang scanfile.close() 3882bfe3f2eSlogwang return (None, None) 3892bfe3f2eSlogwang 3902bfe3f2eSlogwang section = scanelf._section_from_spec(".rodata") 3912bfe3f2eSlogwang if section is None: 3922bfe3f2eSlogwang if scanfile is not None: 3932bfe3f2eSlogwang scanfile.close() 3942bfe3f2eSlogwang return (None, None) 3952bfe3f2eSlogwang 3962bfe3f2eSlogwang data = section.data() 3972bfe3f2eSlogwang dataptr = 0 3982bfe3f2eSlogwang 3992bfe3f2eSlogwang while dataptr < len(data): 4002bfe3f2eSlogwang while (dataptr < len(data) and 401*2d9fd380Sjfb8856606 not 32 <= byte2int(data[dataptr]) <= 127): 4022bfe3f2eSlogwang dataptr += 1 4032bfe3f2eSlogwang 4042bfe3f2eSlogwang if dataptr >= len(data): 4052bfe3f2eSlogwang break 4062bfe3f2eSlogwang 4072bfe3f2eSlogwang endptr = dataptr 4082bfe3f2eSlogwang while endptr < len(data) and byte2int(data[endptr]) != 0: 4092bfe3f2eSlogwang endptr += 1 4102bfe3f2eSlogwang 4114418919fSjohnjiang # pyelftools may return byte-strings, force decode them 4124418919fSjohnjiang mystring = force_unicode(data[dataptr:endptr]) 4132bfe3f2eSlogwang rc = mystring.find("DPDK_PLUGIN_PATH") 414*2d9fd380Sjfb8856606 if rc != -1: 4152bfe3f2eSlogwang rc = mystring.find("=") 4162bfe3f2eSlogwang return (mystring[rc + 1:], library) 4172bfe3f2eSlogwang 4182bfe3f2eSlogwang dataptr = endptr 4192bfe3f2eSlogwang if scanfile is not None: 4202bfe3f2eSlogwang scanfile.close() 4212bfe3f2eSlogwang return (None, None) 4222bfe3f2eSlogwang 4232bfe3f2eSlogwang def get_dt_runpath(self, dynsec): 4242bfe3f2eSlogwang for tag in dynsec.iter_tags(): 4254418919fSjohnjiang # pyelftools may return byte-strings, force decode them 4264418919fSjohnjiang if force_unicode(tag.entry.d_tag) == 'DT_RUNPATH': 4274418919fSjohnjiang return force_unicode(tag.runpath) 4282bfe3f2eSlogwang return "" 4292bfe3f2eSlogwang 4302bfe3f2eSlogwang def process_dt_needed_entries(self): 4312bfe3f2eSlogwang """ Look to see if there are any DT_NEEDED entries in the binary 4322bfe3f2eSlogwang And process those if there are 4332bfe3f2eSlogwang """ 4342bfe3f2eSlogwang runpath = "" 4352bfe3f2eSlogwang ldlibpath = os.environ.get('LD_LIBRARY_PATH') 4362bfe3f2eSlogwang if ldlibpath is None: 4372bfe3f2eSlogwang ldlibpath = "" 4382bfe3f2eSlogwang 4392bfe3f2eSlogwang dynsec = self._section_from_spec(".dynamic") 4402bfe3f2eSlogwang try: 4412bfe3f2eSlogwang runpath = self.get_dt_runpath(dynsec) 4422bfe3f2eSlogwang except AttributeError: 4432bfe3f2eSlogwang # dynsec is None, just return 4442bfe3f2eSlogwang return 4452bfe3f2eSlogwang 4462bfe3f2eSlogwang for tag in dynsec.iter_tags(): 4474418919fSjohnjiang # pyelftools may return byte-strings, force decode them 4484418919fSjohnjiang if force_unicode(tag.entry.d_tag) == 'DT_NEEDED': 449*2d9fd380Sjfb8856606 if 'librte_' in force_unicode(tag.needed): 4504418919fSjohnjiang library = search_file(force_unicode(tag.needed), 4512bfe3f2eSlogwang runpath + ":" + ldlibpath + 4522bfe3f2eSlogwang ":/usr/lib64:/lib64:/usr/lib:/lib") 4532bfe3f2eSlogwang if library is not None: 454*2d9fd380Sjfb8856606 with open(library, 'rb') as file: 4552bfe3f2eSlogwang try: 4562bfe3f2eSlogwang libelf = ReadElf(file, sys.stdout) 4572bfe3f2eSlogwang except ELFError: 4582bfe3f2eSlogwang print("%s is no an ELF file" % library) 4592bfe3f2eSlogwang continue 4602bfe3f2eSlogwang libelf.process_dt_needed_entries() 4612bfe3f2eSlogwang libelf.display_pmd_info_strings(".rodata") 4622bfe3f2eSlogwang file.close() 4632bfe3f2eSlogwang 4642bfe3f2eSlogwang 4654418919fSjohnjiang# compat: remove force_unicode & force_bytes when pyelftools<=0.23 support is 4664418919fSjohnjiang# dropped. 4674418919fSjohnjiangdef force_unicode(s): 4684418919fSjohnjiang if hasattr(s, 'decode') and callable(s.decode): 4694418919fSjohnjiang s = s.decode('latin-1') # same encoding used in pyelftools py3compat 4704418919fSjohnjiang return s 4714418919fSjohnjiang 4724418919fSjohnjiang 4734418919fSjohnjiangdef force_bytes(s): 4744418919fSjohnjiang if hasattr(s, 'encode') and callable(s.encode): 4754418919fSjohnjiang s = s.encode('latin-1') # same encoding used in pyelftools py3compat 4764418919fSjohnjiang return s 4774418919fSjohnjiang 4784418919fSjohnjiang 4792bfe3f2eSlogwangdef scan_autoload_path(autoload_path): 4802bfe3f2eSlogwang global raw_output 4812bfe3f2eSlogwang 482*2d9fd380Sjfb8856606 if not os.path.exists(autoload_path): 4832bfe3f2eSlogwang return 4842bfe3f2eSlogwang 4852bfe3f2eSlogwang try: 4862bfe3f2eSlogwang dirs = os.listdir(autoload_path) 4872bfe3f2eSlogwang except OSError: 4882bfe3f2eSlogwang # Couldn't read the directory, give up 4892bfe3f2eSlogwang return 4902bfe3f2eSlogwang 4912bfe3f2eSlogwang for d in dirs: 4922bfe3f2eSlogwang dpath = os.path.join(autoload_path, d) 4932bfe3f2eSlogwang if os.path.isdir(dpath): 4942bfe3f2eSlogwang scan_autoload_path(dpath) 4952bfe3f2eSlogwang if os.path.isfile(dpath): 4962bfe3f2eSlogwang try: 497*2d9fd380Sjfb8856606 file = open(dpath, 'rb') 4982bfe3f2eSlogwang readelf = ReadElf(file, sys.stdout) 4992bfe3f2eSlogwang except ELFError: 5002bfe3f2eSlogwang # this is likely not an elf file, skip it 5012bfe3f2eSlogwang continue 5022bfe3f2eSlogwang except IOError: 5032bfe3f2eSlogwang # No permission to read the file, skip it 5042bfe3f2eSlogwang continue 5052bfe3f2eSlogwang 506*2d9fd380Sjfb8856606 if not raw_output: 5072bfe3f2eSlogwang print("Hw Support for library %s" % d) 5082bfe3f2eSlogwang readelf.display_pmd_info_strings(".rodata") 5092bfe3f2eSlogwang file.close() 5102bfe3f2eSlogwang 5112bfe3f2eSlogwang 5122bfe3f2eSlogwangdef scan_for_autoload_pmds(dpdk_path): 5132bfe3f2eSlogwang """ 5142bfe3f2eSlogwang search the specified application or path for a pmd autoload path 5152bfe3f2eSlogwang then scan said path for pmds and report hw support 5162bfe3f2eSlogwang """ 5172bfe3f2eSlogwang global raw_output 5182bfe3f2eSlogwang 519*2d9fd380Sjfb8856606 if not os.path.isfile(dpdk_path): 520*2d9fd380Sjfb8856606 if not raw_output: 5212bfe3f2eSlogwang print("Must specify a file name") 5222bfe3f2eSlogwang return 5232bfe3f2eSlogwang 524*2d9fd380Sjfb8856606 file = open(dpdk_path, 'rb') 5252bfe3f2eSlogwang try: 5262bfe3f2eSlogwang readelf = ReadElf(file, sys.stdout) 5272bfe3f2eSlogwang except ElfError: 528*2d9fd380Sjfb8856606 if not raw_output: 5292bfe3f2eSlogwang print("Unable to parse %s" % file) 5302bfe3f2eSlogwang return 5312bfe3f2eSlogwang 5322bfe3f2eSlogwang (autoload_path, scannedfile) = readelf.search_for_autoload_path() 5334418919fSjohnjiang if not autoload_path: 534*2d9fd380Sjfb8856606 if not raw_output: 5352bfe3f2eSlogwang print("No autoload path configured in %s" % dpdk_path) 5362bfe3f2eSlogwang return 537*2d9fd380Sjfb8856606 if not raw_output: 538*2d9fd380Sjfb8856606 if scannedfile is None: 5392bfe3f2eSlogwang scannedfile = dpdk_path 5402bfe3f2eSlogwang print("Found autoload path %s in %s" % (autoload_path, scannedfile)) 5412bfe3f2eSlogwang 5422bfe3f2eSlogwang file.close() 543*2d9fd380Sjfb8856606 if not raw_output: 5442bfe3f2eSlogwang print("Discovered Autoload HW Support:") 5452bfe3f2eSlogwang scan_autoload_path(autoload_path) 5462bfe3f2eSlogwang return 5472bfe3f2eSlogwang 5482bfe3f2eSlogwang 5492bfe3f2eSlogwangdef main(stream=None): 5502bfe3f2eSlogwang global raw_output 5512bfe3f2eSlogwang global pcidb 5522bfe3f2eSlogwang 5532bfe3f2eSlogwang pcifile_default = "./pci.ids" # For unknown OS's assume local file 5542bfe3f2eSlogwang if platform.system() == 'Linux': 5550c6bd470Sfengbojiang # hwdata is the legacy location, misc is supported going forward 5560c6bd470Sfengbojiang pcifile_default = "/usr/share/misc/pci.ids" 5570c6bd470Sfengbojiang if not os.path.exists(pcifile_default): 5582bfe3f2eSlogwang pcifile_default = "/usr/share/hwdata/pci.ids" 5592bfe3f2eSlogwang elif platform.system() == 'FreeBSD': 5602bfe3f2eSlogwang pcifile_default = "/usr/local/share/pciids/pci.ids" 5612bfe3f2eSlogwang if not os.path.exists(pcifile_default): 5622bfe3f2eSlogwang pcifile_default = "/usr/share/misc/pci_vendors" 5632bfe3f2eSlogwang 564*2d9fd380Sjfb8856606 parser = argparse.ArgumentParser( 565*2d9fd380Sjfb8856606 usage='usage: %(prog)s [-hrtp] [-d <pci id file>] elf_file', 566*2d9fd380Sjfb8856606 description="Dump pmd hardware support info") 567*2d9fd380Sjfb8856606 group = parser.add_mutually_exclusive_group() 568*2d9fd380Sjfb8856606 group.add_argument('-r', '--raw', 5692bfe3f2eSlogwang action='store_true', dest='raw_output', 570*2d9fd380Sjfb8856606 help='dump raw json strings') 571*2d9fd380Sjfb8856606 group.add_argument("-t", "--table", dest="tblout", 572*2d9fd380Sjfb8856606 help="output information on hw support as a hex table", 5732bfe3f2eSlogwang action='store_true') 574*2d9fd380Sjfb8856606 parser.add_argument("-d", "--pcidb", dest="pcifile", 575*2d9fd380Sjfb8856606 help="specify a pci database to get vendor names from", 576*2d9fd380Sjfb8856606 default=pcifile_default, metavar="FILE") 577*2d9fd380Sjfb8856606 parser.add_argument("-p", "--plugindir", dest="pdir", 5782bfe3f2eSlogwang help="scan dpdk for autoload plugins", 5792bfe3f2eSlogwang action='store_true') 580*2d9fd380Sjfb8856606 parser.add_argument("elf_file", help="driver shared object file") 581*2d9fd380Sjfb8856606 args = parser.parse_args() 5822bfe3f2eSlogwang 583*2d9fd380Sjfb8856606 if args.raw_output: 5842bfe3f2eSlogwang raw_output = True 5852bfe3f2eSlogwang 586*2d9fd380Sjfb8856606 if args.tblout: 587*2d9fd380Sjfb8856606 args.pcifile = None 588*2d9fd380Sjfb8856606 589*2d9fd380Sjfb8856606 if args.pcifile: 590*2d9fd380Sjfb8856606 pcidb = PCIIds(args.pcifile) 5912bfe3f2eSlogwang if pcidb is None: 5922bfe3f2eSlogwang print("Pci DB file not found") 5932bfe3f2eSlogwang exit(1) 5942bfe3f2eSlogwang 595*2d9fd380Sjfb8856606 if args.pdir: 5962bfe3f2eSlogwang exit(scan_for_autoload_pmds(args[0])) 5972bfe3f2eSlogwang 5982bfe3f2eSlogwang ldlibpath = os.environ.get('LD_LIBRARY_PATH') 599*2d9fd380Sjfb8856606 if ldlibpath is None: 6002bfe3f2eSlogwang ldlibpath = "" 6012bfe3f2eSlogwang 602*2d9fd380Sjfb8856606 if os.path.exists(args.elf_file): 603*2d9fd380Sjfb8856606 myelffile = args.elf_file 6042bfe3f2eSlogwang else: 605*2d9fd380Sjfb8856606 myelffile = search_file(args.elf_file, 606*2d9fd380Sjfb8856606 ldlibpath + ":/usr/lib64:/lib64:/usr/lib:/lib") 6072bfe3f2eSlogwang 608*2d9fd380Sjfb8856606 if myelffile is None: 6092bfe3f2eSlogwang print("File not found") 6102bfe3f2eSlogwang sys.exit(1) 6112bfe3f2eSlogwang 612*2d9fd380Sjfb8856606 with open(myelffile, 'rb') as file: 6132bfe3f2eSlogwang try: 6142bfe3f2eSlogwang readelf = ReadElf(file, sys.stdout) 6152bfe3f2eSlogwang readelf.process_dt_needed_entries() 6162bfe3f2eSlogwang readelf.display_pmd_info_strings(".rodata") 6172bfe3f2eSlogwang sys.exit(0) 6182bfe3f2eSlogwang 6192bfe3f2eSlogwang except ELFError as ex: 6202bfe3f2eSlogwang sys.stderr.write('ELF error: %s\n' % ex) 6212bfe3f2eSlogwang sys.exit(1) 6222bfe3f2eSlogwang 6232bfe3f2eSlogwang 6242bfe3f2eSlogwang# ------------------------------------------------------------------------- 6252bfe3f2eSlogwangif __name__ == '__main__': 6262bfe3f2eSlogwang main() 627