Annotation of qemu/roms/seabios/tools/checkstack.py, revision 1.1.1.1

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()

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.