These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / scripts / checkstack.py
index b49b6c8..5d9b0bf 100755 (executable)
@@ -2,7 +2,7 @@
 # Script that tries to find how much stack space each function in an
 # object is using.
 #
-# Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2008-2015  Kevin O'Connor <kevin@koconnor.net>
 #
 # This file may be distributed under the terms of the GNU GPLv3 license.
 
@@ -26,85 +26,84 @@ OUTPUTDESC = """
 #    insn_addr:called_function [u+c,t,usage_to_yield_point]
 """
 
+class function:
+    def __init__(self, funcaddr, funcname):
+        self.funcaddr = funcaddr
+        self.funcname = funcname
+        self.basic_stack_usage = 0
+        self.max_stack_usage = None
+        self.yield_usage = -1
+        self.max_yield_usage = None
+        self.total_calls = 0
+        # called_funcs = [(insnaddr, calladdr, stackusage), ...]
+        self.called_funcs = []
+        self.subfuncs = {}
+    # Update function info with a found "yield" point.
+    def noteYield(self, stackusage):
+        if self.yield_usage < stackusage:
+            self.yield_usage = stackusage
+    # Update function info with a found "call" point.
+    def noteCall(self, insnaddr, calladdr, stackusage):
+        if (calladdr, stackusage) in self.subfuncs:
+            # Already noted a nearly identical call - ignore this one.
+            return
+        self.called_funcs.append((insnaddr, calladdr, stackusage))
+        self.subfuncs[(calladdr, stackusage)] = 1
+
 # Find out maximum stack usage for a function
-def calcmaxstack(funcs, funcaddr):
-    info = funcs[funcaddr]
-    # Find max of all nested calls.
-    maxusage = info[1]
-    maxyieldusage = doesyield = 0
-    if info[3] is not None:
-        maxyieldusage = info[3]
-        doesyield = 1
-    info[2] = maxusage
-    info[4] = info[3]
+def calcmaxstack(info, funcs):
+    if info.max_stack_usage is not None:
+        return
+    info.max_stack_usage = max_stack_usage = info.basic_stack_usage
+    info.max_yield_usage = max_yield_usage = info.yield_usage
+    total_calls = 0
     seenbefore = {}
-    totcalls = 0
-    for insnaddr, calladdr, usage in info[6]:
+    # Find max of all nested calls.
+    for insnaddr, calladdr, usage in info.called_funcs:
         callinfo = funcs.get(calladdr)
         if callinfo is None:
             continue
-        if callinfo[2] is None:
-            calcmaxstack(funcs, calladdr)
-        if callinfo[0] not in seenbefore:
-            seenbefore[callinfo[0]] = 1
-            totcalls += 1 + callinfo[5]
-        funcnameroot = callinfo[0].split('.')[0]
+        calcmaxstack(callinfo, funcs)
+        if callinfo.funcname not in seenbefore:
+            seenbefore[callinfo.funcname] = 1
+            total_calls += callinfo.total_calls + 1
+        funcnameroot = callinfo.funcname.split('.')[0]
         if funcnameroot in IGNORE:
             # This called function is ignored - don't contribute it to
             # the max stack.
             continue
+        totusage = usage + callinfo.max_stack_usage
+        totyieldusage = usage + callinfo.max_yield_usage
         if funcnameroot in STACKHOP:
-            if usage > maxusage:
-                maxusage = usage
-            if callinfo[4] is not None:
-                doesyield = 1
-                if usage > maxyieldusage:
-                    maxyieldusage = usage
-            continue
-        totusage = usage + callinfo[2]
-        if totusage > maxusage:
-            maxusage = totusage
-        if callinfo[4] is not None:
-            doesyield = 1
-            totyieldusage = usage + callinfo[4]
-            if totyieldusage > maxyieldusage:
-                maxyieldusage = totyieldusage
-    info[2] = maxusage
-    if doesyield:
-        info[4] = maxyieldusage
-    info[5] = totcalls
+            # Don't count children of this function
+            totusage = totyieldusage = usage
+        if totusage > max_stack_usage:
+            max_stack_usage = totusage
+        if callinfo.max_yield_usage >= 0 and totyieldusage > max_yield_usage:
+            max_yield_usage = totyieldusage
+    info.max_stack_usage = max_stack_usage
+    info.max_yield_usage = max_yield_usage
+    info.total_calls = total_calls
 
 # Try to arrange output so that functions that call each other are
 # near each other.
 def orderfuncs(funcaddrs, availfuncs):
