Change checkstack.py tool - key functions by address instead of name.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 13 Jul 2008 14:59:11 +0000 (10:59 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 13 Jul 2008 14:59:11 +0000 (10:59 -0400)
Keying by address allows the tool to work even when multiple symbols
    have the same address.

tools/checkstack.py

index 84635005973b61502c9f579c80a9a8ef120e52a1..680c0335d2c3dbca81047a8ec6ffb51413f067d5 100755 (executable)
@@ -17,36 +17,37 @@ import re
 IGNORE = ['screenc', 'BX_PANIC']
 
 # Find out maximum stack usage for a function
-def calcmaxstack(funcs, func):
-    info = funcs[func]
-    if func.split('.')[0] in IGNORE:
-        # Function is hardcoded to report 0 stack usage
-        info[1] = 0
-        return
+def calcmaxstack(funcs, funcaddr):
+    info = funcs[funcaddr]
     # Find max of all nested calls.
-    max = info[0]
-    info[1] = max
-    for addr, callfname, usage in info[2]:
-        callinfo = funcs[callfname]
-        if callinfo[1] is None:
-            calcmaxstack(funcs, callfname)
-        totusage = usage + callinfo[1]
+    max = info[1]
+    info[2] = max
+    for insnaddr, calladdr, usage in info[3]:
+        callinfo = funcs[calladdr]
+        if callinfo[2] is None:
+            calcmaxstack(funcs, calladdr)
+        if callinfo[0].split('.')[0] in IGNORE:
+            # This called function is ignored - don't contribute it to
+            # the max stack.
+            continue
+        totusage = usage + callinfo[2]
         if totusage > max:
             max = totusage
-    info[1] = max
+    info[2] = max
 
 hex_s = r'[0-9a-f]+'
-re_func = re.compile(r'^' + hex_s + r' <(?P<func>.*)>:$')
+re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
 re_asm = re.compile(
-    r'^[ ]*(?P<addr>' + hex_s + r'):\t.*\t'
-    r'(addr32 )?(?P<insn>[a-z0-9]+ [^<]*)( <(?P<ref>.*)>)?$')
+    r'^[ ]*(?P<insnaddr>' + hex_s
+    + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
+    + r') <(?P<ref>.*)>)?$')
 re_usestack = re.compile(
     r'^(push.*)|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
 
 def calc():
-    # funcs = {funcname: [basicstackusage, maxstackusage
-    #                     , [(addr, callfname, stackusage), ...]] }
-    funcs = {'<indirect>': [0, 0, []]}
+    # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
+    #                    , [(addr, callfname, stackusage), ...]]
+    funcs = {-1: ['<indirect>', 0, 0, []]}
     cur = None
     atstart = 0
     stackusage = 0
@@ -56,8 +57,8 @@ def calc():
         m = re_func.match(line)
         if m is not None:
             # Found function
-            cur = [0, None, []]
-            funcs[m.group('func')] = cur
+            funcaddr = int(m.group('funcaddr'), 16)
+            funcs[funcaddr] = cur = [m.group('func'), 0, None, []]
             stackusage = 0
             atstart = 1
             subfuncs = {}
@@ -77,62 +78,64 @@ def calc():
                 stackusage += int(im.group('num'), 16)
 
             if atstart:
-                cur[0] = stackusage
+                cur[1] = stackusage
                 atstart = 0
 
-            ref = m.group('ref')
-            if ref is None:
+            calladdr = m.group('calladdr')
+            if calladdr is None:
                 if insn[:6] == 'lcallw':
                     stackusage += 4
-                    ref = '<indirect>'
+                    calladdr = -1
                 else:
                     # misc instruction - just ignore
                     continue
             else:
                 # Jump or call insn
+                calladdr = int(calladdr, 16)
+                ref = m.group('ref')
                 if '+' in ref:
                     # Inter-function jump - reset stack usage to
                     # preamble usage
-                    stackusage = cur[0]
+                    stackusage = cur[1]
                     continue
-                if ref.split('.')[0] in IGNORE:
-                    # Call ignored - list only for informational purposes
-                    stackusage = 0
-                elif insn[:1] == 'j':
+                if insn[:1] == 'j':
                     # Tail call
                     stackusage = 0
                 elif insn[:5] == 'calll':
                     stackusage += 4
                 else:
                     print "unknown call", ref
-            if (ref, stackusage) not in subfuncs:
-                cur[2].append((m.group('addr'), ref, stackusage))
-                subfuncs[(ref, stackusage)] = 1
+            if (calladdr, stackusage) not in subfuncs:
+                cur[3].append((m.group('insnaddr'), calladdr, stackusage))
+                subfuncs[(calladdr, stackusage)] = 1
             # Reset stack usage to preamble usage
-            stackusage = cur[0]
+            stackusage = cur[1]
 
             continue
 
         #print "other", repr(line)
 
     # Calculate maxstackusage
-    for func, info in funcs.items():
-        if info[1] is not None:
+    bynames = {}
+    for funcaddr, info in funcs.items():
+        bynames[info[0]] = info
+        if info[2] is not None:
             continue
-        calcmaxstack(funcs, func)
+        calcmaxstack(funcs, funcaddr)
 
     # Show all functions
-    funcnames = funcs.keys()
+    funcnames = bynames.keys()
     funcnames.sort()
-    for func in funcnames:
-        basicusage, maxusage, calls = funcs[func]
+    for funcname in funcnames:
+        name, basicusage, maxusage, calls = bynames[funcname]
         if maxusage == 0:
             continue
-        print "\n%s[%d,%d]:" % (func, basicusage, maxusage)
-        for addr, callfname, stackusage in calls:
-            callinfo = funcs[callfname]
+        print "\n%s[%d,%d]:" % (funcname, basicusage, maxusage)
+        for insnaddr, calladdr, stackusage in calls:
+            callinfo = funcs[calladdr]
             print "    %04s:%-40s [%d+%d,%d]" % (
-                addr, callfname, stackusage, callinfo[0], stackusage+callinfo[1])
+                insnaddr, callinfo[0], stackusage, callinfo[1]
+                , stackusage+callinfo[2])
 
 def main():
     calc()