diff options
author | whitespace <nobody@nobody> | 2020-10-07 23:22:26 +0200 |
---|---|---|
committer | Quentin Young <qlyoung@nvidia.com> | 2020-10-07 23:22:26 +0200 |
commit | 701a01920eee5431d2052aad92aefbdf50ac2139 (patch) | |
tree | 2bf2339327241f59593b9583b060ebb347db1cea /tools/symalyzer.py | |
parent | Merge pull request #7058 from Niral-Networks/niral_dev_vrf_ospf6 (diff) | |
download | frr-701a01920eee5431d2052aad92aefbdf50ac2139.tar.xz frr-701a01920eee5431d2052aad92aefbdf50ac2139.zip |
*: reformat python files
We are now using black.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
Diffstat (limited to 'tools/symalyzer.py')
-rwxr-xr-x | tools/symalyzer.py | 251 |
1 files changed, 157 insertions, 94 deletions
diff --git a/tools/symalyzer.py b/tools/symalyzer.py index cff21f9f9..ce0bfde0a 100755 --- a/tools/symalyzer.py +++ b/tools/symalyzer.py @@ -21,18 +21,40 @@ import sys, os, subprocess import re from collections import namedtuple -sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'python')) +sys.path.insert( + 0, + os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "python"), +) from makevars import MakeVars -SymRowBase = namedtuple('SymRow', ['target', 'object', 'name', 'address', 'klass', 'typ', 'size', 'line', 'section', 'loc']) +SymRowBase = namedtuple( + "SymRow", + [ + "target", + "object", + "name", + "address", + "klass", + "typ", + "size", + "line", + "section", + "loc", + ], +) + + class SymRow(SymRowBase): - ''' + """ wrapper around a line of `nm` output - ''' - lib_re = re.compile(r'/lib[^/]+\.(so|la)$') + """ + + lib_re = re.compile(r"/lib[^/]+\.(so|la)$") + def is_global(self): - return self.klass.isupper() or self.klass in 'uvw' + return self.klass.isupper() or self.klass in "uvw" + def scope(self): if self.lib_re.search(self.target) is None: return self.target @@ -40,28 +62,29 @@ class SymRow(SymRowBase): return None def is_export(self): - ''' + """ FRR-specific list of symbols which are considered "externally used" e.g. hooks are by design APIs for external use, same for qobj_t_* frr_inet_ntop is here because it's used through an ELF alias to "inet_ntop()" - ''' - if self.name in ['main', 'frr_inet_ntop', '_libfrr_version']: + """ + if self.name in ["main", "frr_inet_ntop", "_libfrr_version"]: return True - if self.name.startswith('_hook_'): + if self.name.startswith("_hook_"): return True - if self.name.startswith('qobj_t_'): + if self.name.startswith("qobj_t_"): return True return False + class Symbols(dict): - ''' + """ dict of all symbols in all libs & executables - ''' + """ - from_re = re.compile(r'^Symbols from (.*?):$') - lt_re = re.compile(r'^(.*/)([^/]+)\.l[oa]$') + from_re = re.compile(r"^Symbols from (.*?):$") + lt_re = re.compile(r"^(.*/)([^/]+)\.l[oa]$") def __init__(self): super().__init__() @@ -69,26 +92,35 @@ class Symbols(dict): class ReportSym(object): def __init__(self, sym): self.sym = sym + def __repr__(self): - return '<%-25s %-40s [%s]>' % (self.__class__.__name__ + ':', self.sym.name, self.sym.loc) + return "<%-25s %-40s [%s]>" % ( + self.__class__.__name__ + ":", + self.sym.name, + self.sym.loc, + ) + def __lt__(self, other): return self.sym.name.__lt__(other.sym.name) class ReportSymCouldBeStaticAlreadyLocal(ReportSym): - idshort = 'Z' - idlong = 'extrastatic' + idshort = "Z" + idlong = "extrastatic" title = "symbol is local to library, but only used in its source file (make static?)" + class ReportSymCouldBeStatic(ReportSym): - idshort = 'S' - idlong = 'static' + idshort = "S" + idlong = "static" title = "symbol is only used in its source file (make static?)" + class ReportSymCouldBeLibLocal(ReportSym): - idshort = 'L' - idlong = 'liblocal' + idshort = "L" + idlong = "liblocal" title = "symbol is only used inside of library" + class ReportSymModuleAPI(ReportSym): - idshort = 'A' - idlong = 'api' + idshort = "A" + idlong = "api" title = "symbol (in executable) is referenced externally from a module" class Symbol(object): @@ -100,31 +132,38 @@ class Symbols(dict): def process(self, row): scope = row.scope() - if row.section == '*UND*': + if row.section == "*UND*": self.refs.append(row) else: self.defs.setdefault(scope, []).append(row) def evaluate(self, out): - ''' + """ generate output report invoked after all object files have been read in, so it can look at inter-object-file relationships - ''' + """ if len(self.defs) == 0: out.extsyms.add(self.name) return for scopename, symdefs in self.defs.items(): - common_defs = [symdef for symdef in symdefs if symdef.section == '*COM*'] - proper_defs = [symdef for symdef in symdefs if symdef.section != '*COM*'] + common_defs = [ + symdef for symdef in symdefs if symdef.section == "*COM*" + ] + proper_defs = [ + symdef for symdef in symdefs if symdef.section != "*COM*" + ] if len(proper_defs) > 1: - print(self.name, ' DUPLICATE') - print('\tD: %s %s' % (scopename, '\n\t\t'.join([repr(s) for s in symdefs]))) + print(self.name, " DUPLICATE") + print( + "\tD: %s %s" + % (scopename, "\n\t\t".join([repr(s) for s in symdefs])) + ) for syms in self.refs: - print('\tR: %s' % (syms, )) + print("\tR: %s" % (syms,)) return if len(proper_defs): @@ -140,7 +179,9 @@ class Symbols(dict): if scopename is not None and len(self.refs) > 0: for ref in self.refs: - if ref.target != primary_def.target and ref.target.endswith('.la'): + if ref.target != primary_def.target and ref.target.endswith( + ".la" + ): outobj = out.report.setdefault(primary_def.object, []) outobj.append(out.ReportSymModuleAPI(primary_def)) break @@ -152,7 +193,9 @@ class Symbols(dict): if primary_def.visible: outobj.append(out.ReportSymCouldBeStatic(primary_def)) else: - outobj.append(out.ReportSymCouldBeStaticAlreadyLocal(primary_def)) + outobj.append( + out.ReportSymCouldBeStaticAlreadyLocal(primary_def) + ) continue if scopename is None and primary_def.visible: @@ -164,7 +207,6 @@ class Symbols(dict): outobj = out.report.setdefault(primary_def.object, []) outobj.append(out.ReportSymCouldBeLibLocal(primary_def)) - def evaluate(self): self.extsyms = set() self.report = {} @@ -177,14 +219,14 @@ class Symbols(dict): m = self.lt_re.match(fn) if m is None: return fn - return m.group(1) + '.libs/' + m.group(2) + '.o' + return m.group(1) + ".libs/" + m.group(2) + ".o" def libtooltargetmustdie(fn): m = self.lt_re.match(fn) if m is None: - a, b = fn.rsplit('/', 1) - return '%s/.libs/%s' % (a, b) - return m.group(1) + '.libs/' + m.group(2) + '.so' + a, b = fn.rsplit("/", 1) + return "%s/.libs/%s" % (a, b) + return m.group(1) + ".libs/" + m.group(2) + ".so" files = list(set([libtoolmustdie(fn) for fn in files])) @@ -192,30 +234,30 @@ class Symbols(dict): filename = None path_rel_to = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - for line in text.split('\n'): - if line.strip() == '': + for line in text.split("\n"): + if line.strip() == "": continue m = self.from_re.match(line) if m is not None: filename = m.group(1) continue - if line.startswith('Name'): + if line.startswith("Name"): continue - items = [i.strip() for i in line.split('|')] + items = [i.strip() for i in line.split("|")] loc = None - if '\t' in items[-1]: - items[-1], loc = items[-1].split('\t', 1) - fn, lno = loc.rsplit(':', 1) + if "\t" in items[-1]: + items[-1], loc = items[-1].split("\t", 1) + fn, lno = loc.rsplit(":", 1) fn = os.path.relpath(fn, path_rel_to) - loc = '%s:%s' % (fn, lno) + loc = "%s:%s" % (fn, lno) - items[1] = int(items[1] if items[1] != '' else '0', 16) - items[4] = int(items[4] if items[4] != '' else '0', 16) + items[1] = int(items[1] if items[1] != "" else "0", 16) + items[4] = int(items[4] if items[4] != "" else "0", 16) items.append(loc) row = SymRow(target, filename, *items) - if row.section == '.group' or row.name == '_GLOBAL_OFFSET_TABLE_': + if row.section == ".group" or row.name == "_GLOBAL_OFFSET_TABLE_": continue if not row.is_global(): continue @@ -230,14 +272,19 @@ class Symbols(dict): # in the linked result (this covers ELF "hidden"/"internal" linkage) libfile = libtooltargetmustdie(target) - nmlib = subprocess.Popen(['nm', '-l', '-g', '--defined-only', '-f', 'sysv', libfile], stdout = subprocess.PIPE) - out = nmlib.communicate()[0].decode('US-ASCII') + nmlib = subprocess.Popen( + ["nm", "-l", "-g", "--defined-only", "-f", "sysv", libfile], + stdout=subprocess.PIPE, + ) + out = nmlib.communicate()[0].decode("US-ASCII") for row in parse_nm_output(out): visible_syms.add(row.name) - nm = subprocess.Popen(['nm', '-l', '-f', 'sysv'] + files, stdout = subprocess.PIPE) - out = nm.communicate()[0].decode('US-ASCII') + nm = subprocess.Popen( + ["nm", "-l", "-f", "sysv"] + files, stdout=subprocess.PIPE + ) + out = nm.communicate()[0].decode("US-ASCII") for row in parse_nm_output(out): row.visible = row.name in visible_syms @@ -249,95 +296,111 @@ def write_html_report(syms): try: import jinja2 except ImportError: - sys.stderr.write('jinja2 could not be imported, not writing HTML report!\n') + sys.stderr.write("jinja2 could not be imported, not writing HTML report!\n") return self_path = os.path.dirname(os.path.abspath(__file__)) jenv = jinja2.Environment(loader=jinja2.FileSystemLoader(self_path)) - template = jenv.get_template('symalyzer.html') + template = jenv.get_template("symalyzer.html") dirgroups = {} for fn, reports in syms.report.items(): - dirname, filename = fn.replace('.libs/', '').rsplit('/', 1) + dirname, filename = fn.replace(".libs/", "").rsplit("/", 1) dirgroups.setdefault(dirname, {})[fn] = reports klasses = { - 'T': 'code / plain old regular function (Text)', - 'D': 'global variable, read-write, with nonzero initializer (Data)', - 'B': 'global variable, read-write, with zero initializer (BSS)', - 'C': 'global variable, read-write, with zero initializer (Common)', - 'R': 'global variable, read-only (Rodata)', + "T": "code / plain old regular function (Text)", + "D": "global variable, read-write, with nonzero initializer (Data)", + "B": "global variable, read-write, with zero initializer (BSS)", + "C": "global variable, read-write, with zero initializer (Common)", + "R": "global variable, read-only (Rodata)", } - with open('symalyzer_report.html.tmp', 'w') as fd: - fd.write(template.render(dirgroups = dirgroups, klasses = klasses)) - os.rename('symalyzer_report.html.tmp', 'symalyzer_report.html') + with open("symalyzer_report.html.tmp", "w") as fd: + fd.write(template.render(dirgroups=dirgroups, klasses=klasses)) + os.rename("symalyzer_report.html.tmp", "symalyzer_report.html") - if not os.path.exists('jquery-3.4.1.min.js'): - url = 'https://code.jquery.com/jquery-3.4.1.min.js' + if not os.path.exists("jquery-3.4.1.min.js"): + url = "https://code.jquery.com/jquery-3.4.1.min.js" sys.stderr.write( - 'trying to grab a copy of jquery from %s\nif this fails, please get it manually (the HTML output is done.)\n' % (url)) + "trying to grab a copy of jquery from %s\nif this fails, please get it manually (the HTML output is done.)\n" + % (url) + ) import requests - r = requests.get('https://code.jquery.com/jquery-3.4.1.min.js') + + r = requests.get("https://code.jquery.com/jquery-3.4.1.min.js") if r.status_code != 200: - sys.stderr.write('failed -- please download jquery-3.4.1.min.js and put it next to the HTML report\n') + sys.stderr.write( + "failed -- please download jquery-3.4.1.min.js and put it next to the HTML report\n" + ) else: - with open('jquery-3.4.1.min.js.tmp', 'w') as fd: + with open("jquery-3.4.1.min.js.tmp", "w") as fd: fd.write(r.text) - os.rename('jquery-3.4.1.min.js.tmp', 'jquery-3.4.1.min.js') - sys.stderr.write('done.\n') + os.rename("jquery-3.4.1.min.js.tmp", "jquery-3.4.1.min.js") + sys.stderr.write("done.\n") + def automake_escape(s): - return s.replace('.', '_').replace('/', '_') + return s.replace(".", "_").replace("/", "_") -if __name__ == '__main__': + +if __name__ == "__main__": mv = MakeVars() - if not (os.path.exists('config.version') and os.path.exists('lib/.libs/libfrr.so')): - sys.stderr.write('please execute this script in the root directory of an FRR build tree\n') - sys.stderr.write('./configure && make need to have completed successfully\n') + if not (os.path.exists("config.version") and os.path.exists("lib/.libs/libfrr.so")): + sys.stderr.write( + "please execute this script in the root directory of an FRR build tree\n" + ) + sys.stderr.write("./configure && make need to have completed successfully\n") sys.exit(1) - amtargets = ['bin_PROGRAMS', 'sbin_PROGRAMS', 'lib_LTLIBRARIES', 'module_LTLIBRARIES'] + amtargets = [ + "bin_PROGRAMS", + "sbin_PROGRAMS", + "lib_LTLIBRARIES", + "module_LTLIBRARIES", + ] targets = [] mv.getvars(amtargets) for amtarget in amtargets: - targets.extend([item for item in mv[amtarget].strip().split() if item != 'tools/ssd']) + targets.extend( + [item for item in mv[amtarget].strip().split() if item != "tools/ssd"] + ) - mv.getvars(['%s_LDADD' % automake_escape(t) for t in targets]) + mv.getvars(["%s_LDADD" % automake_escape(t) for t in targets]) ldobjs = targets[:] for t in targets: - ldadd = mv['%s_LDADD' % automake_escape(t)].strip().split() + ldadd = mv["%s_LDADD" % automake_escape(t)].strip().split() for item in ldadd: - if item.startswith('-'): + if item.startswith("-"): continue - if item.endswith('.a'): + if item.endswith(".a"): ldobjs.append(item) - mv.getvars(['%s_OBJECTS' % automake_escape(o) for o in ldobjs]) + mv.getvars(["%s_OBJECTS" % automake_escape(o) for o in ldobjs]) syms = Symbols() for t in targets: - objs = mv['%s_OBJECTS' % automake_escape(t)].strip().split() - ldadd = mv['%s_LDADD' % automake_escape(t)].strip().split() + objs = mv["%s_OBJECTS" % automake_escape(t)].strip().split() + ldadd = mv["%s_LDADD" % automake_escape(t)].strip().split() for item in ldadd: - if item.startswith('-'): + if item.startswith("-"): continue - if item.endswith('.a'): - objs.extend(mv['%s_OBJECTS' % automake_escape(item)].strip().split()) + if item.endswith(".a"): + objs.extend(mv["%s_OBJECTS" % automake_escape(item)].strip().split()) - sys.stderr.write('processing %s...\n' % t) + sys.stderr.write("processing %s...\n" % t) sys.stderr.flush() - #print(t, '\n\t', objs) + # print(t, '\n\t', objs) syms.load(t, objs) syms.evaluate() for obj, reports in sorted(syms.report.items()): - print('%s:' % obj) + print("%s:" % obj) for report in reports: - print('\t%r' % report) + print("\t%r" % report) write_html_report(syms) |