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 # List of functions we can assume are never called.
16 #IGNORE = ['screenc', 'BX_PANIC', '__dprintf']
17 IGNORE = ['screenc', 'BX_PANIC']
19 # Find out maximum stack usage for a function
20 def calcmaxstack(funcs, func):
22 if func.split('.')[0] in IGNORE:
23 # Function is hardcoded to report 0 stack usage
26 # Find max of all nested calls.
29 for addr, callfname, usage in info[2]:
30 callinfo = funcs[callfname]
31 if callinfo[1] is None:
32 calcmaxstack(funcs, callfname)
33 totusage = usage + callinfo[1]
39 re_func = re.compile(r'^' + hex_s + r' <(?P<func>.*)>:$')
41 r'^[ ]*(?P<addr>' + hex_s + r'):\t.*\t'
42 r'(addr32 )?(?P<insn>[a-z0-9]+ [^<]*)( <(?P<ref>.*)>)?$')
43 re_usestack = re.compile(
44 r'^(push.*)|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
47 # funcs = {funcname: [basicstackusage, maxstackusage
48 # , [(addr, callfname, stackusage), ...]] }
49 funcs = {'<indirect>': [0, 0, []]}
55 for line in sys.stdin.readlines():
56 m = re_func.match(line)
60 funcs[m.group('func')] = cur
65 m = re_asm.match(line)
67 insn = m.group('insn')
69 im = re_usestack.match(insn)
71 if insn[:5] == 'pushl' or insn[:6] == 'pushfl':
74 elif insn[:5] == 'pushw' or insn[:6] == 'pushfw':
77 stackusage += int(im.group('num'), 16)
85 if insn[:6] == 'lcallw':
89 # misc instruction - just ignore
94 # Inter-function jump - reset stack usage to
98 if ref.split('.')[0] in IGNORE:
99 # Call ignored - list only for informational purposes
101 elif insn[:1] == 'j':
104 elif insn[:5] == 'calll':
107 print "unknown call", ref
108 if (ref, stackusage) not in subfuncs:
109 cur[2].append((m.group('addr'), ref, stackusage))
110 subfuncs[(ref, stackusage)] = 1
111 # Reset stack usage to preamble usage
116 #print "other", repr(line)
118 # Calculate maxstackusage
119 for func, info in funcs.items():
120 if info[1] is not None:
122 calcmaxstack(funcs, func)
125 funcnames = funcs.keys()
127 for func in funcnames:
128 basicusage, maxusage, calls = funcs[func]
131 print "\n%s[%d,%d]:" % (func, basicusage, maxusage)
132 for addr, callfname, stackusage in calls:
133 callinfo = funcs[callfname]
134 print " %04s:%-40s [%d+%d,%d]" % (
135 addr, callfname, stackusage, callinfo[0], stackusage+callinfo[1])
140 if __name__ == '__main__':