2 # Script that tries to find how much stack space each function in an
5 # Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
7 # This file may be distributed under the terms of the GNU GPLv3 license.
10 # objdump -m i386 -M i8086 -M suffix -d out/rom16.o | tools/checkstack.py
15 #IGNORE = ['screenc', 'bvprintf']
18 # Find out maximum stack usage for a function
19 def calcmaxstack(funcs, func):
21 if func.split('.')[0] in IGNORE:
22 # Function is hardcoded to report 0 stack usage
25 # Find max of all nested calls.
27 for addr, callfname, usage in info[2]:
28 callinfo = funcs[callfname]
29 if callinfo[1] is None:
30 calcmaxstack(funcs, callfname)
31 totusage = usage + callinfo[1]
37 re_func = re.compile(r'^' + hex_s + r' <(?P<func>.*)>:$')
39 r'^[ ]*(?P<addr>' + hex_s + r'):\t.*\t'
40 r'(?P<insn>[a-z0-9]+ [^<]*)( <(?P<ref>.*)>)?$')
41 re_usestack = re.compile(
42 r'^(push.*)|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
45 # funcs = {funcname: [basicstackusage, maxstackusage
46 # , [(addr, callfname, stackusage), ...]] }
53 for line in sys.stdin.readlines():
54 m = re_func.match(line)
58 funcs[m.group('func')] = cur
62 m = re_asm.match(line)
64 insn = m.group('insn')
66 im = re_usestack.match(insn)
68 if insn[:4] == 'push':
71 stackusage += int(im.group('num'), 16)
78 if ref is not None and '+' not in ref:
82 elif insn[:4] == 'call':
85 print "unknown call", ref
86 cur[2].append((m.group('addr'), ref, stackusage))
87 # Reset stack usage to preamble usage
92 #print "other", repr(line)
94 # Calculate maxstackusage
95 for func, info in funcs.items():
96 if info[1] is not None:
98 calcmaxstack(funcs, func)
101 funcnames = funcs.keys()
103 for func in funcnames:
104 basicusage, maxusage, calls = funcs[func]
107 print "\n%s[%d,%d]:" % (func, basicusage, maxusage)
108 for addr, callfname, stackusage in calls:
109 callinfo = funcs[callfname]
110 print " %04s:%-30s[%d+%d,%d]" % (
111 addr, callfname, stackusage, callinfo[0], stackusage+callinfo[1])
116 if __name__ == '__main__':