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.reloc.o | tools/checkstack.py
15 # List of functions we can assume are never called.
16 #IGNORE = ['panic', '__dprintf', '__send_disk_op']
17 IGNORE = ['panic', '__send_disk_op']
19 # Find out maximum stack usage for a function
20 def calcmaxstack(funcs, funcaddr):
21 info = funcs[funcaddr]
22 # Find max of all nested calls.
25 for insnaddr, calladdr, usage in info[3]:
26 callinfo = funcs[calladdr]
27 if callinfo[2] is None:
28 calcmaxstack(funcs, calladdr)
29 if callinfo[0].split('.')[0] in IGNORE:
30 # This called function is ignored - don't contribute it to
33 totusage = usage + callinfo[2]
39 re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
41 r'^[ ]*(?P<insnaddr>' + hex_s
42 + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
43 + r') <(?P<ref>.*)>)?$')
44 re_usestack = re.compile(
45 r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
48 # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
49 # , [(addr, callfname, stackusage), ...]]
50 funcs = {-1: ['<indirect>', 0, 0, []]}
56 for line in sys.stdin.readlines():
57 m = re_func.match(line)
60 funcaddr = int(m.group('funcaddr'), 16)
61 funcs[funcaddr] = cur = [m.group('func'), 0, None, []]
66 m = re_asm.match(line)
68 insn = m.group('insn')
70 im = re_usestack.match(insn)
72 if insn[:5] == 'pushl' or insn[:6] == 'pushfl':
75 elif insn[:5] == 'pushw' or insn[:6] == 'pushfw':
78 stackusage += int(im.group('num'), 16)
81 if insn == 'movl %esp,%ebp':
82 # Still part of initial header
87 calladdr = m.group('calladdr')
89 if insn[:6] == 'lcallw':
93 # misc instruction - just ignore
97 calladdr = int(calladdr, 16)
100 # Inter-function jump - reset stack usage to
107 elif insn[:5] == 'calll':
110 print "unknown call", ref
111 if (calladdr, stackusage) not in subfuncs:
112 cur[3].append((m.group('insnaddr'), calladdr, stackusage))
113 subfuncs[(calladdr, stackusage)] = 1
114 # Reset stack usage to preamble usage
119 #print "other", repr(line)
121 # Calculate maxstackusage
123 for funcaddr, info in funcs.items():
124 bynames[info[0]] = info
125 if info[2] is not None:
127 calcmaxstack(funcs, funcaddr)
130 funcnames = bynames.keys()
132 for funcname in funcnames:
133 name, basicusage, maxusage, calls = bynames[funcname]
136 print "\n%s[%d,%d]:" % (funcname, basicusage, maxusage)
137 for insnaddr, calladdr, stackusage in calls:
138 callinfo = funcs[calladdr]
139 print " %04s:%-40s [%d+%d,%d]" % (
140 insnaddr, callinfo[0], stackusage, callinfo[1]
141 , stackusage+callinfo[2])
146 if __name__ == '__main__':