1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#!/usr/bin/python
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# found in the LICENSE file.
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import commands
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import os
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import sys
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)orderfile = sys.argv[1]
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)uninstrumented_shlib = sys.argv[2]
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)nmlines_uninstrumented = commands.getoutput ('nm -S -n ' +
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   uninstrumented_shlib + '  | egrep "( t )|( W )|( T )"').split('\n')
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)nmlines = []
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)for nmline in nmlines_uninstrumented:
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (len(nmline.split()) == 4):
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    nmlines.append(nmline)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# Map addresses to list of functions at that address.  There are multiple
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# functions at an address because of aliasing.
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)nm_index = 0
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)uniqueAddrs = []
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)addressMap = {}
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)while nm_index < len(nmlines):
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (len(nmlines[nm_index].split()) == 4):
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    nm_int = int (nmlines[nm_index].split()[0], 16)
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size = int (nmlines[nm_index].split()[1], 16)
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    fnames = [nmlines[nm_index].split()[3]]
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    nm_index = nm_index + 1
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    while nm_index < len(nmlines) and nm_int == int (
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        nmlines[nm_index].split()[0], 16):
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      fnames.append(nmlines[nm_index].split()[3])
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      nm_index = nm_index + 1
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    addressMap[nm_int] = fnames
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    uniqueAddrs.append((nm_int, size))
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  else:
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    nm_index = nm_index + 1
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)def binary_search (addr, start, end):
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if start >= end or start == end - 1:
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (nm_addr, size) = uniqueAddrs[start]
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if not (addr >= nm_addr and addr < nm_addr + size):
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sys.stderr.write ("ERROR: did not find function in binary: addr: " +
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          hex(addr) + " nm_addr: " + str(nm_addr) + " start: " + str(start) +
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          " end: " + str(end) + "\n")
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      raise Error("error")
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return (addressMap[nm_addr], size)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  else:
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    halfway = start + ((end - start) / 2)
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (nm_addr, size) = uniqueAddrs[halfway]
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (addr >= nm_addr and addr < nm_addr + size):
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return (addressMap[nm_addr], size)
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    elif (addr < nm_addr):
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return binary_search (addr, start, halfway)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    elif (addr >= nm_addr + size):
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return binary_search (addr, halfway, end)
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    else:
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      raise "ERROR: did not expect this case"
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)f = open (orderfile)
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)lines = f.readlines()
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)profiled_list = []
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)for line in lines:
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (line.strip() == ''):
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    continue
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  functionName = line.replace('.text.', '').split('.clone.')[0].strip()
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  profiled_list.append (functionName)
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# Symbol names are not unique.  Since the order file uses symbol names, the
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# patched order file pulls in all symbols with the same name.  Multiple function
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# addresses for the same function name may also be due to ".clone" symbols,
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)# since the substring is stripped.
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)functions = []
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)functionAddressMap = {}
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)for line in nmlines:
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  try:
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    functionName = line.split()[3]
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  except:
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    functionName = line.split()[2]
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  functionName = functionName.split('.clone.')[0]
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  functionAddress = int (line.split()[0].strip(), 16)
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  try:
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    functionAddressMap[functionName].append(functionAddress)
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  except:
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    functionAddressMap[functionName] = [functionAddress]
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    functions.append(functionName)
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)sys.stderr.write ("profiled list size: " + str(len(profiled_list)) + "\n")
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)addresses = []
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)symbols_found = 0
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)for function in profiled_list:
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   try:
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     addrs = functionAddressMap[function]
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     symbols_found = symbols_found + 1
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   except:
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     addrs = []
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     # sys.stderr.write ("WARNING: could not find symbol " + function + "\n")
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   for addr in addrs:
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     if not (addr in addresses):
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       addresses.append(addr)
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)sys.stderr.write ("symbols found: " + str(symbols_found) + "\n")
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)sys.stderr.write ("number of addresses: " + str(len(addresses)) + "\n")
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)total_size = 0
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)for addr in addresses:
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  (functions, size) = binary_search (addr, 0, len(uniqueAddrs))
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  total_size = total_size + size
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  prefixes = ['.text.', '.text.startup.', '.text.hot.', '.text.unlikely.']
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for function in functions:
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for prefix in prefixes:
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      print prefix + function
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# The following is needed otherwise Gold only applies a partial sort.
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)print '.text.*'
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)sys.stderr.write ("total_size: " + str(total_size) + "\n")
118