| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import json | 6 import json |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import re | 9 import re |
| 10 import shutil | 10 import shutil |
| 11 import subprocess | 11 import subprocess |
| 12 import sys | 12 import sys |
| 13 import tempfile | 13 import tempfile |
| 14 | 14 |
| 15 from parse_proc_maps import parse_proc_maps | 15 from parse_proc_maps import parse_proc_maps |
| 16 from util import executable_condition | 16 from util import executable_condition |
| 17 | 17 |
| 18 | 18 |
| 19 def _dump_command_result(command, output_dir_path, basename, suffix, log): |
| 20 handle_out, filename_out = tempfile.mkstemp( |
| 21 suffix=suffix, prefix=basename + '.', dir=output_dir_path) |
| 22 handle_err, filename_err = tempfile.mkstemp( |
| 23 suffix=suffix + '.err', prefix=basename + '.', dir=output_dir_path) |
| 24 error = False |
| 25 try: |
| 26 subprocess.check_call( |
| 27 command, stdout=handle_out, stderr=handle_err, shell=True) |
| 28 except: |
| 29 error = True |
| 30 finally: |
| 31 os.close(handle_err) |
| 32 os.close(handle_out) |
| 33 |
| 34 if os.path.exists(filename_err): |
| 35 if log.getEffectiveLevel() <= logging.DEBUG: |
| 36 with open(filename_err, 'r') as f: |
| 37 for line in f: |
| 38 log.debug(line.rstrip()) |
| 39 os.remove(filename_err) |
| 40 |
| 41 if os.path.exists(filename_out) and ( |
| 42 os.path.getsize(filename_out) == 0 or error): |
| 43 os.remove(filename_out) |
| 44 return None |
| 45 |
| 46 if not os.path.exists(filename_out): |
| 47 return None |
| 48 |
| 49 return filename_out |
| 50 |
| 51 |
| 19 def prepare_symbol_info(maps_path, output_dir_path=None, loglevel=logging.WARN): | 52 def prepare_symbol_info(maps_path, output_dir_path=None, loglevel=logging.WARN): |
| 20 log = logging.getLogger('prepare_symbol_info') | 53 log = logging.getLogger('prepare_symbol_info') |
| 21 log.setLevel(loglevel) | 54 log.setLevel(loglevel) |
| 22 handler = logging.StreamHandler() | 55 handler = logging.StreamHandler() |
| 23 handler.setLevel(loglevel) | 56 handler.setLevel(loglevel) |
| 24 formatter = logging.Formatter('%(message)s') | 57 formatter = logging.Formatter('%(message)s') |
| 25 handler.setFormatter(formatter) | 58 handler.setFormatter(formatter) |
| 26 log.addHandler(handler) | 59 log.addHandler(handler) |
| 27 | 60 |
| 28 if not output_dir_path: | 61 if not output_dir_path: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 51 | 84 |
| 52 if output_dir_path_exists: | 85 if output_dir_path_exists: |
| 53 return 1 | 86 return 1 |
| 54 | 87 |
| 55 shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps')) | 88 shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps')) |
| 56 | 89 |
| 57 with open(maps_path, mode='r') as f: | 90 with open(maps_path, mode='r') as f: |
| 58 maps = parse_proc_maps(f) | 91 maps = parse_proc_maps(f) |
| 59 | 92 |
| 60 log.debug('Listing up symbols.') | 93 log.debug('Listing up symbols.') |
| 61 nm_files = {} | 94 files = {} |
| 62 for entry in maps.iter(executable_condition): | 95 for entry in maps.iter(executable_condition): |
| 63 log.debug(' %016x-%016x +%06x %s' % ( | 96 log.debug(' %016x-%016x +%06x %s' % ( |
| 64 entry.begin, entry.end, entry.offset, entry.name)) | 97 entry.begin, entry.end, entry.offset, entry.name)) |
| 65 with tempfile.NamedTemporaryFile( | 98 nm_filename = _dump_command_result( |
| 66 prefix=os.path.basename(entry.name) + '.', | 99 'nm -n --format bsd %s | c++filt' % entry.name, |
| 67 suffix='.nm', delete=False, mode='w', dir=output_dir_path) as f: | 100 output_dir_path, os.path.basename(entry.name), '.nm', log) |
| 68 nm_filename = os.path.realpath(f.name) | 101 if not nm_filename: |
| 69 nm_succeeded = False | 102 continue |
| 70 cppfilt_succeeded = False | 103 readelf_e_filename = _dump_command_result( |
| 71 p_nm = subprocess.Popen( | 104 'readelf -e %s' % entry.name, |
| 72 'nm -n --format bsd %s' % entry.name, shell=True, | 105 output_dir_path, os.path.basename(entry.name), '.readelf-e', log) |
| 73 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 106 if not readelf_e_filename: |
| 74 p_cppfilt = subprocess.Popen( | 107 continue |
| 75 'c++filt', shell=True, | |
| 76 stdin=p_nm.stdout, stdout=f, stderr=subprocess.PIPE) | |
| 77 | 108 |
| 78 if p_nm.wait() == 0: | 109 files[entry.name] = {} |
| 79 nm_succeeded = True | 110 files[entry.name]['nm'] = { |
| 80 for line in p_nm.stderr: | |
| 81 log.debug(line.rstrip()) | |
| 82 if p_cppfilt.wait() == 0: | |
| 83 cppfilt_succeeded = True | |
| 84 for line in p_cppfilt.stderr: | |
| 85 log.debug(line.rstrip()) | |
| 86 | |
| 87 if nm_succeeded and cppfilt_succeeded: | |
| 88 nm_files[entry.name] = { | |
| 89 'file': os.path.basename(nm_filename), | 111 'file': os.path.basename(nm_filename), |
| 90 'format': 'bsd', | 112 'format': 'bsd', |
| 91 'mangled': False} | 113 'mangled': False} |
| 92 else: | 114 files[entry.name]['readelf-e'] = { |
| 93 os.remove(nm_filename) | 115 'file': os.path.basename(readelf_e_filename)} |
| 94 | 116 |
| 95 with open(os.path.join(output_dir_path, 'nm.json'), 'w') as f: | 117 with open(os.path.join(output_dir_path, 'files.json'), 'w') as f: |
| 96 json.dump(nm_files, f, indent=2, sort_keys=True) | 118 json.dump(files, f, indent=2, sort_keys=True) |
| 97 | 119 |
| 98 log.info('Collected symbol information at "%s".' % output_dir_path) | 120 log.info('Collected symbol information at "%s".' % output_dir_path) |
| 99 return 0 | 121 return 0 |
| 100 | 122 |
| 101 | 123 |
| 102 def main(): | 124 def main(): |
| 103 if not sys.platform.startswith('linux'): | 125 if not sys.platform.startswith('linux'): |
| 104 sys.stderr.write('This script work only on Linux.') | 126 sys.stderr.write('This script work only on Linux.') |
| 105 return 1 | 127 return 1 |
| 106 | 128 |
| 107 if len(sys.argv) < 2: | 129 if len(sys.argv) < 2: |
| 108 sys.stderr.write("""Usage: | 130 sys.stderr.write("""Usage: |
| 109 %s /path/to/maps [/path/to/output_data_dir/] | 131 %s /path/to/maps [/path/to/output_data_dir/] |
| 110 """ % sys.argv[0]) | 132 """ % sys.argv[0]) |
| 111 return 1 | 133 return 1 |
| 112 elif len(sys.argv) == 2: | 134 elif len(sys.argv) == 2: |
| 113 sys.exit(prepare_symbol_info(sys.argv[1], loglevel=logging.DEBUG)) | 135 sys.exit(prepare_symbol_info(sys.argv[1], loglevel=logging.INFO)) |
| 114 else: | 136 else: |
| 115 sys.exit(prepare_symbol_info(sys.argv[1], sys.argv[2], | 137 sys.exit(prepare_symbol_info(sys.argv[1], sys.argv[2], |
| 116 loglevel=logging.INFO)) | 138 loglevel=logging.INFO)) |
| 117 return 0 | 139 return 0 |
| 118 | 140 |
| 119 | 141 |
| 120 if __name__ == '__main__': | 142 if __name__ == '__main__': |
| 121 sys.exit(main()) | 143 sys.exit(main()) |
| OLD | NEW |