lkml.org 
[lkml]   [2011]   [Oct]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/3] ARM: Add static kernel function stack size analyzer, for ARM
    This tool can be used to analyze the function stack size for ARM kernels,
    statically, based on a disassembly of vmlinux (or an individual .o file

    Signed-off-by: Tim Bird <tim.bird@am.sony.com>
    ---
    scripts/stack_size | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 289 insertions(+), 0 deletions(-)
    create mode 100755 scripts/stack_size

    diff --git a/scripts/stack_size b/scripts/stack_size
    new file mode 100755
    index 0000000..af9fdac
    --- /dev/null
    +++ b/scripts/stack_size
    @@ -0,0 +1,289 @@
    +#!/usr/bin/python
    +# stack_size - a program to parse ARM assembly files and produce
    +# a listing of stack sizes for the functions encountered.
    +#
    +# To use: compile your kernel as normal, then run this program on vmlinux:
    +# $ scripts/stac_size vmlinux
    +#
    +# If you have cross-compiled, then your CROSS_COMPILE environment variable
    +# should be set to the cross prefix for your toolchain
    +#
    +# Author: Tim Bird <tim dot bird ~(at)~ am dot sony dot com>
    +# Copyright 2011 Sony Network Entertainment, Inc
    +#
    +# GPL version 2.0 applies.
    +#
    +
    +import os, sys
    +version = "1.0"
    +
    +debug = 0
    +
    +def dprint(msg):
    + global debug
    + if debug:
    + print msg
    +
    +def usage():
    + print """Usage: %s [options] <filename>
    +
    +Show stack size for functions in a program or object file.
    +Generate and parse the ARM assembly for the indicated filename,
    +and print out the size of the stack for each function.
    +
    +If you used a cross-compiler, please set the cross-compiler prefix
    +in the environment variable 'CROSS_COMPILE', before using this tool.
    +
    +Options:
    + -h show this usage help
    + -t <n> show the top n functions with the largest stacks
    + (default is to show top 10 functions with largest stacks)
    + -f show full function list
    + -g show histogram of stack depths
    + -V or --version show version information and exit
    +
    +Notes: This leaves the assembly file in the same directory as the source
    +filename, called '<filename>.S' This program currently only supports
    +ARM EABI.
    +
    +""" % os.path.basename(sys.argv[0])
    + sys.exit(0)
    +
    +class function_class():
    + def __init__(self, name, addr):
    + self.name = name
    + self.addr = addr
    + self.depth = 0
    +
    + def __repr__(self):
    + return "function: %s with depth %d" % (self.name, self.depth)
    +
    +def open_assembly(filename):
    + base = filename
    + if base.endswith(".o"):
    + base = base[:-2]
    +
    + assembly_filename = "%s.S" % base
    +
    + try:
    + fd = open(assembly_filename)
    + except:
    + print "Could not find %s - trying to generate from %s\n" % \
    + (assembly_filename, filename)
    + print "This might take a few minutes..."
    + try:
    + cross = os.environ["CROSS_COMPILE"]
    + except:
    + cross = ""
    + cmd = "%sobjdump -d %s >%s" % \
    + (cross, filename, assembly_filename)
    + print "Using command: '%s'" % cmd
    + os.system(cmd)
    +
    + try:
    + fd = open(assembly_filename)
    + except:
    + print "Could not find %s, and conversion didn't work\n" % \
    + (assembly_filename)
    + sys.exit(1)
    +
    + return fd;
    +
    +def do_show_histogram(functions):
    + depth_count = {}
    +
    + max_depth_bucket = 0
    + for funcname in functions.keys():
    + depth = functions[funcname].depth
    + depth_bucket = depth/10
    + if depth_bucket > max_depth_bucket:
    + max_depth_bucket = depth_bucket
    +
    + try:
    + depth_count[depth_bucket] += 1
    + except:
    + depth_count[depth_bucket] = 1
    +
    + print "=========== HISTOGRAM =============="
    + for i in range(0,max_depth_bucket+1):
    + try:
    + count = depth_count[i]
    + except:
    + count = 0
    +
    + # use numbers for bars that are too long
    + if count<72:
    + bar = count*"*"
    + else:
    + bar = (72-8)*"*" + "(%d)*" % count
    + print "%3d: %s" % (i*10,bar)
    +
    +def cmp_depth(f1, f2):
    + return cmp(f1.depth, f2.depth)
    +
    +def main():
    + global debug
    +
    + full_list = 0
    + show_histogram = 0
    + debug = 0
    + top_count = 10
    +
    + if "-h" in sys.argv:
    + usage()
    +
    + if "-f" in sys.argv:
    + full_list = 1
    + sys.argv.remove("-f")
    +
    + if "-g" in sys.argv:
    + show_histogram = 1
    + sys.argv.remove("-g")
    +
    + if "-t" in sys.argv:
    + top_count = sys.argv[sys.argv.index("-t")+1]
    + sys.argv.remove(top_count)
    + sys.argv.remove("-t")
    + top_count = int(top_count)
    +
    + if "--debug" in sys.argv:
    + debug = 1
    + sys.argv.remove("--debug")
    +
    + if "--version" in sys.argv or "-V" in sys.argv:
    + print "%s version %s" % (os.path.basename(sys.argv[0]),version)
    + sys.exit(0)
    +
    + try:
    + filename = sys.argv[1]
    + except:
    + print "Error: missing filename to scan"
    + usage()
    +
    + fd = open_assembly(filename)
    +
    + functions = {}
    + func = None
    +
    + max_cur_depth = 0
    + depth = 0
    + func_line_count = 0
    + PROGRAM_ENTRY_MAXLINES = 4
    +
    + for line in fd.xreadlines():
    + # parse lines
    +
    + # find function starts
    + try:
    + if line[8:10]==" <":
    + func_line = line
    + (func_addr_s,rest) = func_line.split(" ",1)
    + funcname = rest[1:-3]
    + #print line,
    + func_addr = int(func_addr_s, 16)
    + #print "func_addr=%x, func=%s" % (func_addr, func)
    + # record depth of last function
    + if func:
    + func.depth = max_cur_depth
    + dprint("stack depth: %d" % max_cur_depth)
    +
    + # start new function
    + dprint("function: %s" % funcname)
    + func = function_class(funcname, func_addr)
    + functions[funcname] = func
    + depth = 0
    + max_cur_depth = 0
    + func_line_count = 0
    +
    + except:
    + pass
    +
    + func_line_count += 1
    +
    + # calculate stack depth
    + # pattern is: initial register push (with "push {...}
    + # reservation of local stack space
    + if line.find("push\t") != -1 and \
    + func_line_count<PROGRAM_ENTRY_MAXLINES:
    + # parse push
    + (before, args) = line.split("push",1)
    + dprint("push args=%s" % args)
    + regs = line.split(",")
    + depth += 4 * len(regs)
    + if depth>max_cur_depth:
    + max_cur_depth = depth
    +
    + dprint("depth=%d" % depth)
    +
    + if line.find("sub\tsp, sp, #") != -1 and \
    + func_line_count<PROGRAM_ENTRY_MAXLINES:
    + # parse sub
    + (before, args) = line.split("sub",1)
    + if debug:
    + print "sub args=%s" % args
    + (sp1,sp2,imm) = line.split(",",2)
    + # next line splits: ' #84\t ; 0x54\n'
    + # into ['#84',';','0x54']
    + # take [0]th element, and strip leading '#'
    + #print "imm='%s'" % imm
    + depth += int(imm.split()[0][1:])
    + if depth>max_cur_depth:
    + max_cur_depth = depth
    +
    + dprint("depth=%d" % depth)
    +
    + # disable check for pops (used for debugging)
    + if None and line.find("pop\t") != -1:
    + # parse pop
    + (before, args) = line.split("pop",1)
    + dprint("pop args=%s" % args)
    + regs = line.split(",")
    + depth -= 4 * len(regs)
    + if depth<0:
    + print "Parser Error: function: %s, depth=%d" % \
    + (funcname, depth)
    + dprint("depth=%d" % depth)
    +
    + # record depth of last function
    + if func:
    + func.depth = max_cur_depth
    + dprint("max stack depth: %d" % max_cur_depth)
    +
    + fd.close()
    +
    + if not functions:
    + print "No functions found. Done."
    + return
    +
    + # calculate results
    + max_depth = 0
    + maxfunc = func
    + for func in functions.values():
    + if func.depth > max_depth:
    + max_depth = func.depth
    + maxfunc = func
    +
    + print "============ RESULTS ==============="
    + print "number of functions = %d" % len(functions)
    + print "max function stack depth= %d" % maxfunc.depth
    + print "function with max depth = %s\n" % maxfunc.name
    +
    + if full_list or top_count:
    + funclist = functions.values()
    + funclist.sort(cmp_depth)
    + print "%-32s %s" % ("Function Name ","Stack Depth")
    + print "%-32s %s" % ("=====================","===========")
    +
    + if full_list:
    + top_count = len(funclist)
    +
    + start = len(funclist)-top_count
    + for i in range(start, start+top_count):
    + func = funclist[i]
    + print "%-32s %4d" % (func.name, func.depth)
    +
    + if show_histogram:
    + do_show_histogram(functions)
    +
    +if __name__=="__main__":
    + main()
    --
    1.6.6


    \
     
     \ /
      Last update: 2011-10-19 01:35    [W:0.034 / U:0.728 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site