summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/scripts/checkstack.py
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/scripts/checkstack.py')
-rwxr-xr-xqemu/roms/seabios/scripts/checkstack.py270
1 files changed, 132 insertions, 138 deletions
diff --git a/qemu/roms/seabios/scripts/checkstack.py b/qemu/roms/seabios/scripts/checkstack.py
index b49b6c8cc..5d9b0bfaf 100755
--- a/qemu/roms/seabios/scripts/checkstack.py
+++ b/qemu/roms/seabios/scripts/checkstack.py
@@ -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()