diff options
Diffstat (limited to 'scripts/checkstack.py')
-rwxr-xr-x | scripts/checkstack.py | 106 |
1 files changed, 64 insertions, 42 deletions
diff --git a/scripts/checkstack.py b/scripts/checkstack.py index 1a6605fe..6ae9c473 100755 --- a/scripts/checkstack.py +++ b/scripts/checkstack.py @@ -25,6 +25,7 @@ OUTPUTDESC = """ # insn_addr:called_function [u+c,t,usage_to_yield_point] """ + class function: def __init__(self, funcaddr, funcname): self.funcaddr = funcaddr @@ -37,10 +38,12 @@ class function: # called_funcs = [(insnaddr, calladdr, stackusage), ...] self.called_funcs = [] self.subfuncs = {} + # Update function info with a found "yield" point. def noteYield(self, stackusage): if self.yield_usage < stackusage: self.yield_usage = stackusage + # Update function info with a found "call" point. def noteCall(self, insnaddr, calladdr, stackusage): if (calladdr, stackusage) in self.subfuncs: @@ -49,6 +52,7 @@ class function: self.called_funcs.append((insnaddr, calladdr, stackusage)) self.subfuncs[(calladdr, stackusage)] = 1 + # Find out maximum stack usage for a function def calcmaxstack(info, funcs): if info.max_stack_usage is not None: @@ -66,7 +70,7 @@ def calcmaxstack(info, funcs): if callinfo.funcname not in seenbefore: seenbefore[callinfo.funcname] = 1 total_calls += callinfo.total_calls + 1 - funcnameroot = callinfo.funcname.split('.')[0] + funcnameroot = callinfo.funcname.split(".")[0] if funcnameroot in IGNORE: # This called function is ignored - don't contribute it to # the max stack. @@ -84,12 +88,15 @@ def calcmaxstack(info, funcs): info.max_yield_usage = max_yield_usage info.total_calls = total_calls + # Try to arrange output so that functions that call each other are # near each other. def orderfuncs(funcaddrs, availfuncs): - l = [(availfuncs[funcaddr].total_calls - , availfuncs[funcaddr].funcname, funcaddr) - for funcaddr in funcaddrs if funcaddr in availfuncs] + l = [ + (availfuncs[funcaddr].total_calls, availfuncs[funcaddr].funcname, funcaddr) + for funcaddr in funcaddrs + if funcaddr in availfuncs + ] l.sort() l.reverse() out = [] @@ -103,17 +110,22 @@ def orderfuncs(funcaddrs, availfuncs): out = out + orderfuncs(calladdrs, availfuncs) + [info] return out -hex_s = r'[0-9a-f]+' -re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$') + +hex_s = r"[0-9a-f]+" +re_func = re.compile(r"^(?P<funcaddr>" + hex_s + r") <(?P<func>.*)>:$") re_asm = re.compile( - r'^[ ]*(?P<insnaddr>' + hex_s - + r'):\t[^\t]*\t(?P<insn>[^\t]+?)(?P<params>\t[^;]*)?' - + r'[ ]*(; (?P<calladdr>0x' + hex_s - + r') <(?P<ref>.*)>)?$') + r"^[ ]*(?P<insnaddr>" + + hex_s + + r"):\t[^\t]*\t(?P<insn>[^\t]+?)(?P<params>\t[^;]*)?" + + r"[ ]*(; (?P<calladdr>0x" + + hex_s + + r") <(?P<ref>.*)>)?$" +) + def main(): unknownfunc = function(None, "<unknown>") - indirectfunc = function(-1, '<indirect>') + indirectfunc = function(-1, "<indirect>") unknownfunc.max_stack_usage = indirectfunc.max_stack_usage = 0 unknownfunc.max_yield_usage = indirectfunc.max_yield_usage = -1 funcs = {-1: indirectfunc} @@ -128,38 +140,38 @@ def main(): m = re_func.match(line) if m is not None: # Found function - funcaddr = int(m.group('funcaddr'), 16) - funcs[funcaddr] = cur = function(funcaddr, m.group('func')) + funcaddr = int(m.group("funcaddr"), 16) + funcs[funcaddr] = cur = function(funcaddr, m.group("func")) stackusage = 0 atstart = 1 continue m = re_asm.match(line) if m is None: datalines.setdefault(funcaddr, []).append(line) - #print("other", repr(line)) + # print("other", repr(line)) continue - insn = m.group('insn') + insn = m.group("insn") - if insn == 'push': + if insn == "push": stackusage += 1 continue - if insn == 'rcall' and m.group('params').strip() == '.+0': + if insn == "rcall" and m.group("params").strip() == ".+0": stackusage += 2 continue if atstart: - if insn in ['in', 'eor']: + if insn in ["in", "eor"]: continue cur.basic_stack_usage = stackusage atstart = 0 - insnaddr = m.group('insnaddr') - calladdr = m.group('calladdr') + insnaddr = m.group("insnaddr") + calladdr = m.group("calladdr") if calladdr is None: - if insn == 'ijmp': + if insn == "ijmp": # Indirect tail call cur.noteCall(insnaddr, -1, 0) - elif insn == 'icall': + elif insn == "icall": cur.noteCall(insnaddr, -1, stackusage + 2) else: # misc instruction @@ -167,17 +179,17 @@ def main(): else: # Jump or call insn calladdr = int(calladdr, 16) - ref = m.group('ref') - if '+' in ref: + ref = m.group("ref") + if "+" in ref: # Inter-function jump. continue - elif insn.startswith('ld') or insn.startswith('st'): + elif insn.startswith("ld") or insn.startswith("st"): # memory access continue - elif insn in ('rjmp', 'jmp', 'brne', 'brcs'): + elif insn in ("rjmp", "jmp", "brne", "brcs"): # Tail call cur.noteCall(insnaddr, calladdr, 0) - elif insn in ('rcall', 'call'): + elif insn in ("rcall", "call"): cur.noteCall(insnaddr, calladdr, stackusage + 2) else: print("unknown call", ref) @@ -188,29 +200,29 @@ def main(): # Update for known indirect functions funcsbyname = {} for info in funcs.values(): - funcnameroot = info.funcname.split('.')[0] + funcnameroot = info.funcname.split(".")[0] funcsbyname[funcnameroot] = info - cmdfunc = funcsbyname.get('sched_main') - command_index = funcsbyname.get('command_index') + cmdfunc = funcsbyname.get("sched_main") + command_index = funcsbyname.get("command_index") if command_index is not None and cmdfunc is not None: for line in datalines[command_index.funcaddr]: parts = line.split() if len(parts) < 9: continue - calladdr = int(parts[8]+parts[7], 16) * 2 + calladdr = int(parts[8] + parts[7], 16) * 2 numparams = int(parts[2], 16) stackusage = cmdfunc.basic_stack_usage + 2 + numparams * 4 cmdfunc.noteCall(0, calladdr, stackusage) if len(parts) < 17: continue - calladdr = int(parts[16]+parts[15], 16) * 2 + calladdr = int(parts[16] + parts[15], 16) * 2 numparams = int(parts[10], 16) stackusage = cmdfunc.basic_stack_usage + 2 + numparams * 4 cmdfunc.noteCall(0, calladdr, stackusage) - eventfunc = funcsbyname.get('__vector_13', funcsbyname.get('__vector_17')) + eventfunc = funcsbyname.get("__vector_13", funcsbyname.get("__vector_17")) for funcnameroot, info in funcsbyname.items(): - if funcnameroot.endswith('_event') and eventfunc is not None: - eventfunc.noteCall(0, info.funcaddr, eventfunc.basic_stack_usage+2) + if funcnameroot.endswith("_event") and eventfunc is not None: + eventfunc.noteCall(0, info.funcaddr, eventfunc.basic_stack_usage + 2) # Calculate maxstackusage for info in funcs.values(): @@ -227,17 +239,27 @@ def main(): yieldstr = "" if info.max_yield_usage >= 0: yieldstr = ",%d" % info.max_yield_usage - print("\n%s[%d,%d%s]:" % (info.funcname, info.basic_stack_usage - , info.max_stack_usage, yieldstr)) + print( + "\n%s[%d,%d%s]:" + % (info.funcname, info.basic_stack_usage, info.max_stack_usage, yieldstr) + ) for insnaddr, calladdr, stackusage in info.called_funcs: callinfo = funcs.get(calladdr, unknownfunc) yieldstr = "" if callinfo.max_yield_usage >= 0: yieldstr = ",%d" % (stackusage + callinfo.max_yield_usage) - print(" %04s:%-40s [%d+%d,%d%s]" % ( - insnaddr, callinfo.funcname, stackusage - , callinfo.basic_stack_usage - , stackusage+callinfo.max_stack_usage, yieldstr)) + print( + " %04s:%-40s [%d+%d,%d%s]" + % ( + insnaddr, + callinfo.funcname, + stackusage, + callinfo.basic_stack_usage, + stackusage + callinfo.max_stack_usage, + yieldstr, + ) + ) + -if __name__ == '__main__': +if __name__ == "__main__": main() |