Index: tools/cygprofile/symbolize.py |
diff --git a/tools/cygprofile/symbolize.py b/tools/cygprofile/symbolize.py |
index 027da57a521ac95975d598e60687ae50877c2aba..6dad6eabf1c287c39613922ca1ca647e80e38099 100755 |
--- a/tools/cygprofile/symbolize.py |
+++ b/tools/cygprofile/symbolize.py |
@@ -63,6 +63,10 @@ def ParseLogLines(log_file_lines): |
return call_info |
+def GetOutputLines(cmd): |
pasko
2014/12/10 12:07:05
we are ignoring stderr (which is arguable also an
azarchs
2014/12/10 17:13:33
Done.
|
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE) |
+ output = p.communicate()[0] |
+ return output.split('\n') |
def ParseLibSymbols(lib_file): |
"""Get output from running nm and greping for text symbols. |
@@ -75,9 +79,7 @@ def ParseLibSymbols(lib_file): |
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_lines = GetOutputLines(cmd) |
nm_symbols = [] |
for nm_line in nm_lines: |
@@ -170,8 +172,7 @@ def FindFunctions(addr, unique_addrs, address_map): |
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') |
+ output = GetOutputLines(cmd) |
line = output[0] |
index = 1 |
while index < len(output): |
pasko
2014/12/10 12:07:05
with the given arguments addr2line always outputs
azarchs
2014/12/10 17:13:33
Done.
|
@@ -179,6 +180,41 @@ def AddrToLine(addr, lib_file): |
index += 1 |
return line |
+def ObjectFiles(obj_dir): |
pasko
2014/12/10 12:07:05
GetObjectFiles
azarchs
2014/12/10 17:13:33
Done.
|
+ """ Gets the list of object files in the output folder """ |
pasko
2014/12/10 12:07:05
this is on linux, so s/folder/directory./ :)
azarchs
2014/12/10 17:13:33
Done.
|
+ obj_files = [] |
+ for (dirpath, dirnames, filenames) in os.walk(obj_dir): |
+ for file_name in filenames: |
+ if file_name.endswith('.o'): |
+ obj_files.append(os.path.join(dirpath, file_name)) |
+ return obj_files |
+ |
+def SymbolToSection(obj_dir): |
+ """ Gets a mapping from symbol to linker section name by scanning all |
+ of the object files """ |
pasko
2014/12/10 12:07:05
s/files/files./
|
+ object_files = ObjectFiles(obj_dir) |
+ symbol_map = {} |
+ for obj_file in object_files: |
+ cmd = ['objdump', '-w', '-t', obj_file] |
+ objects = GetOutputLines(cmd) |
pasko
2014/12/10 12:07:05
in lunix/binutils land 'object' and 'object file'
azarchs
2014/12/10 17:13:33
Done.
|
+ for object_line in objects: |
+ items = object_line.split() |
pasko
2014/12/10 12:07:05
it is non-obvious that simple splitting like this
azarchs
2014/12/10 17:13:33
Done.
|
+ if len(items) > 4 and items[2] == 'F': |
+ # This symbol is a function |
+ symbol = items[len(items) - 1] |
pasko
2014/12/10 12:07:05
more pythonic, but arguably less readable:
symbol
azarchs
2014/12/10 17:13:33
Style guide says nothing on the subject. I prefer
pasko
2014/12/10 17:56:09
Acknowledged.
|
+ if symbol.startswith('.LTHUNK'): |
+ continue |
+ section = items[3] |
+ if symbol in symbol_map and symbol_map[symbol] != section: |
+ sys.stderr.write('WARNING: Symbol ' + symbol + |
+ ' in conflicting sections ' + section + |
pasko
2014/12/10 12:07:05
I really don't see a problem with having a single
azarchs
2014/12/10 17:13:33
It doesn't currently happen. If it did, which sec
|
+ ' and ' + symbol_map[symbol] + '\n') |
+ elif not section.startswith('.text.'): |
+ sys.stderr.write('WARNING: Symbol ' + symbol + |
pasko
2014/12/10 12:07:04
should we limit the number of messages like this t
azarchs
2014/12/10 17:13:33
Done.
|
+ ' in incorrect section ' + section + '\n') |
+ else: |
+ symbol_map[symbol] = section |
pasko
2014/12/10 12:07:05
section_map or symbol_to_section_map would be bett
azarchs
2014/12/10 17:13:33
Done.
|
+ return symbol_map |
def main(): |
"""Write output for profiled run to standard out. |
@@ -201,6 +237,8 @@ def main(): |
(log_file, lib_file) = args |
output_type = options.output_type |
+ obj_dir = os.path.abspath(os.path.join(os.path.dirname(lib_file), '../obj')) |
+ |
lib_name = lib_file.split('/')[-1].strip() |
log_file_lines = map(string.rstrip, open(log_file).readlines()) |
call_info = ParseLogLines(log_file_lines) |
@@ -218,6 +256,8 @@ def main(): |
print('WARNING: Address ' + hex(addr) + ' (line= ' + |
AddrToLine(addr, lib_file) + ') already profiled.') |
+ symbol_map = SymbolToSection(obj_dir) |
+ |
for call in call_info: |
if output_type == 'lineize': |
symbol = AddrToLine(call[3], lib_file) |
@@ -227,7 +267,10 @@ def main(): |
try: |
symbols = FindFunctions(call[3], unique_addrs, address_map) |
for symbol in symbols: |
- print '.text.' + symbol |
+ if symbol in symbol_map: |
+ print symbol_map[symbol] |
+ else: |
+ sys.stderr.write('WARNING: Unknown symbol ' + symbol + '\n') |
pasko
2014/12/10 12:07:05
so this happens when a symbol is in the final libr
azarchs
2014/12/10 17:13:33
Done.
|
print '' |
except SymbolNotFoundException as e: |
sys.stderr.write('WARNING: Did not find function in binary. addr: ' |