#!/usr/bin/python # Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import commands import os import sys orderfile = sys.argv[1] uninstrumented_shlib = sys.argv[2] nmlines_uninstrumented = commands.getoutput ('nm -S -n ' + uninstrumented_shlib + ' | egrep "( t )|( W )|( T )"').split('\n') nmlines = [] for nmline in nmlines_uninstrumented: if (len(nmline.split()) == 4): nmlines.append(nmline) # Map addresses to list of functions at that address. There are multiple # functions at an address because of aliasing. nm_index = 0 uniqueAddrs = [] addressMap = {} while nm_index < len(nmlines): if (len(nmlines[nm_index].split()) == 4): nm_int = int (nmlines[nm_index].split()[0], 16) size = int (nmlines[nm_index].split()[1], 16) fnames = [nmlines[nm_index].split()[3]] nm_index = nm_index + 1 while nm_index < len(nmlines) and nm_int == int ( nmlines[nm_index].split()[0], 16): fnames.append(nmlines[nm_index].split()[3]) nm_index = nm_index + 1 addressMap[nm_int] = fnames uniqueAddrs.append((nm_int, size)) else: nm_index = nm_index + 1 def binary_search (addr, start, end): if start >= end or start == end - 1: (nm_addr, size) = uniqueAddrs[start] if not (addr >= nm_addr and addr < nm_addr + size): sys.stderr.write ("ERROR: did not find function in binary: addr: " + hex(addr) + " nm_addr: " + str(nm_addr) + " start: " + str(start) + " end: " + str(end) + "\n") raise Error("error") return (addressMap[nm_addr], size) else: halfway = start + ((end - start) / 2) (nm_addr, size) = uniqueAddrs[halfway] if (addr >= nm_addr and addr < nm_addr + size): return (addressMap[nm_addr], size) elif (addr < nm_addr): return binary_search (addr, start, halfway) elif (addr >= nm_addr + size): return binary_search (addr, halfway, end) else: raise "ERROR: did not expect this case" f = open (orderfile) lines = f.readlines() profiled_list = [] for line in lines: if (line.strip() == ''): continue functionName = line.replace('.text.', '').split('.clone.')[0].strip() profiled_list.append (functionName) # Symbol names are not unique. Since the order file uses symbol names, the # patched order file pulls in all symbols with the same name. Multiple function # addresses for the same function name may also be due to ".clone" symbols, # since the substring is stripped. functions = [] functionAddressMap = {} for line in nmlines: try: functionName = line.split()[3] except: functionName = line.split()[2] functionName = functionName.split('.clone.')[0] functionAddress = int (line.split()[0].strip(), 16) try: functionAddressMap[functionName].append(functionAddress) except: functionAddressMap[functionName] = [functionAddress] functions.append(functionName) sys.stderr.write ("profiled list size: " + str(len(profiled_list)) + "\n") addresses = [] symbols_found = 0 for function in profiled_list: try: addrs = functionAddressMap[function] symbols_found = symbols_found + 1 except: addrs = [] # sys.stderr.write ("WARNING: could not find symbol " + function + "\n") for addr in addrs: if not (addr in addresses): addresses.append(addr) sys.stderr.write ("symbols found: " + str(symbols_found) + "\n") sys.stderr.write ("number of addresses: " + str(len(addresses)) + "\n") total_size = 0 for addr in addresses: (functions, size) = binary_search (addr, 0, len(uniqueAddrs)) total_size = total_size + size prefixes = ['.text.', '.text.startup.', '.text.hot.', '.text.unlikely.'] for function in functions: for prefix in prefixes: print prefix + function # The following is needed otherwise Gold only applies a partial sort. print '.text.*' sys.stderr.write ("total_size: " + str(total_size) + "\n")