-    l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr)
+    l = [(availfuncs[funcaddr].total_calls
+          , availfuncs[funcaddr].funcname, funcaddr)
          for funcaddr in funcaddrs if funcaddr in availfuncs]
     l.sort()
     l.reverse()
     out = []
     while l:
         count, name, funcaddr = l.pop(0)
-        if funcaddr not in availfuncs:
+        info = availfuncs.get(funcaddr)
+        if info is None:
             continue
-        calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]]
+        calladdrs = [calls[1] for calls in info.called_funcs]
         del availfuncs[funcaddr]
-        out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr]
+        out = out + orderfuncs(calladdrs, availfuncs) + [info]
     return out
 
-# Update function info with a found "yield" point.
-def noteYield(info, stackusage):
-    prevyield = info[3]
-    if prevyield is None or prevyield < stackusage:
-        info[3] = stackusage
-
-# Update function info with a found "call" point.
-def noteCall(info, subfuncs, insnaddr, calladdr, stackusage):
-    if (calladdr, stackusage) in subfuncs:
-        # Already noted a nearly identical call - ignore this one.
-        return
-    info[6].append((insnaddr, calladdr, stackusage))
-    subfuncs[(calladdr, stackusage)] = 1
-
 hex_s = r'[0-9a-f]+'
 re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
 re_asm = re.compile(
@@ -114,11 +113,12 @@ re_asm = re.compile(
 re_usestack = re.compile(
     r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
 
-def calc():
-    # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
-    #                    , yieldusage, maxyieldusage, totalcalls
-    #                    , [(insnaddr, calladdr, stackusage), ...]]
-    funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]}
+def main():
+    unknownfunc = function(None, "<unknown>")
+    indirectfunc = function(-1, '<indirect>')
+    unknownfunc.max_stack_usage = indirectfunc.max_stack_usage = 0
+    unknownfunc.max_yield_usage = indirectfunc.max_yield_usage = -1
+    funcs = {-1: indirectfunc}
     cur = None
     atstart = 0
     stackusage = 0
@@ -129,99 +129,93 @@ def calc():
         if m is not None:
             # Found function
             funcaddr = int(m.group('funcaddr'), 16)
-            funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []]
+            funcs[funcaddr] = cur = function(funcaddr, m.group('func'))
             stackusage = 0
             atstart = 1
-            subfuncs = {}
             continue
         m = re_asm.match(line)
-        if m is not None:
-            insn = m.group('insn')
-
-            im = re_usestack.match(insn)
-            if im is not None:
-                if insn.startswith('pushl') or insn.startswith('pushfl'):
-                    stackusage += 4
-                    continue
-                elif insn.startswith('pushw') or insn.startswith('pushfw'):
-                    stackusage += 2
-                    continue
-                stackusage += int(im.group('num'), 16)
-
-            if atstart:
-                if '%esp' in insn or insn.startswith('leal'):
-                    # Still part of initial header
-                    continue
-                cur[1] = stackusage
-                atstart = 0
-
-            insnaddr = m.group('insnaddr')
-            calladdr = m.group('calladdr')
-            if calladdr is None:
-                if insn.startswith('lcallw'):
-                    noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4)
-                    noteYield(cur, stackusage + 4)
-                elif insn.startswith('int'):
-                    noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6)
-                    noteYield(cur, stackusage + 6)
-                elif insn.startswith('sti'):
-                    noteYield(cur, stackusage)
-                else:
-                    # misc instruction
-                    continue
+        if m is None:
+            #print("other", repr(line))
+            continue
+        insn = m.group('insn')
+
+        im = re_usestack.match(insn)
+        if im is not None:
+            if insn.startswith('pushl') or insn.startswith('pushfl'):
+                stackusage += 4
+                continue
+            elif insn.startswith('pushw') or insn.startswith('pushfw'):
+                stackusage += 2
+                continue
+            stackusage += int(im.group('num'), 16)
+
+        if atstart:
+            if '%esp' in insn or insn.startswith('leal'):
+                # Still part of initial header
+                continue
+            cur.basic_stack_usage = stackusage
+            atstart = 0
+
+        insnaddr = m.group('insnaddr')
+        calladdr = m.group('calladdr')
+        if calladdr is None:
+            if insn.startswith('lcallw'):
+                cur.noteCall(insnaddr, -1, stackusage + 4)
+                cur.noteYield(stackusage + 4)
+            elif insn.startswith('int'):
+                cur.noteCall(insnaddr, -1, stackusage + 6)
+                cur.noteYield(stackusage + 6)
+            elif insn.startswith('sti'):
+                cur.noteYield(stackusage)
+            else:
+                # misc instruction
+                continue
+        else:
+            # Jump or call insn
+            calladdr = int(calladdr, 16)
+            ref = m.group('ref')
+            if '+' in ref:
+                # Inter-function jump.
+                pass
+            elif insn.startswith('j'):
+                # Tail call
+                cur.noteCall(insnaddr, calladdr, 0)
+            elif insn.startswith('calll'):
+                cur.noteCall(insnaddr, calladdr, stackusage + 4)
+            elif insn.startswith('callw'):
+                cur.noteCall(insnaddr, calladdr, stackusage + 2)
             else:
