1*03ce13f7SAndroid Build Coastguard Worker#!/usr/bin/python 2*03ce13f7SAndroid Build Coastguard Worker# 3*03ce13f7SAndroid Build Coastguard Worker# Copyright 2013 Google Inc. All Rights Reserved. 4*03ce13f7SAndroid Build Coastguard Worker# 5*03ce13f7SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*03ce13f7SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*03ce13f7SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*03ce13f7SAndroid Build Coastguard Worker# 9*03ce13f7SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*03ce13f7SAndroid Build Coastguard Worker# 11*03ce13f7SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*03ce13f7SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*03ce13f7SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*03ce13f7SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*03ce13f7SAndroid Build Coastguard Worker# limitations under the License. 16*03ce13f7SAndroid Build Coastguard Worker 17*03ce13f7SAndroid Build Coastguard Workerimport fileinput 18*03ce13f7SAndroid Build Coastguard Workerimport operator 19*03ce13f7SAndroid Build Coastguard Workerimport optparse 20*03ce13f7SAndroid Build Coastguard Workerimport os 21*03ce13f7SAndroid Build Coastguard Workerimport pprint 22*03ce13f7SAndroid Build Coastguard Workerimport re 23*03ce13f7SAndroid Build Coastguard Workerimport subprocess 24*03ce13f7SAndroid Build Coastguard Workerimport sys 25*03ce13f7SAndroid Build Coastguard Workerimport json 26*03ce13f7SAndroid Build Coastguard Worker 27*03ce13f7SAndroid Build Coastguard Workerdef format_bytes(bytes): 28*03ce13f7SAndroid Build Coastguard Worker """Pretty-print a number of bytes.""" 29*03ce13f7SAndroid Build Coastguard Worker if bytes > 1e6: 30*03ce13f7SAndroid Build Coastguard Worker bytes = bytes / 1.0e6 31*03ce13f7SAndroid Build Coastguard Worker return '%.1fm' % bytes 32*03ce13f7SAndroid Build Coastguard Worker if bytes > 1e3: 33*03ce13f7SAndroid Build Coastguard Worker bytes = bytes / 1.0e3 34*03ce13f7SAndroid Build Coastguard Worker return '%.1fk' % bytes 35*03ce13f7SAndroid Build Coastguard Worker return str(bytes) 36*03ce13f7SAndroid Build Coastguard Worker 37*03ce13f7SAndroid Build Coastguard Worker 38*03ce13f7SAndroid Build Coastguard Workerdef symbol_type_to_human(type): 39*03ce13f7SAndroid Build Coastguard Worker """Convert a symbol type as printed by nm into a human-readable name.""" 40*03ce13f7SAndroid Build Coastguard Worker return { 41*03ce13f7SAndroid Build Coastguard Worker 'b': 'bss', 42*03ce13f7SAndroid Build Coastguard Worker 'd': 'data', 43*03ce13f7SAndroid Build Coastguard Worker 'r': 'read-only data', 44*03ce13f7SAndroid Build Coastguard Worker 't': 'code', 45*03ce13f7SAndroid Build Coastguard Worker 'u': 'weak symbol', # Unique global. 46*03ce13f7SAndroid Build Coastguard Worker 'w': 'weak symbol', 47*03ce13f7SAndroid Build Coastguard Worker 'v': 'weak symbol' 48*03ce13f7SAndroid Build Coastguard Worker }[type] 49*03ce13f7SAndroid Build Coastguard Worker 50*03ce13f7SAndroid Build Coastguard Worker 51*03ce13f7SAndroid Build Coastguard Workerdef parse_nm(input): 52*03ce13f7SAndroid Build Coastguard Worker """Parse nm output. 53*03ce13f7SAndroid Build Coastguard Worker 54*03ce13f7SAndroid Build Coastguard Worker Argument: an iterable over lines of nm output. 55*03ce13f7SAndroid Build Coastguard Worker 56*03ce13f7SAndroid Build Coastguard Worker Yields: (symbol name, symbol type, symbol size, source file path). 57*03ce13f7SAndroid Build Coastguard Worker Path may be None if nm couldn't figure out the source file. 58*03ce13f7SAndroid Build Coastguard Worker """ 59*03ce13f7SAndroid Build Coastguard Worker 60*03ce13f7SAndroid Build Coastguard Worker # Match lines with size + symbol + optional filename. 61*03ce13f7SAndroid Build Coastguard Worker sym_re = re.compile(r'^[0-9a-f]+ ([0-9a-f]+) (.) ([^\t]+)(?:\t(.*):\d+)?$') 62*03ce13f7SAndroid Build Coastguard Worker 63*03ce13f7SAndroid Build Coastguard Worker # Match lines with addr but no size. 64*03ce13f7SAndroid Build Coastguard Worker addr_re = re.compile(r'^[0-9a-f]+ (.) ([^\t]+)(?:\t.*)?$') 65*03ce13f7SAndroid Build Coastguard Worker # Match lines that don't have an address at all -- typically external symbols. 66*03ce13f7SAndroid Build Coastguard Worker noaddr_re = re.compile(r'^ + (.) (.*)$') 67*03ce13f7SAndroid Build Coastguard Worker 68*03ce13f7SAndroid Build Coastguard Worker for line in input: 69*03ce13f7SAndroid Build Coastguard Worker line = line.rstrip() 70*03ce13f7SAndroid Build Coastguard Worker match = sym_re.match(line) 71*03ce13f7SAndroid Build Coastguard Worker if match: 72*03ce13f7SAndroid Build Coastguard Worker size, type, sym = match.groups()[0:3] 73*03ce13f7SAndroid Build Coastguard Worker size = int(size, 16) 74*03ce13f7SAndroid Build Coastguard Worker type = type.lower() 75*03ce13f7SAndroid Build Coastguard Worker if type in ['u', 'v']: 76*03ce13f7SAndroid Build Coastguard Worker type = 'w' # just call them all weak 77*03ce13f7SAndroid Build Coastguard Worker if type == 'b': 78*03ce13f7SAndroid Build Coastguard Worker continue # skip all BSS for now 79*03ce13f7SAndroid Build Coastguard Worker path = match.group(4) 80*03ce13f7SAndroid Build Coastguard Worker yield sym, type, size, path 81*03ce13f7SAndroid Build Coastguard Worker continue 82*03ce13f7SAndroid Build Coastguard Worker match = addr_re.match(line) 83*03ce13f7SAndroid Build Coastguard Worker if match: 84*03ce13f7SAndroid Build Coastguard Worker type, sym = match.groups()[0:2] 85*03ce13f7SAndroid Build Coastguard Worker # No size == we don't care. 86*03ce13f7SAndroid Build Coastguard Worker continue 87*03ce13f7SAndroid Build Coastguard Worker match = noaddr_re.match(line) 88*03ce13f7SAndroid Build Coastguard Worker if match: 89*03ce13f7SAndroid Build Coastguard Worker type, sym = match.groups() 90*03ce13f7SAndroid Build Coastguard Worker if type in ('U', 'w'): 91*03ce13f7SAndroid Build Coastguard Worker # external or weak symbol 92*03ce13f7SAndroid Build Coastguard Worker continue 93*03ce13f7SAndroid Build Coastguard Worker 94*03ce13f7SAndroid Build Coastguard Worker print >>sys.stderr, 'unparsed:', repr(line) 95*03ce13f7SAndroid Build Coastguard Worker 96*03ce13f7SAndroid Build Coastguard Workerdef demangle(ident, cppfilt): 97*03ce13f7SAndroid Build Coastguard Worker if cppfilt and ident.startswith('_Z'): 98*03ce13f7SAndroid Build Coastguard Worker # Demangle names when possible. Mangled names all start with _Z. 99*03ce13f7SAndroid Build Coastguard Worker ident = subprocess.check_output([cppfilt, ident]).strip() 100*03ce13f7SAndroid Build Coastguard Worker return ident 101*03ce13f7SAndroid Build Coastguard Worker 102*03ce13f7SAndroid Build Coastguard Worker 103*03ce13f7SAndroid Build Coastguard Workerclass Suffix: 104*03ce13f7SAndroid Build Coastguard Worker def __init__(self, suffix, replacement): 105*03ce13f7SAndroid Build Coastguard Worker self.pattern = '^(.*)' + suffix + '(.*)$' 106*03ce13f7SAndroid Build Coastguard Worker self.re = re.compile(self.pattern) 107*03ce13f7SAndroid Build Coastguard Worker self.replacement = replacement 108*03ce13f7SAndroid Build Coastguard Worker 109*03ce13f7SAndroid Build Coastguard Workerclass SuffixCleanup: 110*03ce13f7SAndroid Build Coastguard Worker """Pre-compile suffix regular expressions.""" 111*03ce13f7SAndroid Build Coastguard Worker def __init__(self): 112*03ce13f7SAndroid Build Coastguard Worker self.suffixes = [ 113*03ce13f7SAndroid Build Coastguard Worker Suffix('\.part\.([0-9]+)', 'part'), 114*03ce13f7SAndroid Build Coastguard Worker Suffix('\.constprop\.([0-9]+)', 'constprop'), 115*03ce13f7SAndroid Build Coastguard Worker Suffix('\.isra\.([0-9]+)', 'isra'), 116*03ce13f7SAndroid Build Coastguard Worker ] 117*03ce13f7SAndroid Build Coastguard Worker def cleanup(self, ident, cppfilt): 118*03ce13f7SAndroid Build Coastguard Worker """Cleanup identifiers that have suffixes preventing demangling, 119*03ce13f7SAndroid Build Coastguard Worker and demangle if possible.""" 120*03ce13f7SAndroid Build Coastguard Worker to_append = [] 121*03ce13f7SAndroid Build Coastguard Worker for s in self.suffixes: 122*03ce13f7SAndroid Build Coastguard Worker found = s.re.match(ident) 123*03ce13f7SAndroid Build Coastguard Worker if not found: 124*03ce13f7SAndroid Build Coastguard Worker continue 125*03ce13f7SAndroid Build Coastguard Worker to_append += [' [' + s.replacement + '.' + found.group(2) + ']'] 126*03ce13f7SAndroid Build Coastguard Worker ident = found.group(1) + found.group(3) 127*03ce13f7SAndroid Build Coastguard Worker if len(to_append) > 0: 128*03ce13f7SAndroid Build Coastguard Worker # Only try to demangle if there were suffixes. 129*03ce13f7SAndroid Build Coastguard Worker ident = demangle(ident, cppfilt) 130*03ce13f7SAndroid Build Coastguard Worker for s in to_append: 131*03ce13f7SAndroid Build Coastguard Worker ident += s 132*03ce13f7SAndroid Build Coastguard Worker return ident 133*03ce13f7SAndroid Build Coastguard Worker 134*03ce13f7SAndroid Build Coastguard Workersuffix_cleanup = SuffixCleanup() 135*03ce13f7SAndroid Build Coastguard Worker 136*03ce13f7SAndroid Build Coastguard Workerdef parse_cpp_name(name, cppfilt): 137*03ce13f7SAndroid Build Coastguard Worker name = suffix_cleanup.cleanup(name, cppfilt) 138*03ce13f7SAndroid Build Coastguard Worker 139*03ce13f7SAndroid Build Coastguard Worker # Turn prefixes into suffixes so namespacing works. 140*03ce13f7SAndroid Build Coastguard Worker prefixes = [ 141*03ce13f7SAndroid Build Coastguard Worker ['bool ', ''], 142*03ce13f7SAndroid Build Coastguard Worker ['construction vtable for ', ' [construction vtable]'], 143*03ce13f7SAndroid Build Coastguard Worker ['global constructors keyed to ', ' [global constructors]'], 144*03ce13f7SAndroid Build Coastguard Worker ['guard variable for ', ' [guard variable]'], 145*03ce13f7SAndroid Build Coastguard Worker ['int ', ''], 146*03ce13f7SAndroid Build Coastguard Worker ['non-virtual thunk to ', ' [non-virtual thunk]'], 147*03ce13f7SAndroid Build Coastguard Worker ['typeinfo for ', ' [typeinfo]'], 148*03ce13f7SAndroid Build Coastguard Worker ['typeinfo name for ', ' [typeinfo name]'], 149*03ce13f7SAndroid Build Coastguard Worker ['virtual thunk to ', ' [virtual thunk]'], 150*03ce13f7SAndroid Build Coastguard Worker ['void ', ''], 151*03ce13f7SAndroid Build Coastguard Worker ['vtable for ', ' [vtable]'], 152*03ce13f7SAndroid Build Coastguard Worker ['VTT for ', ' [VTT]'], 153*03ce13f7SAndroid Build Coastguard Worker ] 154*03ce13f7SAndroid Build Coastguard Worker for prefix, replacement in prefixes: 155*03ce13f7SAndroid Build Coastguard Worker if name.startswith(prefix): 156*03ce13f7SAndroid Build Coastguard Worker name = name[len(prefix):] + replacement 157*03ce13f7SAndroid Build Coastguard Worker # Simplify parenthesis parsing. 158*03ce13f7SAndroid Build Coastguard Worker replacements = [ 159*03ce13f7SAndroid Build Coastguard Worker ['(anonymous namespace)', '[anonymous namespace]'], 160*03ce13f7SAndroid Build Coastguard Worker ] 161*03ce13f7SAndroid Build Coastguard Worker for value, replacement in replacements: 162*03ce13f7SAndroid Build Coastguard Worker name = name.replace(value, replacement) 163*03ce13f7SAndroid Build Coastguard Worker 164*03ce13f7SAndroid Build Coastguard Worker def parse_one(val): 165*03ce13f7SAndroid Build Coastguard Worker """Returns (leftmost-part, remaining).""" 166*03ce13f7SAndroid Build Coastguard Worker if (val.startswith('operator') and 167*03ce13f7SAndroid Build Coastguard Worker not (val[8].isalnum() or val[8] == '_')): 168*03ce13f7SAndroid Build Coastguard Worker # Operator overload function, terminate. 169*03ce13f7SAndroid Build Coastguard Worker return (val, '') 170*03ce13f7SAndroid Build Coastguard Worker co = val.find('::') 171*03ce13f7SAndroid Build Coastguard Worker lt = val.find('<') 172*03ce13f7SAndroid Build Coastguard Worker pa = val.find('(') 173*03ce13f7SAndroid Build Coastguard Worker co = len(val) if co == -1 else co 174*03ce13f7SAndroid Build Coastguard Worker lt = len(val) if lt == -1 else lt 175*03ce13f7SAndroid Build Coastguard Worker pa = len(val) if pa == -1 else pa 176*03ce13f7SAndroid Build Coastguard Worker if co < lt and co < pa: 177*03ce13f7SAndroid Build Coastguard Worker # Namespace or type name. 178*03ce13f7SAndroid Build Coastguard Worker return (val[:co], val[co+2:]) 179*03ce13f7SAndroid Build Coastguard Worker if lt < pa: 180*03ce13f7SAndroid Build Coastguard Worker # Template. Make sure we capture nested templates too. 181*03ce13f7SAndroid Build Coastguard Worker open_tmpl = 1 182*03ce13f7SAndroid Build Coastguard Worker gt = lt 183*03ce13f7SAndroid Build Coastguard Worker while val[gt] != '>' or open_tmpl != 0: 184*03ce13f7SAndroid Build Coastguard Worker gt = gt + 1 185*03ce13f7SAndroid Build Coastguard Worker if val[gt] == '<': 186*03ce13f7SAndroid Build Coastguard Worker open_tmpl = open_tmpl + 1 187*03ce13f7SAndroid Build Coastguard Worker if val[gt] == '>': 188*03ce13f7SAndroid Build Coastguard Worker open_tmpl = open_tmpl - 1 189*03ce13f7SAndroid Build Coastguard Worker ret = val[gt+1:] 190*03ce13f7SAndroid Build Coastguard Worker if ret.startswith('::'): 191*03ce13f7SAndroid Build Coastguard Worker ret = ret[2:] 192*03ce13f7SAndroid Build Coastguard Worker if ret.startswith('('): 193*03ce13f7SAndroid Build Coastguard Worker # Template function, terminate. 194*03ce13f7SAndroid Build Coastguard Worker return (val, '') 195*03ce13f7SAndroid Build Coastguard Worker return (val[:gt+1], ret) 196*03ce13f7SAndroid Build Coastguard Worker # Terminate with any function name, identifier, or unmangled name. 197*03ce13f7SAndroid Build Coastguard Worker return (val, '') 198*03ce13f7SAndroid Build Coastguard Worker 199*03ce13f7SAndroid Build Coastguard Worker parts = [] 200*03ce13f7SAndroid Build Coastguard Worker while len(name) > 0: 201*03ce13f7SAndroid Build Coastguard Worker (part, name) = parse_one(name) 202*03ce13f7SAndroid Build Coastguard Worker assert len(part) > 0 203*03ce13f7SAndroid Build Coastguard Worker parts.append(part) 204*03ce13f7SAndroid Build Coastguard Worker return parts 205*03ce13f7SAndroid Build Coastguard Worker 206*03ce13f7SAndroid Build Coastguard Worker 207*03ce13f7SAndroid Build Coastguard Workerdef treeify_syms(symbols, strip_prefix=None, cppfilt=None): 208*03ce13f7SAndroid Build Coastguard Worker dirs = {} 209*03ce13f7SAndroid Build Coastguard Worker for sym, type, size, path in symbols: 210*03ce13f7SAndroid Build Coastguard Worker if path: 211*03ce13f7SAndroid Build Coastguard Worker path = os.path.normpath(path) 212*03ce13f7SAndroid Build Coastguard Worker if strip_prefix and path.startswith(strip_prefix): 213*03ce13f7SAndroid Build Coastguard Worker path = path[len(strip_prefix):] 214*03ce13f7SAndroid Build Coastguard Worker elif path.startswith('/'): 215*03ce13f7SAndroid Build Coastguard Worker path = path[1:] 216*03ce13f7SAndroid Build Coastguard Worker path = ['[path]'] + path.split('/') 217*03ce13f7SAndroid Build Coastguard Worker 218*03ce13f7SAndroid Build Coastguard Worker parts = parse_cpp_name(sym, cppfilt) 219*03ce13f7SAndroid Build Coastguard Worker if len(parts) == 1: 220*03ce13f7SAndroid Build Coastguard Worker if path: 221*03ce13f7SAndroid Build Coastguard Worker # No namespaces, group with path. 222*03ce13f7SAndroid Build Coastguard Worker parts = path + parts 223*03ce13f7SAndroid Build Coastguard Worker else: 224*03ce13f7SAndroid Build Coastguard Worker new_prefix = ['[ungrouped]'] 225*03ce13f7SAndroid Build Coastguard Worker regroups = [ 226*03ce13f7SAndroid Build Coastguard Worker ['.L.str', '[str]'], 227*03ce13f7SAndroid Build Coastguard Worker ['.L__PRETTY_FUNCTION__.', '[__PRETTY_FUNCTION__]'], 228*03ce13f7SAndroid Build Coastguard Worker ['.L__func__.', '[__func__]'], 229*03ce13f7SAndroid Build Coastguard Worker ['.Lswitch.table', '[switch table]'], 230*03ce13f7SAndroid Build Coastguard Worker ] 231*03ce13f7SAndroid Build Coastguard Worker for prefix, group in regroups: 232*03ce13f7SAndroid Build Coastguard Worker if parts[0].startswith(prefix): 233*03ce13f7SAndroid Build Coastguard Worker parts[0] = parts[0][len(prefix):] 234*03ce13f7SAndroid Build Coastguard Worker parts[0] = demangle(parts[0], cppfilt) 235*03ce13f7SAndroid Build Coastguard Worker new_prefix += [group] 236*03ce13f7SAndroid Build Coastguard Worker break 237*03ce13f7SAndroid Build Coastguard Worker parts = new_prefix + parts 238*03ce13f7SAndroid Build Coastguard Worker 239*03ce13f7SAndroid Build Coastguard Worker key = parts.pop() 240*03ce13f7SAndroid Build Coastguard Worker tree = dirs 241*03ce13f7SAndroid Build Coastguard Worker try: 242*03ce13f7SAndroid Build Coastguard Worker depth = 0 243*03ce13f7SAndroid Build Coastguard Worker for part in parts: 244*03ce13f7SAndroid Build Coastguard Worker depth = depth + 1 245*03ce13f7SAndroid Build Coastguard Worker assert part != '', path 246*03ce13f7SAndroid Build Coastguard Worker if part not in tree: 247*03ce13f7SAndroid Build Coastguard Worker tree[part] = {'$bloat_symbols':{}} 248*03ce13f7SAndroid Build Coastguard Worker if type not in tree[part]['$bloat_symbols']: 249*03ce13f7SAndroid Build Coastguard Worker tree[part]['$bloat_symbols'][type] = 0 250*03ce13f7SAndroid Build Coastguard Worker tree[part]['$bloat_symbols'][type] += 1 251*03ce13f7SAndroid Build Coastguard Worker tree = tree[part] 252*03ce13f7SAndroid Build Coastguard Worker old_size, old_symbols = tree.get(key, (0, {})) 253*03ce13f7SAndroid Build Coastguard Worker if type not in old_symbols: 254*03ce13f7SAndroid Build Coastguard Worker old_symbols[type] = 0 255*03ce13f7SAndroid Build Coastguard Worker old_symbols[type] += 1 256*03ce13f7SAndroid Build Coastguard Worker tree[key] = (old_size + size, old_symbols) 257*03ce13f7SAndroid Build Coastguard Worker except: 258*03ce13f7SAndroid Build Coastguard Worker print >>sys.stderr, 'sym `%s`\tparts `%s`\tkey `%s`' % (sym, parts, key) 259*03ce13f7SAndroid Build Coastguard Worker raise 260*03ce13f7SAndroid Build Coastguard Worker return dirs 261*03ce13f7SAndroid Build Coastguard Worker 262*03ce13f7SAndroid Build Coastguard Worker 263*03ce13f7SAndroid Build Coastguard Workerdef jsonify_tree(tree, name): 264*03ce13f7SAndroid Build Coastguard Worker children = [] 265*03ce13f7SAndroid Build Coastguard Worker total = 0 266*03ce13f7SAndroid Build Coastguard Worker files = 0 267*03ce13f7SAndroid Build Coastguard Worker 268*03ce13f7SAndroid Build Coastguard Worker for key, val in tree.iteritems(): 269*03ce13f7SAndroid Build Coastguard Worker if key == '$bloat_symbols': 270*03ce13f7SAndroid Build Coastguard Worker continue 271*03ce13f7SAndroid Build Coastguard Worker if isinstance(val, dict): 272*03ce13f7SAndroid Build Coastguard Worker subtree = jsonify_tree(val, key) 273*03ce13f7SAndroid Build Coastguard Worker total += subtree['data']['$area'] 274*03ce13f7SAndroid Build Coastguard Worker children.append(subtree) 275*03ce13f7SAndroid Build Coastguard Worker else: 276*03ce13f7SAndroid Build Coastguard Worker (size, symbols) = val 277*03ce13f7SAndroid Build Coastguard Worker total += size 278*03ce13f7SAndroid Build Coastguard Worker assert len(symbols) == 1, symbols.values()[0] == 1 279*03ce13f7SAndroid Build Coastguard Worker symbol = symbol_type_to_human(symbols.keys()[0]) 280*03ce13f7SAndroid Build Coastguard Worker children.append({ 281*03ce13f7SAndroid Build Coastguard Worker 'name': key + ' ' + format_bytes(size), 282*03ce13f7SAndroid Build Coastguard Worker 'data': { 283*03ce13f7SAndroid Build Coastguard Worker '$area': size, 284*03ce13f7SAndroid Build Coastguard Worker '$symbol': symbol, 285*03ce13f7SAndroid Build Coastguard Worker } 286*03ce13f7SAndroid Build Coastguard Worker }) 287*03ce13f7SAndroid Build Coastguard Worker 288*03ce13f7SAndroid Build Coastguard Worker children.sort(key=lambda child: -child['data']['$area']) 289*03ce13f7SAndroid Build Coastguard Worker dominant_symbol = '' 290*03ce13f7SAndroid Build Coastguard Worker if '$bloat_symbols' in tree: 291*03ce13f7SAndroid Build Coastguard Worker dominant_symbol = symbol_type_to_human( 292*03ce13f7SAndroid Build Coastguard Worker max(tree['$bloat_symbols'].iteritems(), 293*03ce13f7SAndroid Build Coastguard Worker key=operator.itemgetter(1))[0]) 294*03ce13f7SAndroid Build Coastguard Worker return { 295*03ce13f7SAndroid Build Coastguard Worker 'name': name + ' ' + format_bytes(total), 296*03ce13f7SAndroid Build Coastguard Worker 'data': { 297*03ce13f7SAndroid Build Coastguard Worker '$area': total, 298*03ce13f7SAndroid Build Coastguard Worker '$dominant_symbol': dominant_symbol, 299*03ce13f7SAndroid Build Coastguard Worker }, 300*03ce13f7SAndroid Build Coastguard Worker 'children': children, 301*03ce13f7SAndroid Build Coastguard Worker } 302*03ce13f7SAndroid Build Coastguard Worker 303*03ce13f7SAndroid Build Coastguard Worker 304*03ce13f7SAndroid Build Coastguard Workerdef dump_nm(nmfile, strip_prefix, cppfilt): 305*03ce13f7SAndroid Build Coastguard Worker dirs = treeify_syms(parse_nm(nmfile), strip_prefix, cppfilt) 306*03ce13f7SAndroid Build Coastguard Worker print ('var kTree = ' + 307*03ce13f7SAndroid Build Coastguard Worker json.dumps(jsonify_tree(dirs, '[everything]'), indent=2)) 308*03ce13f7SAndroid Build Coastguard Worker 309*03ce13f7SAndroid Build Coastguard Worker 310*03ce13f7SAndroid Build Coastguard Workerdef parse_objdump(input): 311*03ce13f7SAndroid Build Coastguard Worker """Parse objdump -h output.""" 312*03ce13f7SAndroid Build Coastguard Worker sec_re = re.compile('^\d+ (\S+) +([0-9a-z]+)') 313*03ce13f7SAndroid Build Coastguard Worker sections = [] 314*03ce13f7SAndroid Build Coastguard Worker debug_sections = [] 315*03ce13f7SAndroid Build Coastguard Worker 316*03ce13f7SAndroid Build Coastguard Worker for line in input: 317*03ce13f7SAndroid Build Coastguard Worker line = line.strip() 318*03ce13f7SAndroid Build Coastguard Worker match = sec_re.match(line) 319*03ce13f7SAndroid Build Coastguard Worker if match: 320*03ce13f7SAndroid Build Coastguard Worker name, size = match.groups() 321*03ce13f7SAndroid Build Coastguard Worker if name.startswith('.'): 322*03ce13f7SAndroid Build Coastguard Worker name = name[1:] 323*03ce13f7SAndroid Build Coastguard Worker if name.startswith('debug_'): 324*03ce13f7SAndroid Build Coastguard Worker name = name[len('debug_'):] 325*03ce13f7SAndroid Build Coastguard Worker debug_sections.append((name, int(size, 16))) 326*03ce13f7SAndroid Build Coastguard Worker else: 327*03ce13f7SAndroid Build Coastguard Worker sections.append((name, int(size, 16))) 328*03ce13f7SAndroid Build Coastguard Worker continue 329*03ce13f7SAndroid Build Coastguard Worker return sections, debug_sections 330*03ce13f7SAndroid Build Coastguard Worker 331*03ce13f7SAndroid Build Coastguard Worker 332*03ce13f7SAndroid Build Coastguard Workerdef jsonify_sections(name, sections): 333*03ce13f7SAndroid Build Coastguard Worker children = [] 334*03ce13f7SAndroid Build Coastguard Worker total = 0 335*03ce13f7SAndroid Build Coastguard Worker for section, size in sections: 336*03ce13f7SAndroid Build Coastguard Worker children.append({ 337*03ce13f7SAndroid Build Coastguard Worker 'name': section + ' ' + format_bytes(size), 338*03ce13f7SAndroid Build Coastguard Worker 'data': { '$area': size } 339*03ce13f7SAndroid Build Coastguard Worker }) 340*03ce13f7SAndroid Build Coastguard Worker total += size 341*03ce13f7SAndroid Build Coastguard Worker 342*03ce13f7SAndroid Build Coastguard Worker children.sort(key=lambda child: -child['data']['$area']) 343*03ce13f7SAndroid Build Coastguard Worker 344*03ce13f7SAndroid Build Coastguard Worker return { 345*03ce13f7SAndroid Build Coastguard Worker 'name': name + ' ' + format_bytes(total), 346*03ce13f7SAndroid Build Coastguard Worker 'data': { '$area': total }, 347*03ce13f7SAndroid Build Coastguard Worker 'children': children 348*03ce13f7SAndroid Build Coastguard Worker } 349*03ce13f7SAndroid Build Coastguard Worker 350*03ce13f7SAndroid Build Coastguard Worker 351*03ce13f7SAndroid Build Coastguard Workerdef dump_sections(objdump): 352*03ce13f7SAndroid Build Coastguard Worker sections, debug_sections = parse_objdump(objdump) 353*03ce13f7SAndroid Build Coastguard Worker sections = jsonify_sections('sections', sections) 354*03ce13f7SAndroid Build Coastguard Worker debug_sections = jsonify_sections('debug', debug_sections) 355*03ce13f7SAndroid Build Coastguard Worker size = sections['data']['$area'] + debug_sections['data']['$area'] 356*03ce13f7SAndroid Build Coastguard Worker print 'var kTree = ' + json.dumps({ 357*03ce13f7SAndroid Build Coastguard Worker 'name': 'top ' + format_bytes(size), 358*03ce13f7SAndroid Build Coastguard Worker 'data': { '$area': size }, 359*03ce13f7SAndroid Build Coastguard Worker 'children': [ debug_sections, sections ]}) 360*03ce13f7SAndroid Build Coastguard Worker 361*03ce13f7SAndroid Build Coastguard Worker 362*03ce13f7SAndroid Build Coastguard Workerusage="""%prog [options] MODE 363*03ce13f7SAndroid Build Coastguard Worker 364*03ce13f7SAndroid Build Coastguard WorkerModes are: 365*03ce13f7SAndroid Build Coastguard Worker syms: output symbols json suitable for a treemap 366*03ce13f7SAndroid Build Coastguard Worker dump: print symbols sorted by size (pipe to head for best output) 367*03ce13f7SAndroid Build Coastguard Worker sections: output binary sections json suitable for a treemap 368*03ce13f7SAndroid Build Coastguard Worker 369*03ce13f7SAndroid Build Coastguard Workernm output passed to --nm-output should from running a command 370*03ce13f7SAndroid Build Coastguard Workerlike the following (note, can take a long time -- 30 minutes): 371*03ce13f7SAndroid Build Coastguard Worker nm -C -S -l /path/to/binary > nm.out 372*03ce13f7SAndroid Build Coastguard Worker 373*03ce13f7SAndroid Build Coastguard Workerobjdump output passed to --objdump-output should be from a command 374*03ce13f7SAndroid Build Coastguard Workerlike: 375*03ce13f7SAndroid Build Coastguard Worker objdump -h /path/to/binary > objdump.out""" 376*03ce13f7SAndroid Build Coastguard Workerparser = optparse.OptionParser(usage=usage) 377*03ce13f7SAndroid Build Coastguard Workerparser.add_option('--nm-output', action='store', dest='nmpath', 378*03ce13f7SAndroid Build Coastguard Worker metavar='PATH', default='nm.out', 379*03ce13f7SAndroid Build Coastguard Worker help='path to nm output [default=nm.out]') 380*03ce13f7SAndroid Build Coastguard Workerparser.add_option('--objdump-output', action='store', dest='objdumppath', 381*03ce13f7SAndroid Build Coastguard Worker metavar='PATH', default='objdump.out', 382*03ce13f7SAndroid Build Coastguard Worker help='path to objdump output [default=objdump.out]') 383*03ce13f7SAndroid Build Coastguard Workerparser.add_option('--strip-prefix', metavar='PATH', action='store', 384*03ce13f7SAndroid Build Coastguard Worker help='strip PATH prefix from paths; e.g. /path/to/src/root') 385*03ce13f7SAndroid Build Coastguard Workerparser.add_option('--filter', action='store', 386*03ce13f7SAndroid Build Coastguard Worker help='include only symbols/files matching FILTER') 387*03ce13f7SAndroid Build Coastguard Workerparser.add_option('--c++filt', action='store', metavar='PATH', dest='cppfilt', 388*03ce13f7SAndroid Build Coastguard Worker default='c++filt', help="Path to c++filt, used to demangle " 389*03ce13f7SAndroid Build Coastguard Worker "symbols that weren't handled by nm. Set to an invalid path " 390*03ce13f7SAndroid Build Coastguard Worker "to disable.") 391*03ce13f7SAndroid Build Coastguard Workeropts, args = parser.parse_args() 392*03ce13f7SAndroid Build Coastguard Worker 393*03ce13f7SAndroid Build Coastguard Workerif len(args) != 1: 394*03ce13f7SAndroid Build Coastguard Worker parser.print_usage() 395*03ce13f7SAndroid Build Coastguard Worker sys.exit(1) 396*03ce13f7SAndroid Build Coastguard Worker 397*03ce13f7SAndroid Build Coastguard Workermode = args[0] 398*03ce13f7SAndroid Build Coastguard Workerif mode == 'syms': 399*03ce13f7SAndroid Build Coastguard Worker nmfile = open(opts.nmpath, 'r') 400*03ce13f7SAndroid Build Coastguard Worker try: 401*03ce13f7SAndroid Build Coastguard Worker res = subprocess.check_output([opts.cppfilt, 'main']) 402*03ce13f7SAndroid Build Coastguard Worker if res.strip() != 'main': 403*03ce13f7SAndroid Build Coastguard Worker print >>sys.stderr, ("%s failed demangling, " 404*03ce13f7SAndroid Build Coastguard Worker "output won't be demangled." % opt.cppfilt) 405*03ce13f7SAndroid Build Coastguard Worker opts.cppfilt = None 406*03ce13f7SAndroid Build Coastguard Worker except: 407*03ce13f7SAndroid Build Coastguard Worker print >>sys.stderr, ("Could not find c++filt at %s, " 408*03ce13f7SAndroid Build Coastguard Worker "output won't be demangled." % opt.cppfilt) 409*03ce13f7SAndroid Build Coastguard Worker opts.cppfilt = None 410*03ce13f7SAndroid Build Coastguard Worker dump_nm(nmfile, strip_prefix=opts.strip_prefix, cppfilt=opts.cppfilt) 411*03ce13f7SAndroid Build Coastguard Workerelif mode == 'sections': 412*03ce13f7SAndroid Build Coastguard Worker objdumpfile = open(opts.objdumppath, 'r') 413*03ce13f7SAndroid Build Coastguard Worker dump_sections(objdumpfile) 414*03ce13f7SAndroid Build Coastguard Workerelif mode == 'dump': 415*03ce13f7SAndroid Build Coastguard Worker nmfile = open(opts.nmpath, 'r') 416*03ce13f7SAndroid Build Coastguard Worker syms = list(parse_nm(nmfile)) 417*03ce13f7SAndroid Build Coastguard Worker # a list of (sym, type, size, path); sort by size. 418*03ce13f7SAndroid Build Coastguard Worker syms.sort(key=lambda x: -x[2]) 419*03ce13f7SAndroid Build Coastguard Worker total = 0 420*03ce13f7SAndroid Build Coastguard Worker for sym, type, size, path in syms: 421*03ce13f7SAndroid Build Coastguard Worker if type in ('b', 'w'): 422*03ce13f7SAndroid Build Coastguard Worker continue # skip bss and weak symbols 423*03ce13f7SAndroid Build Coastguard Worker if path is None: 424*03ce13f7SAndroid Build Coastguard Worker path = '' 425*03ce13f7SAndroid Build Coastguard Worker if opts.filter and not (opts.filter in sym or opts.filter in path): 426*03ce13f7SAndroid Build Coastguard Worker continue 427*03ce13f7SAndroid Build Coastguard Worker print '%6s %s (%s) %s' % (format_bytes(size), sym, 428*03ce13f7SAndroid Build Coastguard Worker symbol_type_to_human(type), path) 429*03ce13f7SAndroid Build Coastguard Worker total += size 430*03ce13f7SAndroid Build Coastguard Worker print '%6s %s' % (format_bytes(total), 'total'), 431*03ce13f7SAndroid Build Coastguard Workerelse: 432*03ce13f7SAndroid Build Coastguard Worker print 'unknown mode' 433*03ce13f7SAndroid Build Coastguard Worker parser.print_usage() 434