OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
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 | |
4 # found in the LICENSE file. | |
5 | |
6 import json | |
7 import logging | |
8 import os | |
9 import re | |
10 import shutil | |
11 import subprocess | |
12 import sys | |
13 import tempfile | |
14 | |
15 from parse_proc_maps import parse_proc_maps | |
16 from util import executable_condition | |
17 | |
18 | |
19 def prepare_symbol_info(maps_path, output_dir_path=None, loglevel=logging.WARN): | |
20 log = logging.getLogger('prepare_symbol_info') | |
21 log.setLevel(loglevel) | |
22 handler = logging.StreamHandler() | |
23 handler.setLevel(loglevel) | |
24 formatter = logging.Formatter('%(message)s') | |
25 handler.setFormatter(formatter) | |
26 log.addHandler(handler) | |
27 | |
28 if not output_dir_path: | |
29 matched = re.match('^(.*)\.maps$', os.path.basename(maps_path)) | |
30 if matched: | |
31 output_dir_path = matched.group(1) + '.pre' | |
32 if not output_dir_path: | |
33 matched = re.match('^/proc/(.*)/maps$', os.path.realpath(maps_path)) | |
34 if matched: | |
35 output_dir_path = matched.group(1) + '.pre' | |
36 if not output_dir_path: | |
37 output_dir_prefix = os.path.basename(maps_path) + '.pre' | |
38 # TODO(dmikurube): Find another candidate for output_dir_path. | |
39 | |
40 log.info('Data for profiling will be collected in "%s".' % output_dir_path) | |
41 output_dir_path_exists = False | |
42 if os.path.exists(output_dir_path): | |
43 if os.path.isdir(output_dir_path) and not os.listdir(output_dir_path): | |
44 log.warn('Using an empty directory existing at "%s".' % output_dir_path) | |
45 else: | |
46 log.warn('A file or a directory exists at "%s".' % output_dir_path) | |
47 output_dir_path_exists = True | |
48 else: | |
49 log.info('Creating a new directory at "%s".' % output_dir_path) | |
50 os.mkdir(output_dir_path) | |
51 | |
52 if output_dir_path_exists: | |
53 return 1 | |
54 | |
55 shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps')) | |
56 | |
57 with open(maps_path, mode='r') as f: | |
M-A Ruel
2012/07/20 14:10:21
optional: mode='r' is the default so it is optiona
Dai Mikurube (NOT FULLTIME)
2012/07/21 04:50:10
Thanks. I keep it as is to make it clear that it'
| |
58 maps = parse_proc_maps(f) | |
59 | |
60 log.debug('Listing up symbols.') | |
61 nm_files = {} | |
62 for entry in maps.iter(executable_condition): | |
63 log.debug(' %016x-%016x +%06x %s' % ( | |
64 entry.begin, entry.end, entry.offset, entry.name)) | |
65 with tempfile.NamedTemporaryFile( | |
66 prefix=os.path.basename(entry.name) + '.', | |
67 suffix='.nm', delete=False, mode='w', dir=output_dir_path) as f: | |
68 nm_filename = os.path.realpath(f.name) | |
69 nm_succeeded = False | |
70 cppfilt_succeeded = False | |
71 p_nm = subprocess.Popen( | |
72 'nm -n --format bsd %s' % entry.name, shell=True, | |
73 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
74 p_cppfilt = subprocess.Popen( | |
75 'c++filt', shell=True, | |
76 stdin=p_nm.stdout, stdout=f, stderr=subprocess.PIPE) | |
77 | |
78 if p_nm.wait() == 0: | |
79 nm_succeeded = True | |
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), | |
90 'format': 'bsd', | |
91 'mangled': False} | |
92 else: | |
93 os.remove(nm_filename) | |
94 | |
95 with open(os.path.join(output_dir_path, 'nm.json'), 'w') as f: | |
96 json.dump(nm_files, f, indent=2, sort_keys=True) | |
97 | |
98 log.info('Collected symbol information at "%s".' % output_dir_path) | |
99 return 0 | |
100 | |
101 | |
102 def main(): | |
103 if not sys.platform.startswith('linux'): | |
104 sys.stderr.write('This script work only on Linux.') | |
105 return 1 | |
106 | |
107 if len(sys.argv) < 2: | |
108 sys.stderr.write("""Usage: | |
109 %s /path/to/maps [/path/to/output_data_dir/] | |
110 """ % sys.argv[0]) | |
111 return 1 | |
112 elif len(sys.argv) == 2: | |
113 sys.exit(prepare_symbol_info(sys.argv[1], loglevel=logging.DEBUG)) | |
114 else: | |
115 sys.exit(prepare_symbol_info(sys.argv[1], sys.argv[2], | |
116 loglevel=logging.INFO)) | |
117 return 0 | |
118 | |
119 | |
120 if __name__ == '__main__': | |
121 sys.exit(main()) | |
OLD | NEW |