-                # Jump or call insn
-                calladdr = int(calladdr, 16)
-                ref = m.group('ref')
-                if '+' in ref:
-                    # Inter-function jump.
-                    pass
-                elif insn.startswith('j'):
-                    # Tail call
-                    noteCall(cur, subfuncs, insnaddr, calladdr, 0)
-                elif insn.startswith('calll'):
-                    noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4)
-                elif insn.startswith('callw'):
-                    noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 2)
-                else:
-                    print("unknown call", ref)
-                    noteCall(cur, subfuncs, insnaddr, calladdr, stackusage)
-            # Reset stack usage to preamble usage
-            stackusage = cur[1]
-
-        #print("other", repr(line))
+                print("unknown call", ref)
+                cur.noteCall(insnaddr, calladdr, stackusage)
+        # Reset stack usage to preamble usage
+        stackusage = cur.basic_stack_usage
 
     # Calculate maxstackusage
-    for funcaddr, info in funcs.items():
-        if info[2] is not None:
-            continue
-        calcmaxstack(funcs, funcaddr)
+    for info in funcs.values():
+        calcmaxstack(info, funcs)
 
     # Sort functions for output
-    funcaddrs = orderfuncs(funcs.keys(), funcs.copy())
+    funcinfos = orderfuncs(funcs.keys(), funcs.copy())
 
     # Show all functions
     print(OUTPUTDESC)
-    for funcaddr in funcaddrs:
-        name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \
-            funcs[funcaddr]
-        if maxusage == 0 and maxyieldusage is None:
+    for info in funcinfos:
+        if info.max_stack_usage == 0 and info.max_yield_usage < 0:
             continue
         yieldstr = ""
-        if maxyieldusage is not None:
-            yieldstr = ",%d" % maxyieldusage
-        print("\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr))
-        for insnaddr, calladdr, stackusage in calls:
-            callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None))
+        if info.max_yield_usage >= 0:
+            yieldstr = ",%d" % info.max_yield_usage
+        print("\n%s[%d,%d%s]:" % (info.funcname, info.basic_stack_usage
+                                  , info.max_stack_usage, yieldstr))
+        for insnaddr, calladdr, stackusage in info.called_funcs:
+            callinfo = funcs.get(calladdr, unknownfunc)
             yieldstr = ""
-            if callinfo[4] is not None:
-                yieldstr = ",%d" % (stackusage + callinfo[4])
+            if callinfo.max_yield_usage >= 0:
+                yieldstr = ",%d" % (stackusage + callinfo.max_yield_usage)
             print("    %04s:%-40s [%d+%d,%d%s]" % (
-                insnaddr, callinfo[0], stackusage, callinfo[1]
-                , stackusage+callinfo[2], yieldstr))
-
-def main():
-    calc()
+                insnaddr, callinfo.funcname, stackusage
+                , callinfo.basic_stack_usage
+                , stackusage+callinfo.max_stack_usage, yieldstr))
 
 if __name__ == '__main__':
     main()