<s> import operator <EOL> import optparse <EOL> import os <EOL> import re <EOL> import subprocess <EOL> import sys <EOL> import json <EOL> def format_bytes ( bytes ) : <EOL> """<STR_LIT>""" <EOL> if bytes > <NUM_LIT> : <EOL> bytes = bytes / <NUM_LIT> <EOL> return '<STR_LIT>' % bytes <EOL> if bytes > <NUM_LIT> : <EOL> bytes = bytes / <NUM_LIT> <EOL> return '<STR_LIT>' % bytes <EOL> return str ( bytes ) <EOL> def symbol_type_to_human ( type ) : <EOL> """<STR_LIT>""" <EOL> return { <EOL> '<STR_LIT:b>' : '<STR_LIT>' , <EOL> '<STR_LIT:d>' : '<STR_LIT:data>' , <EOL> '<STR_LIT:r>' : '<STR_LIT>' , <EOL> '<STR_LIT:t>' : '<STR_LIT:code>' , <EOL> '<STR_LIT:u>' : '<STR_LIT>' , <EOL> '<STR_LIT:w>' : '<STR_LIT>' , <EOL> '<STR_LIT:v>' : '<STR_LIT>' <EOL> } [ type ] <EOL> def parse_nm ( input ) : <EOL> """<STR_LIT>""" <EOL> sym_re = re . compile ( r'<STR_LIT>' ) <EOL> addr_re = re . compile ( r'<STR_LIT>' ) <EOL> noaddr_re = re . compile ( r'<STR_LIT>' ) <EOL> for line in input : <EOL> line = line . rstrip ( ) <EOL> match = sym_re . match ( line ) <EOL> if match : <EOL> size , type , sym = match . groups ( ) [ <NUM_LIT:0> : <NUM_LIT:3> ] <EOL> size = int ( size , <NUM_LIT:16> ) <EOL> type = type . lower ( ) <EOL> if type in [ '<STR_LIT:u>' , '<STR_LIT:v>' ] : <EOL> type = '<STR_LIT:w>' <EOL> if type == '<STR_LIT:b>' : <EOL> continue <EOL> path = match . group ( <NUM_LIT:4> ) <EOL> yield sym , type , size , path <EOL> continue <EOL> match = addr_re . match ( line ) <EOL> if match : <EOL> type , sym = match . groups ( ) [ <NUM_LIT:0> : <NUM_LIT:2> ] <EOL> continue <EOL> match = noaddr_re . match ( line ) <EOL> if match : <EOL> type , sym = match . groups ( ) <EOL> if type in ( '<STR_LIT>' , '<STR_LIT:w>' ) : <EOL> continue <EOL> print >> sys . stderr , '<STR_LIT>' , repr ( line ) <EOL> def demangle ( ident , cppfilt ) : <EOL> if cppfilt and ident . startswith ( '<STR_LIT>' ) : <EOL> ident = subprocess . check_output ( [ cppfilt , ident ] ) . strip ( ) <EOL> return ident <EOL> class Suffix : <EOL> def __init__ ( self , suffix , replacement ) : <EOL> self . pattern = '<STR_LIT>' + suffix + '<STR_LIT>' <EOL> self . re = re . compile ( self . pattern ) <EOL> self . replacement = replacement <EOL> class SuffixCleanup : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> self . suffixes = [ <EOL> Suffix ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> Suffix ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> Suffix ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ] <EOL> def cleanup ( self , ident , cppfilt ) : <EOL> """<STR_LIT>""" <EOL> to_append = [ ] <EOL> for s in self . suffixes : <EOL> found = s . re . match ( ident ) <EOL> if not found : <EOL> continue <EOL> to_append += [ '<STR_LIT>' + s . replacement + '<STR_LIT:.>' + found . group ( <NUM_LIT:2> ) + '<STR_LIT:]>' ] <EOL> ident = found . group ( <NUM_LIT:1> ) + found . group ( <NUM_LIT:3> ) <EOL> if len ( to_append ) > <NUM_LIT:0> : <EOL> ident = demangle ( ident , cppfilt ) <EOL> for s in to_append : <EOL> ident += s <EOL> return ident <EOL> suffix_cleanup = SuffixCleanup ( ) <EOL> def parse_cpp_name ( name , cppfilt ) : <EOL> name = suffix_cleanup . cleanup ( name , cppfilt ) <EOL> prefixes = [ <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> ] <EOL> for prefix , replacement in prefixes : <EOL> if name . startswith ( prefix ) : <EOL> name = name [ len ( prefix ) : ] + replacement <EOL> replacements = [ <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> ] <EOL> for value , replacement in replacements : <EOL> name = name . replace ( value , replacement ) <EOL> def parse_one ( val ) : <EOL> """<STR_LIT>""" <EOL> if ( val . startswith ( '<STR_LIT>' ) and <EOL> not ( val [ <NUM_LIT:8> ] . isalnum ( ) or val [ <NUM_LIT:8> ] == '<STR_LIT:_>' ) ) : <EOL> return ( val , '<STR_LIT>' ) <EOL> co = val . find ( '<STR_LIT>' ) <EOL> lt = val . find ( '<STR_LIT:<>' ) <EOL> pa = val . find ( '<STR_LIT:(>' ) <EOL> co = len ( val ) if co == - <NUM_LIT:1> else co <EOL> lt = len ( val ) if lt == - <NUM_LIT:1> else lt <EOL> pa = len ( val ) if pa == - <NUM_LIT:1> else pa <EOL> if co < lt and co < pa : <EOL> return ( val [ : co ] , val [ co + <NUM_LIT:2> : ] ) <EOL> if lt < pa : <EOL> open_tmpl = <NUM_LIT:1> <EOL> gt = lt <EOL> while val [ gt ] != '<STR_LIT:>>' or open_tmpl != <NUM_LIT:0> : <EOL> gt = gt + <NUM_LIT:1> <EOL> if val [ gt ] == '<STR_LIT:<>' : <EOL> open_tmpl = open_tmpl + <NUM_LIT:1> <EOL> if val [ gt ] == '<STR_LIT:>>' : <EOL> open_tmpl = open_tmpl - <NUM_LIT:1> <EOL> ret = val [ gt + <NUM_LIT:1> : ] <EOL> if ret . startswith ( '<STR_LIT>' ) : <EOL> ret = ret [ <NUM_LIT:2> : ] <EOL> if ret . startswith ( '<STR_LIT:(>' ) : <EOL> return ( val , '<STR_LIT>' ) <EOL> return ( val [ : gt + <NUM_LIT:1> ] , ret ) <EOL> return ( val , '<STR_LIT>' ) <EOL> parts = [ ] <EOL> while len ( name ) > <NUM_LIT:0> : <EOL> ( part , name ) = parse_one ( name ) <EOL> assert len ( part ) > <NUM_LIT:0> <EOL> parts . append ( part ) <EOL> return parts <EOL> def treeify_syms ( symbols , strip_prefix = None , cppfilt = None ) : <EOL> dirs = { } <EOL> for sym , type , size , path in symbols : <EOL> if path : <EOL> path = os . path . normpath ( path ) <EOL> if strip_prefix and path . startswith ( strip_prefix ) : <EOL> path = path [ len ( strip_prefix ) : ] <EOL> elif path . startswith ( '<STR_LIT:/>' ) : <EOL> path = path [ <NUM_LIT:1> : ] <EOL> path = [ '<STR_LIT>' ] + path . split ( '<STR_LIT:/>' ) <EOL> parts = parse_cpp_name ( sym , cppfilt ) <EOL> if len ( parts ) == <NUM_LIT:1> : <EOL> if path : <EOL> parts = path + parts <EOL> else : <EOL> new_prefix = [ '<STR_LIT>' ] <EOL> regroups = [ <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> [ '<STR_LIT>' , '<STR_LIT>' ] , <EOL> ] <EOL> for prefix , group in regroups : <EOL> if parts [ <NUM_LIT:0> ] . startswith ( prefix ) : <EOL> parts [ <NUM_LIT:0> ] = parts [ <NUM_LIT:0> ] [ len ( prefix ) : ] <EOL> parts [ <NUM_LIT:0> ] = demangle ( parts [ <NUM_LIT:0> ] , cppfilt ) <EOL> new_prefix += [ group ] <EOL> break <EOL> parts = new_prefix + parts <EOL> key = parts . pop ( ) <EOL> tree = dirs <EOL> try : <EOL> depth = <NUM_LIT:0> <EOL> for part in parts : <EOL> depth = depth + <NUM_LIT:1> <EOL> assert part != '<STR_LIT>' , path <EOL> if part not in tree : <EOL> tree [ part ] = { '<STR_LIT>' : { } } <EOL> if type not in tree [ part ] [ '<STR_LIT>' ] : <EOL> tree [ part ] [ '<STR_LIT>' ] [ type ] = <NUM_LIT:0> <EOL> tree [ part ] [ '<STR_LIT>' ] [ type ] += <NUM_LIT:1> <EOL> tree = tree [ part ] <EOL> old_size , old_symbols = tree . get ( key , ( <NUM_LIT:0> , { } ) ) <EOL> if type not in old_symbols : <EOL> old_symbols [ type ] = <NUM_LIT:0> <EOL> old_symbols [ type ] += <NUM_LIT:1> <EOL> tree [ key ] = ( old_size + size , old_symbols ) <EOL> except : <EOL> print >> sys . stderr , '<STR_LIT>' % ( sym , parts , key ) <EOL> raise <EOL> return dirs <EOL> def jsonify_tree ( tree , name ) : <EOL> children = [ ] <EOL> total = <NUM_LIT:0> <EOL> files = <NUM_LIT:0> <EOL> for key , val in tree . iteritems ( ) : <EOL> if key == '<STR_LIT>' : <EOL> continue <EOL> if isinstance ( val , dict ) : <EOL> subtree = jsonify_tree ( val , key ) <EOL> total += subtree [ '<STR_LIT:data>' ] [ '<STR_LIT>' ] <EOL> children . append ( subtree ) <EOL> else : <EOL> ( size , symbols ) = val <EOL> total += size <EOL> assert len ( symbols ) == <NUM_LIT:1> , symbols . values ( ) [ <NUM_LIT:0> ] == <NUM_LIT:1> <EOL> symbol = symbol_type_to_human ( symbols . keys ( ) [ <NUM_LIT:0> ] ) <EOL> children . append ( { <EOL> '<STR_LIT:name>' : key + '<STR_LIT:U+0020>' + format_bytes ( size ) , <EOL> '<STR_LIT:data>' : { <EOL> '<STR_LIT>' : size , <EOL> '<STR_LIT>' : symbol , <EOL> } <EOL> } ) <EOL> children . sort ( key = lambda child : - child [ '<STR_LIT:data>' ] [ '<STR_LIT>' ] ) <EOL> dominant_symbol = '<STR_LIT>' <EOL> if '<STR_LIT>' in tree : <EOL> dominant_symbol = symbol_type_to_human ( <EOL> max ( tree [ '<STR_LIT>' ] . iteritems ( ) , <EOL> key = operator . itemgetter ( <NUM_LIT:1> ) ) [ <NUM_LIT:0> ] ) <EOL> return { <EOL> '<STR_LIT:name>' : name + '<STR_LIT:U+0020>' + format_bytes ( total ) , <EOL> '<STR_LIT:data>' : { <EOL> '<STR_LIT>' : total , <EOL> '<STR_LIT>' : dominant_symbol , <EOL> } , <EOL> '<STR_LIT>' : children , <EOL> } <EOL> def dump_nm ( nmfile , strip_prefix , cppfilt ) : <EOL> dirs = treeify_syms ( parse_nm ( nmfile ) , strip_prefix , cppfilt ) <EOL> print ( '<STR_LIT>' + <EOL> json . dumps ( jsonify_tree ( dirs , '<STR_LIT>' ) , indent = <NUM_LIT:2> ) ) <EOL> def parse_objdump ( input ) : <EOL> """<STR_LIT>""" <EOL> sec_re = re . compile ( '<STR_LIT>' ) <EOL> sections = [ ] <EOL> debug_sections = [ ] <EOL> for line in input : <EOL> line = line . strip ( ) <EOL> match = sec_re . match ( line ) <EOL> if match : <EOL> name , size = match . groups ( ) <EOL> if name . startswith ( '<STR_LIT:.>' ) : <EOL> name = name [ <NUM_LIT:1> : ] <EOL> if name . startswith ( '<STR_LIT>' ) : <EOL> name = name [ len ( '<STR_LIT>' ) : ] <EOL> debug_sections . append ( ( name , int ( size , <NUM_LIT:16> ) ) ) <EOL> else : <EOL> sections . append ( ( name , int ( size , <NUM_LIT:16> ) ) ) <EOL> continue <EOL> return sections , debug_sections <EOL> def jsonify_sections ( name , sections ) : <EOL> children = [ ] <EOL> total = <NUM_LIT:0> <EOL> for section , size in sections : <EOL> children . append ( { <EOL> '<STR_LIT:name>' : section + '<STR_LIT:U+0020>' + format_bytes ( size ) , <EOL> '<STR_LIT:data>' : { '<STR_LIT>' : size } <EOL> } ) <EOL> total += size <EOL> children . sort ( key = lambda child : - child [ '<STR_LIT:data>' ] [ '<STR_LIT>' ] ) <EOL> return { <EOL> '<STR_LIT:name>' : name + '<STR_LIT:U+0020>' + format_bytes ( total ) , <EOL> '<STR_LIT:data>' : { '<STR_LIT>' : total } , <EOL> '<STR_LIT>' : children <EOL> } <EOL> def dump_sections ( objdump ) : <EOL> sections , debug_sections = parse_objdump ( objdump ) <EOL> sections = jsonify_sections ( '<STR_LIT>' , sections ) <EOL> debug_sections = jsonify_sections ( '<STR_LIT>' , debug_sections ) <EOL> size = sections [ '<STR_LIT:data>' ] [ '<STR_LIT>' ] + debug_sections [ '<STR_LIT:data>' ] [ '<STR_LIT>' ] <EOL> print '<STR_LIT>' + json . dumps ( { <EOL> '<STR_LIT:name>' : '<STR_LIT>' + format_bytes ( size ) , <EOL> '<STR_LIT:data>' : { '<STR_LIT>' : size } , <EOL> '<STR_LIT>' : [ debug_sections , sections ] } ) <EOL> usage = """<STR_LIT>""" <EOL> parser = optparse . OptionParser ( usage = usage ) <EOL> parser . add_option ( '<STR_LIT>' , action = '<STR_LIT:store>' , dest = '<STR_LIT>' , <EOL> metavar = '<STR_LIT>' , default = '<STR_LIT>' , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_option ( '<STR_LIT>' , action = '<STR_LIT:store>' , dest = '<STR_LIT>' , <EOL> metavar = '<STR_LIT>' , default = '<STR_LIT>' , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_option ( '<STR_LIT>' , metavar = '<STR_LIT>' , action = '<STR_LIT:store>' , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_option ( '<STR_LIT>' , action = '<STR_LIT:store>' , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_option ( '<STR_LIT>' , action = '<STR_LIT:store>' , metavar = '<STR_LIT>' , dest = '<STR_LIT>' , <EOL> default = '<STR_LIT>' , help = "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> opts , args = parser . parse_args ( ) <EOL> if len ( args ) != <NUM_LIT:1> : <EOL> parser . print_usage ( ) <EOL> sys . exit ( <NUM_LIT:1> ) <EOL> mode = args [ <NUM_LIT:0> ] <EOL> if mode == '<STR_LIT>' : <EOL> nmfile = open ( opts . nmpath , '<STR_LIT:r>' ) <EOL> try : <EOL> res = subprocess . check_output ( [ opts . cppfilt , '<STR_LIT>' ] ) <EOL> if res . strip ( ) != '<STR_LIT>' : <EOL> print >> sys . stderr , ( "<STR_LIT>" <EOL> "<STR_LIT>" % opt . cppfilt ) <EOL> opts . cppfilt = None <EOL> except : <EOL> print >> sys . stderr , ( "<STR_LIT>" <EOL> "<STR_LIT>" % opt . cppfilt ) <EOL> opts . cppfilt = None <EOL> dump_nm ( nmfile , strip_prefix = opts . strip_prefix , cppfilt = opts . cppfilt ) <EOL> elif mode == '<STR_LIT>' : <EOL> objdumpfile = open ( opts . objdumppath , '<STR_LIT:r>' ) <EOL> dump_sections ( objdumpfile ) <EOL> elif mode == '<STR_LIT>' : <EOL> nmfile = open ( opts . nmpath , '<STR_LIT:r>' ) <EOL> syms = list ( parse_nm ( nmfile ) ) <EOL> syms . sort ( key = lambda x : - x [ <NUM_LIT:2> ] ) <EOL> total = <NUM_LIT:0> <EOL> for sym , type , size , path in syms : <EOL> if type in ( '<STR_LIT:b>' , '<STR_LIT:w>' ) : <EOL> continue <EOL> if path is None : <EOL> path = '<STR_LIT>' <EOL> if opts . filter and not ( opts . filter in sym or opts . filter in path ) : <EOL> continue <EOL> print '<STR_LIT>' % ( format_bytes ( size ) , sym , <EOL> symbol_type_to_human ( type ) , path ) <EOL> total += size <EOL> print '<STR_LIT>' % ( format_bytes ( total ) , '<STR_LIT>' ) , <EOL> else : <EOL> print '<STR_LIT>' <EOL> parser . print_usage ( ) </s>
