|
|
1.1 ! root 1: #!/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 <[email protected]> ! 6: # ! 7: # This file may be distributed under the terms of the GNU GPLv3 license. ! 8: ! 9: # Usage: ! 10: # objdump -m i386 -M i8086 -M suffix -d out/rom16.reloc.o | tools/checkstack.py ! 11: ! 12: import sys ! 13: import re ! 14: ! 15: # List of functions we can assume are never called. ! 16: #IGNORE = ['panic', '__dprintf', '__send_disk_op'] ! 17: IGNORE = ['panic', '__send_disk_op'] ! 18: ! 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. ! 23: 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] ! 34: if totusage > max: ! 35: max = totusage ! 36: info[2] = max ! 37: ! 38: hex_s = r'[0-9a-f]+' ! 39: re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$') ! 40: re_asm = re.compile( ! 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)$') ! 46: ! 47: def calc(): ! 48: # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage ! 49: # , [(addr, callfname, stackusage), ...]] ! 50: funcs = {-1: ['<indirect>', 0, 0, []]} ! 51: 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 ! 60: funcaddr = int(m.group('funcaddr'), 16) ! 61: funcs[funcaddr] = cur = [m.group('func'), 0, None, []] ! 62: stackusage = 0 ! 63: atstart = 1 ! 64: subfuncs = {} ! 65: 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: ! 72: if insn[:5] == 'pushl' or insn[:6] == 'pushfl': ! 73: stackusage += 4 ! 74: continue ! 75: elif insn[:5] == 'pushw' or insn[:6] == 'pushfw': ! 76: stackusage += 2 ! 77: continue ! 78: stackusage += int(im.group('num'), 16) ! 79: ! 80: if atstart: ! 81: if insn == 'movl %esp,%ebp': ! 82: # Still part of initial header ! 83: continue ! 84: cur[1] = stackusage ! 85: atstart = 0 ! 86: ! 87: calladdr = m.group('calladdr') ! 88: if calladdr is None: ! 89: if insn[:6] == 'lcallw': ! 90: stackusage += 4 ! 91: calladdr = -1 ! 92: else: ! 93: # misc instruction - just ignore ! 94: continue ! 95: else: ! 96: # Jump or call insn ! 97: calladdr = int(calladdr, 16) ! 98: ref = m.group('ref') ! 99: if '+' in ref: ! 100: # Inter-function jump - reset stack usage to ! 101: # preamble usage ! 102: stackusage = cur[1] ! 103: continue ! 104: if insn[:1] == 'j': ! 105: # Tail call ! 106: stackusage = 0 ! 107: elif insn[:5] == 'calll': ! 108: stackusage += 4 ! 109: else: ! 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 ! 115: stackusage = cur[1] ! 116: ! 117: continue ! 118: ! 119: #print "other", repr(line) ! 120: ! 121: # Calculate maxstackusage ! 122: bynames = {} ! 123: for funcaddr, info in funcs.items(): ! 124: bynames[info[0]] = info ! 125: if info[2] is not None: ! 126: continue ! 127: calcmaxstack(funcs, funcaddr) ! 128: ! 129: # Show all functions ! 130: funcnames = bynames.keys() ! 131: funcnames.sort() ! 132: for funcname in funcnames: ! 133: name, basicusage, maxusage, calls = bynames[funcname] ! 134: if maxusage == 0: ! 135: continue ! 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]) ! 142: ! 143: def main(): ! 144: calc() ! 145: ! 146: if __name__ == '__main__': ! 147: main()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.