Annotation of qemu/roms/seabios/tools/checkstack.py, revision 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.