blob: 82becdd3a09beea03e7466fc1613723a161ab79b [file] [log] [blame]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -04001#!/usr/bin/env python
2# Script that tries to find how much stack space each function in an
3# object is using.
4#
5# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
6#
7# This file may be distributed under the terms of the GNU GPLv3 license.
8
9# Usage:
Kevin O'Connor7173f6f2009-05-27 22:23:33 -040010# objdump -m i386 -M i8086 -M suffix -d out/rom16.reloc.o | tools/checkstack.py
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040011
12import sys
13import re
14
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040015# List of functions we can assume are never called.
Kevin O'Connore07e18e2009-02-08 17:07:29 -050016#IGNORE = ['panic', '__dprintf', '__send_disk_op']
17IGNORE = ['panic', '__send_disk_op']
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040018
19# Find out maximum stack usage for a function
Kevin O'Connor95cde272008-07-13 10:59:11 -040020def calcmaxstack(funcs, funcaddr):
21 info = funcs[funcaddr]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040022 # Find max of all nested calls.
Kevin O'Connor95cde272008-07-13 10:59:11 -040023 max = info[1]
24 info[2] = max
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
31 # the max stack.
32 continue
33 totusage = usage + callinfo[2]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040034 if totusage > max:
35 max = totusage
Kevin O'Connor95cde272008-07-13 10:59:11 -040036 info[2] = max
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040037
38hex_s = r'[0-9a-f]+'
Kevin O'Connor95cde272008-07-13 10:59:11 -040039re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040040re_asm = re.compile(
Kevin O'Connor95cde272008-07-13 10:59:11 -040041 r'^[ ]*(?P<insnaddr>' + hex_s
42 + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
43 + r') <(?P<ref>.*)>)?$')
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040044re_usestack = re.compile(
Kevin O'Connor0b04b782009-06-10 21:40:26 -040045 r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040046
47def calc():
Kevin O'Connor95cde272008-07-13 10:59:11 -040048 # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
49 # , [(addr, callfname, stackusage), ...]]
50 funcs = {-1: ['<indirect>', 0, 0, []]}
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040051 cur = None
52 atstart = 0
53 stackusage = 0
54
55 # Parse input lines
56 for line in sys.stdin.readlines():
57 m = re_func.match(line)
58 if m is not None:
59 # Found function
Kevin O'Connor95cde272008-07-13 10:59:11 -040060 funcaddr = int(m.group('funcaddr'), 16)
61 funcs[funcaddr] = cur = [m.group('func'), 0, None, []]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040062 stackusage = 0
63 atstart = 1
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040064 subfuncs = {}
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040065 continue
66 m = re_asm.match(line)
67 if m is not None:
68 insn = m.group('insn')
69
70 im = re_usestack.match(insn)
71 if im is not None:
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040072 if insn[:5] == 'pushl' or insn[:6] == 'pushfl':
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040073 stackusage += 4
74 continue
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040075 elif insn[:5] == 'pushw' or insn[:6] == 'pushfw':
76 stackusage += 2
77 continue
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040078 stackusage += int(im.group('num'), 16)
79
80 if atstart:
Kevin O'Connordbbb7cf2009-08-09 13:10:47 -040081 if insn == 'movl %esp,%ebp':
82 # Still part of initial header
83 continue
Kevin O'Connor95cde272008-07-13 10:59:11 -040084 cur[1] = stackusage
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -040085 atstart = 0
86
Kevin O'Connor95cde272008-07-13 10:59:11 -040087 calladdr = m.group('calladdr')
88 if calladdr is None:
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040089 if insn[:6] == 'lcallw':
90 stackusage += 4
Kevin O'Connor95cde272008-07-13 10:59:11 -040091 calladdr = -1
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040092 else:
93 # misc instruction - just ignore
94 continue
95 else:
96 # Jump or call insn
Kevin O'Connor95cde272008-07-13 10:59:11 -040097 calladdr = int(calladdr, 16)
98 ref = m.group('ref')
Kevin O'Connorf5cb0792008-06-07 10:11:36 -040099 if '+' in ref:
100 # Inter-function jump - reset stack usage to
101 # preamble usage
Kevin O'Connor95cde272008-07-13 10:59:11 -0400102 stackusage = cur[1]
Kevin O'Connorf5cb0792008-06-07 10:11:36 -0400103 continue
Kevin O'Connor95cde272008-07-13 10:59:11 -0400104 if insn[:1] == 'j':
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400105 # Tail call
106 stackusage = 0
Kevin O'Connorf5cb0792008-06-07 10:11:36 -0400107 elif insn[:5] == 'calll':
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400108 stackusage += 4
109 else:
110 print "unknown call", ref
Kevin O'Connor95cde272008-07-13 10:59:11 -0400111 if (calladdr, stackusage) not in subfuncs:
112 cur[3].append((m.group('insnaddr'), calladdr, stackusage))
113 subfuncs[(calladdr, stackusage)] = 1
Kevin O'Connorf5cb0792008-06-07 10:11:36 -0400114 # Reset stack usage to preamble usage
Kevin O'Connor95cde272008-07-13 10:59:11 -0400115 stackusage = cur[1]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400116
117 continue
118
119 #print "other", repr(line)
120
121 # Calculate maxstackusage
Kevin O'Connor95cde272008-07-13 10:59:11 -0400122 bynames = {}
123 for funcaddr, info in funcs.items():
124 bynames[info[0]] = info
125 if info[2] is not None:
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400126 continue
Kevin O'Connor95cde272008-07-13 10:59:11 -0400127 calcmaxstack(funcs, funcaddr)
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400128
129 # Show all functions
Kevin O'Connor95cde272008-07-13 10:59:11 -0400130 funcnames = bynames.keys()
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400131 funcnames.sort()
Kevin O'Connor95cde272008-07-13 10:59:11 -0400132 for funcname in funcnames:
133 name, basicusage, maxusage, calls = bynames[funcname]
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400134 if maxusage == 0:
135 continue
Kevin O'Connor95cde272008-07-13 10:59:11 -0400136 print "\n%s[%d,%d]:" % (funcname, basicusage, maxusage)
137 for insnaddr, calladdr, stackusage in calls:
138 callinfo = funcs[calladdr]
Kevin O'Connorf5cb0792008-06-07 10:11:36 -0400139 print " %04s:%-40s [%d+%d,%d]" % (
Kevin O'Connor95cde272008-07-13 10:59:11 -0400140 insnaddr, callinfo[0], stackusage, callinfo[1]
141 , stackusage+callinfo[2])
Kevin O'Connor5c4a8c62008-05-12 23:50:16 -0400142
143def main():
144 calc()
145
146if __name__ == '__main__':
147 main()