blob: ea3c6024b81a7f7b9249b12df6a678662d40b0f1 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright Microsoft and CHERIoT Contributors.
# SPDX-License-Identifier: MIT
import optparse, re, bisect, sys, subprocess
nm_re=re.compile('([0-9a-f]+) . (.+)')
trace_re=re.compile('(?P<pc>[0-9a-fA-F]{8})')
def usage(msg):
sys.stderr.write(msg + "\n")
sys.exit(1)
def get_names(options):
if options.exe_file:
p = subprocess.Popen(['nm','--demangle', options.exe_file],stdout=subprocess.PIPE,text=True)
nm_file = p.stdout
elif options.nm_file:
nm_file = open(options.nm_file, 'r')
else:
usage("Error: please provide either exe file or nm output.")
print("Parsing nm file...")
names=[]
for line in nm_file:
# line=str(line)
m=nm_re.match(line)
if not m:
sys.stderr.write(f"Warning: unrecognized line in nm file: {line}")
continue
names.append((int(m.group(1), 16), m.group(2)))
# Sort by address
names.sort(key=lambda x: x[0])
# Got the data, now merge duplicate symbols into one.
print("Removing duplicate symbols...")
unique_names=[]
prev_addr, prev_name=0, 'null'
for (addr, name) in names:
if addr != prev_addr:
unique_names.append((prev_addr, prev_name))
prev_name = name
prev_addr = addr
else:
prev_name = prev_name + '/' + name
unique_names.append((prev_addr, prev_name))
print("Loaded names.")
return unique_names
def annotate_trace(options):
names = get_names(options)
non_local_names = filter(lambda x: not x[1].startswith('.'), names)
(addresses, syms) = list(zip(*names))
(non_local_addresses, non_local_syms) = list(zip(*non_local_names))
if options.trace_file is None:
trace_file=sys.stdin
else:
trace_file=open(options.trace_file, 'r')
for line in trace_file:
m = trace_re.search(line)
if m:
addr=int(m.group('pc'), 16)
i = bisect.bisect_right(addresses, addr)-1
sym = syms[i]
i2 = bisect.bisect_right(non_local_addresses, addr) - 1
non_local_sym = non_local_syms[i2]
if non_local_sym != sym:
sym = f"{non_local_sym} / {sym}"
print(f"{line[:-1]:{options.width}s} | {sym}")
else:
print(line[:-1])
if __name__=="__main__":
parser = optparse.OptionParser("""%prog --exe <EXE> --trace <TRACE>
Simple script to annotate an instruction trace with function names.
Assumes the first 8 digit hex number in each input line is the program counter.""")
parser.add_option('-e','--exe', dest="exe_file", help="Elf file containing symbol names")
parser.add_option('-N','--nm', dest="nm_file", help="File containing output of nm (alternative to elf file)")
parser.add_option('-t','--trace', dest="trace_file", help="Trace file to annotate (default stdin)", default=None)
parser.add_option('-w','--width', help="Width to pad input lines to before annotating", type=int, default=70)
(opts, args) = parser.parse_args()
annotate_trace(opts)