Chromium Code Reviews| Index: tools/find_runtime_symbols/prepare_symbol_info.py |
| diff --git a/tools/find_runtime_symbols/prepare_symbol_info.py b/tools/find_runtime_symbols/prepare_symbol_info.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..310568c129745c1a8e91a837fc0c029f322bed9e |
| --- /dev/null |
| +++ b/tools/find_runtime_symbols/prepare_symbol_info.py |
| @@ -0,0 +1,114 @@ |
| +#!/usr/bin/env python |
| + |
| +import json |
| +import logging |
| +import os |
| +import re |
| +import shutil |
| +import subprocess |
| +import sys |
| +import tempfile |
| + |
| +from parse_proc_maps import parse_proc_maps |
| + |
| + |
| +def _executable_condition(entry): |
|
M-A Ruel
2012/07/19 15:21:15
Why duplicate this function?
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
Moved it to util.py, and shared it.
|
| + return (entry.executable == 'x' and re.match( |
| + '\S+(\.(so|dll|dylib|bundle)|chrome)((\.\d+)+\w*(\.\d+){0,3})?', |
| + entry.name)) |
| + |
| + |
| +def prepare_symbol_info(maps_path, output_dir_path=None, loglevel=logging.WARN): |
| + log = logging.getLogger('prepare_symbol_info') |
| + log.setLevel(loglevel) |
| + handler = logging.StreamHandler() |
| + handler.setLevel(loglevel) |
| + formatter = logging.Formatter('%(message)s') |
| + handler.setFormatter(formatter) |
| + log.addHandler(handler) |
| + |
| + if not output_dir_path: |
| + matched = re.match('^(.*)\.maps$', os.path.basename(maps_path)) |
| + if matched: |
| + output_dir_path = matched.group(1) + '.pre' |
| + if not output_dir_path: |
| + matched = re.match('^/proc/(.*)/maps$', os.path.realpath(maps_path)) |
|
M-A Ruel
2012/07/19 15:21:15
You should make this clear that these files are li
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
Done.
|
| + if matched: |
| + output_dir_path = matched.group(1) + '.pre' |
| + if not output_dir_path: |
| + output_dir_prefix = os.path.basename(maps_path) + '.pre' |
| + # TODO(dmikurube): Find another candidate for output_dir_path. |
| + |
| + log.info('Data for profiling will be collected in "%s".' % output_dir_path) |
| + output_dir_path_exists = False |
| + if os.path.exists(output_dir_path): |
| + if os.path.isdir(output_dir_path) and not os.listdir(output_dir_path): |
| + log.warn('Using an empty directory existing at "%s".' % output_dir_path) |
| + else: |
| + log.warn('A file or a directory exists at "%s".' % output_dir_path) |
| + output_dir_path_exists = True |
| + else: |
| + log.info('Creating a new directory at "%s".' % output_dir_path) |
| + os.mkdir(output_dir_path) |
| + |
| + if output_dir_path_exists: |
| + return 1 |
| + |
| + shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps')) |
| + |
| + with open(maps_path, mode='r') as FILE: |
| + maps = parse_proc_maps(FILE) |
| + |
| + log.debug('Listing up symbols.') |
| + nm_files = {} |
| + for entry in maps.iter(_executable_condition): |
| + log.debug(' %016x-%016x +%06x %s' % ( |
| + entry.begin, entry.end, entry.offset, entry.name)) |
| + with tempfile.NamedTemporaryFile( |
| + prefix=os.path.basename(entry.name) + '.', |
| + suffix='.nm', delete=False, mode='w+', dir=output_dir_path) as FILE: |
| + nm_filename = os.path.realpath(FILE.name) |
| + nm_succeeded = False |
| + cppfilt_succeeded = False |
| + p_nm = subprocess.Popen( |
| + 'nm -n --format bsd %s' % entry.name, shell=True, |
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| + p_cppfilt = subprocess.Popen( |
| + 'c++filt', shell=True, |
| + stdin=p_nm.stdout, stdout=FILE, stderr=subprocess.PIPE) |
| + if p_nm.wait() == 0: |
|
M-A Ruel
2012/07/19 15:21:15
See http://docs.python.org/library/subprocess.html
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
The problem is that it's giving p_nm.stdout to c++
|
| + nm_succeeded = True |
| + for line in p_nm.stderr: |
| + log.debug(line.rstrip()) |
| + if p_cppfilt.wait() == 0: |
| + cppfilt_succeeded = True |
| + for line in p_cppfilt.stderr: |
| + log.debug(line.rstrip()) |
| + |
| + if nm_succeeded and cppfilt_succeeded: |
| + nm_files[entry.name] = { |
| + 'file': os.path.basename(os.path.basename(nm_filename)), |
|
M-A Ruel
2012/07/19 15:21:15
Did you mean dirname?
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
Ah, one of basename is not required.
|
| + 'format': 'bsd', |
| + 'mangled': False, |
| + } |
|
M-A Ruel
2012/07/19 15:21:15
funny alignment
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
Done.
|
| + else: |
| + os.remove(nm_filename) |
| + |
| + with open(os.path.join(output_dir_path, 'nm.json'), 'w+') as FILE: |
| + json.dump(nm_files, FILE, indent=2, sort_keys=True) |
|
M-A Ruel
2012/07/19 15:21:15
json.dump in a w+ opened file? It's going to be in
Dai Mikurube (NOT FULLTIME)
2012/07/20 04:32:39
Done.
|
| + |
| + log.info('Collected symbol information at "%s".' % output_dir_path) |
| + return 0 |
| + |
| + |
| +if __name__ == '__main__': |
| + if len(sys.argv) < 2: |
| + sys.stderr.write("""Usage: |
| +%s /path/to/maps [/path/to/output_data_dir/] |
| +""" % sys.argv[0]) |
| + sys.exit(1) |
| + elif len(sys.argv) == 2: |
| + sys.exit(prepare_symbol_info(sys.argv[1], loglevel=logging.INFO)) |
| + else: |
| + sys.exit(prepare_symbol_info(sys.argv[1], sys.argv[2], |
| + loglevel=logging.INFO)) |