summaryrefslogtreecommitdiffstats
path: root/python/xrelfo.py
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2022-10-28 11:59:41 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2022-10-28 12:01:22 +0200
commit00f0c39903653772d72c9c0adce661508138c0b0 (patch)
treea5d3c0536c2edf4bb8ae314b7ae07bfc223597d8 /python/xrelfo.py
parentbuild: exclude a few more things from frr.xref (diff)
downloadfrr-00f0c39903653772d72c9c0adce661508138c0b0.tar.xz
frr-00f0c39903653772d72c9c0adce661508138c0b0.zip
python: apply black formatting
The python/ directory hasn't been shoved into black yet (unlike topotests, where most FRR python code is.) Run black over it. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'python/xrelfo.py')
-rw-r--r--python/xrelfo.py327
1 files changed, 208 insertions, 119 deletions
diff --git a/python/xrelfo.py b/python/xrelfo.py
index 739becd8a..966ccdee9 100644
--- a/python/xrelfo.py
+++ b/python/xrelfo.py
@@ -40,13 +40,15 @@ from tiabwarfo import FieldApplicator
from xref2vtysh import CommandEntry
try:
- with open(os.path.join(frr_top_src, 'python', 'xrefstructs.json'), 'r') as fd:
+ with open(os.path.join(frr_top_src, "python", "xrefstructs.json"), "r") as fd:
xrefstructs = json.load(fd)
except FileNotFoundError:
- sys.stderr.write('''
+ sys.stderr.write(
+ """
The "xrefstructs.json" file (created by running tiabwarfo.py with the pahole
tool available) could not be found. It should be included with the sources.
-''')
+"""
+ )
sys.exit(1)
# constants, need to be kept in sync manually...
@@ -58,7 +60,7 @@ XREFT_INSTALL_ELEMENT = 0x301
# LOG_*
priovals = {}
-prios = ['0', '1', '2', 'E', 'W', 'N', 'I', 'D']
+prios = ["0", "1", "2", "E", "W", "N", "I", "D"]
class XrelfoJson(object):
@@ -71,9 +73,10 @@ class XrelfoJson(object):
def to_dict(self, refs):
pass
+
class Xref(ELFDissectStruct, XrelfoJson):
- struct = 'xref'
- fieldrename = {'type': 'typ'}
+ struct = "xref"
+ fieldrename = {"type": "typ"}
containers = {}
def __init__(self, *args, **kwargs):
@@ -86,7 +89,7 @@ class Xref(ELFDissectStruct, XrelfoJson):
def container(self):
if self._container is None:
if self.typ in self.containers:
- self._container = self.container_of(self.containers[self.typ], 'xref')
+ self._container = self.container_of(self.containers[self.typ], "xref")
return self._container
def check(self, *args, **kwargs):
@@ -95,10 +98,10 @@ class Xref(ELFDissectStruct, XrelfoJson):
class Xrefdata(ELFDissectStruct):
- struct = 'xrefdata'
+ struct = "xrefdata"
# uid is all zeroes in the data loaded from ELF
- fieldrename = {'uid': '_uid'}
+ fieldrename = {"uid": "_uid"}
def ref_from(self, xref, typ):
self.xref = xref
@@ -109,38 +112,83 @@ class Xrefdata(ELFDissectStruct):
return None
return uidhash(self.xref.file, self.hashstr, self.hashu32_0, self.hashu32_1)
+
class XrefPtr(ELFDissectStruct):
fields = [
- ('xref', 'P', Xref),
+ ("xref", "P", Xref),
]
+
class XrefThreadSched(ELFDissectStruct, XrelfoJson):
- struct = 'xref_threadsched'
+ struct = "xref_threadsched"
+
+
Xref.containers[XREFT_THREADSCHED] = XrefThreadSched
+
class XrefLogmsg(ELFDissectStruct, XrelfoJson):
- struct = 'xref_logmsg'
+ struct = "xref_logmsg"
def _warn_fmt(self, text):
- lines = text.split('\n')
- yield ((self.xref.file, self.xref.line), '%s:%d: %s (in %s())%s\n' % (self.xref.file, self.xref.line, lines[0], self.xref.func, ''.join(['\n' + l for l in lines[1:]])))
+ lines = text.split("\n")
+ yield (
+ (self.xref.file, self.xref.line),
+ "%s:%d: %s (in %s())%s\n"
+ % (
+ self.xref.file,
+ self.xref.line,
+ lines[0],
+ self.xref.func,
+ "".join(["\n" + l for l in lines[1:]]),
+ ),
+ )
fmt_regexes = [
- (re.compile(r'([\n\t]+)'), 'error: log message contains tab or newline'),
- # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'),
- (re.compile(r'^((?:warn(?:ing)?|error):\s*)', re.I), 'warning: log message starts with severity'),
+ (re.compile(r"([\n\t]+)"), "error: log message contains tab or newline"),
+ # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'),
+ (
+ re.compile(r"^((?:warn(?:ing)?|error):\s*)", re.I),
+ "warning: log message starts with severity",
+ ),
]
arg_regexes = [
- # the (?<![\?:] ) avoids warning for x ? inet_ntop(...) : "(bla)"
- (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET|2)\s*,)'), 'cleanup: replace inet_ntop(AF_INET, ...) with %pI4', lambda s: True),
- (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET6|10)\s*,)'), 'cleanup: replace inet_ntop(AF_INET6, ...) with %pI6', lambda s: True),
- (re.compile(r'((?<![\?:] )inet_ntoa)'), 'cleanup: replace inet_ntoa(...) with %pI4', lambda s: True),
- (re.compile(r'((?<![\?:] )ipaddr2str)'), 'cleanup: replace ipaddr2str(...) with %pIA', lambda s: True),
- (re.compile(r'((?<![\?:] )prefix2str)'), 'cleanup: replace prefix2str(...) with %pFX', lambda s: True),
- (re.compile(r'((?<![\?:] )prefix_mac2str)'), 'cleanup: replace prefix_mac2str(...) with %pEA', lambda s: True),
- (re.compile(r'((?<![\?:] )sockunion2str)'), 'cleanup: replace sockunion2str(...) with %pSU', lambda s: True),
-
- # (re.compile(r'^(\s*__(?:func|FUNCTION|PRETTY_FUNCTION)__\s*)'), 'error: debug message starts with __func__', lambda s: (s.priority & 7 == 7) ),
+ # the (?<![\?:] ) avoids warning for x ? inet_ntop(...) : "(bla)"
+ (
+ re.compile(r"((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET|2)\s*,)"),
+ "cleanup: replace inet_ntop(AF_INET, ...) with %pI4",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET6|10)\s*,)"),
+ "cleanup: replace inet_ntop(AF_INET6, ...) with %pI6",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )inet_ntoa)"),
+ "cleanup: replace inet_ntoa(...) with %pI4",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )ipaddr2str)"),
+ "cleanup: replace ipaddr2str(...) with %pIA",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )prefix2str)"),
+ "cleanup: replace prefix2str(...) with %pFX",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )prefix_mac2str)"),
+ "cleanup: replace prefix_mac2str(...) with %pEA",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )sockunion2str)"),
+ "cleanup: replace sockunion2str(...) with %pSU",
+ lambda s: True,
+ ),
+ # (re.compile(r'^(\s*__(?:func|FUNCTION|PRETTY_FUNCTION)__\s*)'), 'error: debug message starts with __func__', lambda s: (s.priority & 7 == 7) ),
]
def check(self, wopt):
@@ -150,11 +198,11 @@ class XrefLogmsg(ELFDissectStruct, XrelfoJson):
out = []
for i, text in enumerate(items):
if (i % 2) == 1:
- out.append('\033[41;37;1m%s\033[m' % repr(text)[1:-1])
+ out.append("\033[41;37;1m%s\033[m" % repr(text)[1:-1])
else:
out.append(repr(text)[1:-1])
- excerpt = ''.join(out)
+ excerpt = "".join(out)
else:
excerpt = repr(itext)[1:-1]
return excerpt
@@ -175,70 +223,99 @@ class XrefLogmsg(ELFDissectStruct, XrelfoJson):
continue
excerpt = fmt_msg(rex, self.args)
- yield from self._warn_fmt('%s:\n\t"%s",\n\t%s' % (msg, repr(self.fmtstring)[1:-1], excerpt))
+ yield from self._warn_fmt(
+ '%s:\n\t"%s",\n\t%s' % (msg, repr(self.fmtstring)[1:-1], excerpt)
+ )
def dump(self):
- print('%-60s %s%s %-25s [EC %d] %s' % (
- '%s:%d %s()' % (self.xref.file, self.xref.line, self.xref.func),
- prios[self.priority & 7],
- priovals.get(self.priority & 0x30, ' '),
- self.xref.xrefdata.uid, self.ec, self.fmtstring))
+ print(
+ "%-60s %s%s %-25s [EC %d] %s"
+ % (
+ "%s:%d %s()" % (self.xref.file, self.xref.line, self.xref.func),
+ prios[self.priority & 7],
+ priovals.get(self.priority & 0x30, " "),
+ self.xref.xrefdata.uid,
+ self.ec,
+ self.fmtstring,
+ )
+ )
def to_dict(self, xrelfo):
- jsobj = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']])
+ jsobj = dict([(i, getattr(self.xref, i)) for i in ["file", "line", "func"]])
if self.ec != 0:
- jsobj['ec'] = self.ec
- jsobj['fmtstring'] = self.fmtstring
- jsobj['args'] = self.args
- jsobj['priority'] = self.priority & 7
- jsobj['type'] = 'logmsg'
- jsobj['binary'] = self._elfsect._elfwrap.orig_filename
+ jsobj["ec"] = self.ec
+ jsobj["fmtstring"] = self.fmtstring
+ jsobj["args"] = self.args
+ jsobj["priority"] = self.priority & 7
+ jsobj["type"] = "logmsg"
+ jsobj["binary"] = self._elfsect._elfwrap.orig_filename
if self.priority & 0x10:
- jsobj.setdefault('flags', []).append('errno')
+ jsobj.setdefault("flags", []).append("errno")
if self.priority & 0x20:
- jsobj.setdefault('flags', []).append('getaddrinfo')
+ jsobj.setdefault("flags", []).append("getaddrinfo")
+
+ xrelfo["refs"].setdefault(self.xref.xrefdata.uid, []).append(jsobj)
- xrelfo['refs'].setdefault(self.xref.xrefdata.uid, []).append(jsobj)
Xref.containers[XREFT_LOGMSG] = XrefLogmsg
+
class CmdElement(ELFDissectStruct, XrelfoJson):
- struct = 'cmd_element'
+ struct = "cmd_element"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def to_dict(self, xrelfo):
- jsobj = xrelfo['cli'].setdefault(self.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {})
-
- jsobj.update({
- 'string': self.string,
- 'doc': self.doc,
- })
+ jsobj = (
+ xrelfo["cli"]
+ .setdefault(self.name, {})
+ .setdefault(self._elfsect._elfwrap.orig_filename, {})
+ )
+
+ jsobj.update(
+ {
+ "string": self.string,
+ "doc": self.doc,
+ }
+ )
if self.attr:
- jsobj['attr'] = attr = self.attr
+ jsobj["attr"] = attr = self.attr
for attrname in CmdAttr.__members__:
val = CmdAttr[attrname]
if attr & val:
- jsobj.setdefault('attrs', []).append(attrname.lower())
+ jsobj.setdefault("attrs", []).append(attrname.lower())
attr &= ~val
- jsobj['defun'] = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']])
+ jsobj["defun"] = dict(
+ [(i, getattr(self.xref, i)) for i in ["file", "line", "func"]]
+ )
+
Xref.containers[XREFT_DEFUN] = CmdElement
+
class XrefInstallElement(ELFDissectStruct, XrelfoJson):
- struct = 'xref_install_element'
+ struct = "xref_install_element"
def to_dict(self, xrelfo):
- jsobj = xrelfo['cli'].setdefault(self.cmd_element.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {})
- nodes = jsobj.setdefault('nodes', [])
+ jsobj = (
+ xrelfo["cli"]
+ .setdefault(self.cmd_element.name, {})
+ .setdefault(self._elfsect._elfwrap.orig_filename, {})
+ )
+ nodes = jsobj.setdefault("nodes", [])
+
+ nodes.append(
+ {
+ "node": self.node_type,
+ "install": dict(
+ [(i, getattr(self.xref, i)) for i in ["file", "line", "func"]]
+ ),
+ }
+ )
- nodes.append({
- 'node': self.node_type,
- 'install': dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']]),
- })
Xref.containers[XREFT_INSTALL_ELEMENT] = XrefInstallElement
@@ -255,86 +332,90 @@ fieldapply()
class Xrelfo(dict):
def __init__(self):
- super().__init__({
- 'refs': {},
- 'cli': {},
- })
+ super().__init__(
+ {
+ "refs": {},
+ "cli": {},
+ }
+ )
self._xrefs = []
def load_file(self, filename):
orig_filename = filename
- if filename.endswith('.la') or filename.endswith('.lo'):
- with open(filename, 'r') as fd:
+ if filename.endswith(".la") or filename.endswith(".lo"):
+ with open(filename, "r") as fd:
for line in fd:
line = line.strip()
- if line.startswith('#') or line == '' or '=' not in line:
+ if line.startswith("#") or line == "" or "=" not in line:
continue
- var, val = line.split('=', 1)
- if var not in ['library_names', 'pic_object']:
+ var, val = line.split("=", 1)
+ if var not in ["library_names", "pic_object"]:
continue
if val.startswith("'") or val.startswith('"'):
val = val[1:-1]
- if var == 'pic_object':
+ if var == "pic_object":
filename = os.path.join(os.path.dirname(filename), val)
break
val = val.strip().split()[0]
- filename = os.path.join(os.path.dirname(filename), '.libs', val)
+ filename = os.path.join(os.path.dirname(filename), ".libs", val)
break
else:
- raise ValueError('could not process libtool file "%s"' % orig_filename)
+ raise ValueError(
+ 'could not process libtool file "%s"' % orig_filename
+ )
while True:
- with open(filename, 'rb') as fd:
+ with open(filename, "rb") as fd:
hdr = fd.read(4)
- if hdr == b'\x7fELF':
+ if hdr == b"\x7fELF":
self.load_elf(filename, orig_filename)
return
- if hdr[:2] == b'#!':
+ if hdr[:2] == b"#!":
path, name = os.path.split(filename)
- filename = os.path.join(path, '.libs', name)
+ filename = os.path.join(path, ".libs", name)
continue
- if hdr[:1] == b'{':
- with open(filename, 'r') as fd:
+ if hdr[:1] == b"{":
+ with open(filename, "r") as fd:
self.load_json(fd)
return
- raise ValueError('cannot determine file type for %s' % (filename))
+ raise ValueError("cannot determine file type for %s" % (filename))
def load_elf(self, filename, orig_filename):
edf = ELFDissectFile(filename)
edf.orig_filename = orig_filename
- note = edf._elffile.find_note('FRRouting', 'XREF')
+ note = edf._elffile.find_note("FRRouting", "XREF")
if note is not None:
- endian = '>' if edf._elffile.bigendian else '<'
+ endian = ">" if edf._elffile.bigendian else "<"
mem = edf._elffile[note]
if edf._elffile.elfclass == 64:
- start, end = struct.unpack(endian + 'QQ', mem)
+ start, end = struct.unpack(endian + "QQ", mem)
start += note.start
end += note.start + 8
else:
- start, end = struct.unpack(endian + 'II', mem)
+ start, end = struct.unpack(endian + "II", mem)
start += note.start
end += note.start + 4
ptrs = edf.iter_data(XrefPtr, slice(start, end))
else:
- xrefarray = edf.get_section('xref_array')
+ xrefarray = edf.get_section("xref_array")
if xrefarray is None:
- raise ValueError('file has neither xref note nor xref_array section')
+ raise ValueError("file has neither xref note nor xref_array section")
ptrs = xrefarray.iter_data(XrefPtr)
for ptr in ptrs:
if ptr.xref is None:
- print('NULL xref')
+ print("NULL xref")
continue
self._xrefs.append(ptr.xref)
@@ -347,15 +428,15 @@ class Xrelfo(dict):
def load_json(self, fd):
data = json.load(fd)
- for uid, items in data['refs'].items():
- myitems = self['refs'].setdefault(uid, [])
+ for uid, items in data["refs"].items():
+ myitems = self["refs"].setdefault(uid, [])
for item in items:
if item in myitems:
continue
myitems.append(item)
- for cmd, items in data['cli'].items():
- self['cli'].setdefault(cmd, {}).update(items)
+ for cmd, items in data["cli"].items():
+ self["cli"].setdefault(cmd, {}).update(items)
return data
@@ -363,24 +444,33 @@ class Xrelfo(dict):
for xref in self._xrefs:
yield from xref.check(checks)
+
def main():
- argp = argparse.ArgumentParser(description = 'FRR xref ELF extractor')
- argp.add_argument('-o', dest='output', type=str, help='write JSON output')
- argp.add_argument('--out-by-file', type=str, help='write by-file JSON output')
- argp.add_argument('-c', dest='vtysh_cmds', type=str, help='write vtysh_cmd.c')
- argp.add_argument('-Wlog-format', action='store_const', const=True)
- argp.add_argument('-Wlog-args', action='store_const', const=True)
- argp.add_argument('-Werror', action='store_const', const=True)
- argp.add_argument('--profile', action='store_const', const=True)
- argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)')
+ argp = argparse.ArgumentParser(description="FRR xref ELF extractor")
+ argp.add_argument("-o", dest="output", type=str, help="write JSON output")
+ argp.add_argument("--out-by-file", type=str, help="write by-file JSON output")
+ argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c")
+ argp.add_argument("-Wlog-format", action="store_const", const=True)
+ argp.add_argument("-Wlog-args", action="store_const", const=True)
+ argp.add_argument("-Werror", action="store_const", const=True)
+ argp.add_argument("--profile", action="store_const", const=True)
+ argp.add_argument(
+ "binaries",
+ metavar="BINARY",
+ nargs="+",
+ type=str,
+ help="files to read (ELF files or libtool objects)",
+ )
args = argp.parse_args()
if args.profile:
import cProfile
- cProfile.runctx('_main(args)', globals(), {'args': args}, sort='cumtime')
+
+ cProfile.runctx("_main(args)", globals(), {"args": args}, sort="cumtime")
else:
_main(args)
+
def _main(args):
errors = 0
xrelfo = Xrelfo()
@@ -390,60 +480,59 @@ def _main(args):
xrelfo.load_file(fn)
except:
errors += 1
- sys.stderr.write('while processing %s:\n' % (fn))
+ sys.stderr.write("while processing %s:\n" % (fn))
traceback.print_exc()
for option in dir(args):
- if option.startswith('W') and option != 'Werror':
+ if option.startswith("W") and option != "Werror":
checks = sorted(xrelfo.check(args))
- sys.stderr.write(''.join([c[-1] for c in checks]))
+ sys.stderr.write("".join([c[-1] for c in checks]))
if args.Werror and len(checks) > 0:
errors += 1
break
-
- refs = xrelfo['refs']
+ refs = xrelfo["refs"]
counts = {}
for k, v in refs.items():
- strs = set([i['fmtstring'] for i in v])
+ strs = set([i["fmtstring"] for i in v])
if len(strs) != 1:
- print('\033[31;1m%s\033[m' % k)
+ print("\033[31;1m%s\033[m" % k)
counts[k] = len(v)
out = xrelfo
outbyfile = {}
for uid, locs in refs.items():
for loc in locs:
- filearray = outbyfile.setdefault(loc['file'], [])
+ filearray = outbyfile.setdefault(loc["file"], [])
loc = dict(loc)
- del loc['file']
+ del loc["file"]
filearray.append(loc)
for k in outbyfile.keys():
- outbyfile[k] = sorted(outbyfile[k], key=lambda x: x['line'])
+ outbyfile[k] = sorted(outbyfile[k], key=lambda x: x["line"])
if errors:
sys.exit(1)
if args.output:
- with open(args.output + '.tmp', 'w') as fd:
+ with open(args.output + ".tmp", "w") as fd:
json.dump(out, fd, indent=2, sort_keys=True, **json_dump_args)
- os.rename(args.output + '.tmp', args.output)
+ os.rename(args.output + ".tmp", args.output)
if args.out_by_file:
- with open(args.out_by_file + '.tmp', 'w') as fd:
+ with open(args.out_by_file + ".tmp", "w") as fd:
json.dump(outbyfile, fd, indent=2, sort_keys=True, **json_dump_args)
- os.rename(args.out_by_file + '.tmp', args.out_by_file)
+ os.rename(args.out_by_file + ".tmp", args.out_by_file)
if args.vtysh_cmds:
- with open(args.vtysh_cmds + '.tmp', 'w') as fd:
+ with open(args.vtysh_cmds + ".tmp", "w") as fd:
CommandEntry.run(out, fd)
- os.rename(args.vtysh_cmds + '.tmp', args.vtysh_cmds)
+ os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds)
if args.Werror and CommandEntry.warn_counter:
sys.exit(1)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()