Add scripts for using cygprofile to repository
These scripts, which are used to create a link order file for Linux based builds (Linux, Android, ChromeOS). This commit simply moves them from a Google private web page where they have lived for the last couple of years. The scripts are: mergetraces.py - merge multiple cygprofile traces into a single trace symbolise.py - convert traces into an order file with symbols patch_orderfile.py - complete the order file with symbols from Chrome. I will seperately add a page on creating an order file to the Chromium web site. Review URL: https://chromiumcodereview.appspot.com/16151006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203143 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
tools/cygprofile
186
tools/cygprofile/mergetraces.py
Executable file
186
tools/cygprofile/mergetraces.py
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/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.
|
||||
|
||||
# Use: ../mergetraces.py `ls cyglog.* -Sr` > merged_cyglog
|
||||
|
||||
""""Merge multiple logs files from different processes into a single log.
|
||||
|
||||
Given two log files of execution traces, merge the traces into a single trace.
|
||||
Merging will use timestamps (i.e. the first two columns of logged calls) to
|
||||
create a single log that is an ordered trace of calls by both processes.
|
||||
"""
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def ParseLogLines(lines):
|
||||
"""Parse log file lines.
|
||||
|
||||
Args:
|
||||
lines: lines from log file produced by profiled run
|
||||
|
||||
Below is an example of a small log file:
|
||||
5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
|
||||
secs msecs pid:threadid func
|
||||
START
|
||||
1314897086 795828 3587:1074648168 0x509e105c
|
||||
1314897086 795874 3587:1074648168 0x509e0eb4
|
||||
1314897086 796326 3587:1074648168 0x509e0e3c
|
||||
1314897086 796552 3587:1074648168 0x509e07bc
|
||||
END
|
||||
|
||||
Returns:
|
||||
tuple conisiting of 1) an ordered list of the logged calls, as an array of
|
||||
fields, 2) the virtual start address of the library, used to compute the
|
||||
offset of the symbol in the library and 3) the virtual end address
|
||||
"""
|
||||
call_lines = []
|
||||
vm_start = 0
|
||||
vm_end = 0
|
||||
dash_index = lines[0].find ('-')
|
||||
space_index = lines[0].find (' ')
|
||||
vm_start = int (lines[0][:dash_index], 16)
|
||||
vm_end = int (lines[0][dash_index+1:space_index], 16)
|
||||
for line in lines[2:]:
|
||||
line = line.strip()
|
||||
# print hex (vm_start)
|
||||
fields = line.split()
|
||||
call_lines.append (fields)
|
||||
|
||||
return (call_lines, vm_start, vm_end)
|
||||
|
||||
def HasDuplicates(calls):
|
||||
"""Funcition is a sanity check to make sure that calls are only logged once.
|
||||
|
||||
Args:
|
||||
calls: list of calls logged
|
||||
|
||||
Returns:
|
||||
boolean indicating if calls has duplicate calls
|
||||
"""
|
||||
seen = []
|
||||
for call in calls:
|
||||
if call[3] in seen:
|
||||
return true
|
||||
else:
|
||||
seen.append(call[3])
|
||||
|
||||
def CheckTimestamps(calls):
|
||||
"""Prints warning to stderr if the call timestamps are not in order.
|
||||
|
||||
Args:
|
||||
calls: list of calls logged
|
||||
"""
|
||||
index = 0
|
||||
last_timestamp_secs = -1
|
||||
last_timestamp_ms = -1
|
||||
while (index < len (calls)):
|
||||
timestamp_secs = int (calls[index][0])
|
||||
timestamp_ms = int (calls[index][1])
|
||||
timestamp = (timestamp_secs * 1000000) + timestamp_ms
|
||||
last_timestamp = (last_timestamp_secs * 1000000) + last_timestamp_ms
|
||||
if (timestamp < last_timestamp):
|
||||
sys.stderr.write("WARNING: last_timestamp: " + str(last_timestamp_secs)
|
||||
+ " " + str(last_timestamp_ms) + " timestamp: "
|
||||
+ str(timestamp_secs) + " " + str(timestamp_ms) + "\n")
|
||||
last_timestamp_secs = timestamp_secs
|
||||
last_timestamp_ms = timestamp_ms
|
||||
index = index + 1
|
||||
|
||||
def Convert (call_lines, startAddr, endAddr):
|
||||
"""Converts the call addresses to static offsets and removes invalid calls.
|
||||
|
||||
Removes profiled calls not in shared library using start and end virtual
|
||||
addresses, converts strings to integer values, coverts virtual addresses to
|
||||
address in shared library.
|
||||
|
||||
Returns:
|
||||
list of calls as tuples (sec, msec, pid:tid, callee)
|
||||
"""
|
||||
converted_calls = []
|
||||
call_addresses = []
|
||||
for fields in call_lines:
|
||||
secs = int (fields[0])
|
||||
msecs = int (fields[1])
|
||||
callee = int (fields[3], 16)
|
||||
# print ("callee: " + hex (callee) + " start: " + hex (startAddr) + " end: "
|
||||
# + hex (endAddr))
|
||||
if (callee >= startAddr and callee < endAddr
|
||||
and (not callee in call_addresses)):
|
||||
converted_calls.append((secs, msecs, fields[2], (callee - startAddr)))
|
||||
call_addresses.append(callee)
|
||||
return converted_calls
|
||||
|
||||
def Timestamp(trace_entry):
|
||||
return int (trace_entry[0]) * 1000000 + int(trace_entry[1])
|
||||
|
||||
def AddTrace (tracemap, trace):
|
||||
"""Adds a trace to the tracemap.
|
||||
|
||||
Adds entries in the trace to the tracemap. All new calls will be added to
|
||||
the tracemap. If the calls already exist in the tracemap then they will be
|
||||
replaced if they happened sooner in the new trace.
|
||||
|
||||
Args:
|
||||
tracemap: the tracemap
|
||||
trace: the trace
|
||||
|
||||
"""
|
||||
for trace_entry in trace:
|
||||
call = trace_entry[3]
|
||||
if (not call in tracemap) or (
|
||||
Timestamp(tracemap[call]) > Timestamp(trace_entry)):
|
||||
tracemap[call] = trace_entry
|
||||
|
||||
def main():
|
||||
"""Merge two traces for code in specified library and write to stdout.
|
||||
|
||||
Merges the two traces and coverts the virtual addresses to the offsets in the
|
||||
library. First line of merged trace has dummy virtual address of 0-ffffffff
|
||||
so that symbolizing the addresses uses the addresses in the log, since the
|
||||
addresses have already been converted to static offsets.
|
||||
"""
|
||||
parser = optparse.OptionParser('usage: %prog trace1 ... traceN')
|
||||
(_, args) = parser.parse_args()
|
||||
if len(args) <= 1:
|
||||
parser.error('expected at least the following args: trace1 trace2')
|
||||
|
||||
step = 0
|
||||
tracemap = dict()
|
||||
for trace_file in args:
|
||||
step += 1
|
||||
sys.stderr.write(" " + str(step) + "/" + str(len(args)) +
|
||||
": " + trace_file + ":\n")
|
||||
|
||||
trace_lines = map(string.rstrip, open(trace_file).readlines())
|
||||
(trace_calls, trace_start, trace_end) = ParseLogLines(trace_lines)
|
||||
CheckTimestamps(trace_calls)
|
||||
sys.stderr.write("Len: " + str(len(trace_calls)) +
|
||||
". Start: " + hex(trace_start) +
|
||||
", end: " + hex(trace_end) + '\n')
|
||||
|
||||
trace_calls = Convert(trace_calls, trace_start, trace_end)
|
||||
sys.stderr.write("Converted len: " + str(len(trace_calls)) + "\n")
|
||||
|
||||
AddTrace(tracemap, trace_calls)
|
||||
sys.stderr.write("Merged len: " + str(len(tracemap)) + "\n")
|
||||
|
||||
# Extract the resulting trace from the tracemap
|
||||
merged_trace = []
|
||||
for call in tracemap:
|
||||
merged_trace.append(tracemap[call])
|
||||
merged_trace.sort(key=Timestamp)
|
||||
|
||||
print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
|
||||
print "secs\tmsecs\tpid:threadid\tfunc"
|
||||
for call in merged_trace:
|
||||
print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
|
||||
hex(call[3]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
117
tools/cygprofile/patch_orderfile.py
Executable file
117
tools/cygprofile/patch_orderfile.py
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/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):
|
||||
# print "addr: " + str(addr) + " start: " + str(start) + " end: " + str(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]
|
||||
# print "nm_addr: " + str(nm_addr) + " halfway: " + str(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:
|
||||
# if (count % 500 == 0):
|
||||
# print "current count: " + str(count)
|
||||
(functions, size) = binary_search (addr, 0, len(uniqueAddrs))
|
||||
total_size = total_size + size
|
||||
for function in functions:
|
||||
print ".text." + function
|
||||
print ""
|
||||
sys.stderr.write ("total_size: " + str(total_size) + "\n")
|
251
tools/cygprofile/symbolize.py
Executable file
251
tools/cygprofile/symbolize.py
Executable file
@@ -0,0 +1,251 @@
|
||||
#!/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.
|
||||
|
||||
"""Symbolize log file produced by cypgofile instrumentation.
|
||||
|
||||
Given a log file and the binary being profiled (e.g. executable, shared
|
||||
library), the script can produce three different outputs: 1) symbols for the
|
||||
addresses, 2) function and line numbers for the addresses, or 3) an order file.
|
||||
"""
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def ParseLogLines(log_file_lines):
|
||||
"""Parse a log file produced by the profiled run of clank.
|
||||
|
||||
Args:
|
||||
log_file_lines: array of lines in log file produced by profiled run
|
||||
lib_name: library or executable containing symbols
|
||||
|
||||
Below is an example of a small log file:
|
||||
5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
|
||||
secs msecs pid:threadid func
|
||||
START
|
||||
1314897086 795828 3587:1074648168 0x509e105c
|
||||
1314897086 795874 3587:1074648168 0x509e0eb4
|
||||
1314897086 796326 3587:1074648168 0x509e0e3c
|
||||
1314897086 796552 3587:1074648168 0x509e07bc
|
||||
END
|
||||
|
||||
Returns:
|
||||
call_info list with list of tuples of the format (sec, msec, call id,
|
||||
function address called)
|
||||
"""
|
||||
call_lines = []
|
||||
has_started = False
|
||||
vm_start = 0
|
||||
line = log_file_lines[0]
|
||||
assert("r-xp" in line)
|
||||
end_index = line.find('-')
|
||||
vm_start = int(line[:end_index], 16)
|
||||
for line in log_file_lines[2:]:
|
||||
# print hex(vm_start)
|
||||
fields = line.split()
|
||||
if len(fields) == 4:
|
||||
call_lines.append(fields)
|
||||
|
||||
# Convert strings to int in fields.
|
||||
call_info = []
|
||||
for call_line in call_lines:
|
||||
(sec_timestamp, msec_timestamp) = map(int, call_line[0:2])
|
||||
callee_id = call_line[2]
|
||||
addr = int(call_line[3], 16)
|
||||
if vm_start < addr:
|
||||
addr -= vm_start
|
||||
call_info.append((sec_timestamp, msec_timestamp, callee_id, addr))
|
||||
|
||||
return call_info
|
||||
|
||||
|
||||
def ParseLibSymbols(lib_file):
|
||||
"""Get output from running nm and greping for text symbols.
|
||||
|
||||
Args:
|
||||
lib_file: the library or executable that contains the profiled code
|
||||
|
||||
Returns:
|
||||
list of sorted unique addresses and corresponding size of function symbols
|
||||
in lib_file and map of addresses to all symbols at a particular address
|
||||
"""
|
||||
cmd = ['nm', '-S', '-n', lib_file]
|
||||
nm_p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
output = nm_p.communicate()[0]
|
||||
nm_lines = output.split('\n')
|
||||
|
||||
nm_symbols = []
|
||||
for nm_line in nm_lines:
|
||||
if any(str in nm_line for str in (' t ', ' W ', ' T ')):
|
||||
nm_symbols.append(nm_line)
|
||||
|
||||
nm_index = 0
|
||||
unique_addrs = []
|
||||
address_map = {}
|
||||
while nm_index < len(nm_symbols):
|
||||
|
||||
# If the length of the split line is not 4, then it does not contain all the
|
||||
# information needed to symbolize (i.e. address, size and symbol name).
|
||||
if len(nm_symbols[nm_index].split()) == 4:
|
||||
(addr, size) = [int(x, 16) for x in nm_symbols[nm_index].split()[0:2]]
|
||||
|
||||
# Multiple symbols may be at the same address. This is do to aliasing
|
||||
# done by the compiler. Since there is no way to be sure which one was
|
||||
# called in profiled run, we will symbolize to include all symbol names at
|
||||
# a particular address.
|
||||
fnames = []
|
||||
while (nm_index < len(nm_symbols) and
|
||||
addr == int(nm_symbols[nm_index].split()[0], 16)):
|
||||
if len(nm_symbols[nm_index].split()) == 4:
|
||||
fnames.append(nm_symbols[nm_index].split()[3])
|
||||
nm_index += 1
|
||||
address_map[addr] = fnames
|
||||
unique_addrs.append((addr, size))
|
||||
else:
|
||||
nm_index += 1
|
||||
|
||||
return (unique_addrs, address_map)
|
||||
|
||||
class SymbolNotFoundException(Exception):
|
||||
def __init__(self,value):
|
||||
self.value = value
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
def BinarySearchAddresses(addr, start, end, arr):
|
||||
"""Find starting address of a symbol at a particular address.
|
||||
|
||||
The reason we can not directly use the address provided by the log file is
|
||||
that the log file may give an address after the start of the symbol. The
|
||||
logged address is often one byte after the start. By using this search
|
||||
function rather than just subtracting one from the logged address allows
|
||||
the logging instrumentation to log any address in a function.
|
||||
|
||||
Args:
|
||||
addr: the address being searched for
|
||||
start: the starting index for the binary search
|
||||
end: the ending index for the binary search
|
||||
arr: the list being searched containing tuple of address and size
|
||||
|
||||
Returns:
|
||||
the starting address of the symbol at address addr
|
||||
|
||||
Raises:
|
||||
Exception: if address not found. Functions expects all logged addresses
|
||||
to be found
|
||||
"""
|
||||
# print "addr: " + str(addr) + " start: " + str(start) + " end: " + str(end)
|
||||
if start >= end or start == end - 1:
|
||||
# arr[i] is a tuple of address and size. Check if addr inside range
|
||||
if addr >= arr[start][0] and addr < arr[start][0] + arr[start][1]:
|
||||
return arr[start][0]
|
||||
elif addr >= arr[end][0] and addr < arr[end][0] + arr[end][1]:
|
||||
return arr[end][0]
|
||||
else:
|
||||
raise SymbolNotFoundException(addr)
|
||||
else:
|
||||
halfway = (start + end) / 2
|
||||
(nm_addr, size) = arr[halfway]
|
||||
# print "nm_addr: " + str(nm_addr) + " halfway: " + str(halfway)
|
||||
if addr >= nm_addr and addr < nm_addr + size:
|
||||
return nm_addr
|
||||
elif addr < nm_addr:
|
||||
return BinarySearchAddresses(addr, start, halfway-1, arr)
|
||||
else:
|
||||
# Condition (addr >= nm_addr + size) must be true.
|
||||
return BinarySearchAddresses(addr, halfway+1, end, arr)
|
||||
|
||||
|
||||
def FindFunctions(addr, unique_addrs, address_map):
|
||||
"""Find function symbol names at address addr."""
|
||||
return address_map[BinarySearchAddresses(addr, 0, len(unique_addrs) - 1,
|
||||
unique_addrs)]
|
||||
|
||||
|
||||
def AddrToLine(addr, lib_file):
|
||||
"""Use addr2line to determine line info of a particular address."""
|
||||
cmd = ['addr2line', '-f', '-e', lib_file, hex(addr)]
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
output = (p.communicate()[0]).split('\n')
|
||||
line = output[0]
|
||||
index = 1
|
||||
while index < len(output):
|
||||
line = line + ':' + output[index]
|
||||
index += 1
|
||||
return line
|
||||
|
||||
|
||||
def main():
|
||||
"""Write output for profiled run to standard out.
|
||||
|
||||
The format of the output depends on the output type specified as the third
|
||||
command line argument. The default output type is to symbolize the addresses
|
||||
of the functions called.
|
||||
"""
|
||||
parser = optparse.OptionParser('usage: %prog [options] log_file lib_file')
|
||||
parser.add_option('-t', '--outputType', dest='output_type',
|
||||
default='symbolize', type='string',
|
||||
help='lineize or symbolize or orderfile')
|
||||
|
||||
# Option for output type. The log file and lib file arguments are required
|
||||
# by the script and therefore are not options.
|
||||
(options, args) = parser.parse_args()
|
||||
if len(args) != 2:
|
||||
parser.error('expected 2 args: log_file lib_file')
|
||||
|
||||
(log_file, lib_file) = args
|
||||
output_type = options.output_type
|
||||
|
||||
lib_name = lib_file.split('/')[-1].strip()
|
||||
log_file_lines = map(string.rstrip, open(log_file).readlines())
|
||||
call_info = ParseLogLines(log_file_lines)
|
||||
(unique_addrs, address_map) = ParseLibSymbols(lib_file)
|
||||
|
||||
# Check for duplicate addresses in the log file, and print a warning if
|
||||
# duplicates are found. The instrumentation that produces the log file
|
||||
# should only print the first time a function is entered.
|
||||
addr_list = []
|
||||
for call in call_info:
|
||||
addr = call[3]
|
||||
if addr not in addr_list:
|
||||
addr_list.append(addr)
|
||||
else:
|
||||
print('WARNING: Address ' + hex(addr) + ' (line= ' +
|
||||
AddrToLine(addr, lib_file) + ') already profiled.')
|
||||
|
||||
for call in call_info:
|
||||
if output_type == 'lineize':
|
||||
symbol = AddrToLine(call[3], lib_file)
|
||||
print(str(call[0]) + ' ' + str(call[1]) + '\t' + str(call[2]) + '\t'
|
||||
+ symbol)
|
||||
elif output_type == 'orderfile':
|
||||
try:
|
||||
symbols = FindFunctions(call[3], unique_addrs, address_map)
|
||||
for symbol in symbols:
|
||||
print '.text.' + symbol
|
||||
print ''
|
||||
except SymbolNotFoundException as e:
|
||||
sys.stderr.write('WARNING: Did not find function in binary. addr: '
|
||||
+ hex(addr) + '\n')
|
||||
else:
|
||||
try:
|
||||
symbols = FindFunctions(call[3], unique_addrs, address_map)
|
||||
print(str(call[0]) + ' ' + str(call[1]) + '\t' + str(call[2]) + '\t'
|
||||
+ symbols[0])
|
||||
first_symbol = True
|
||||
for symbol in symbols:
|
||||
if not first_symbol:
|
||||
print '\t\t\t\t\t' + symbol
|
||||
else:
|
||||
first_symbol = False
|
||||
except SymbolNotFoundException as e:
|
||||
sys.stderr.write('WARNING: Did not find function in binary. addr: '
|
||||
+ hex(addr) + '\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user