OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Symbolizes stack traces generated by Chromium for Android. | 7 """Symbolizes stack traces generated by Chromium for Android. |
8 | 8 |
9 Sample usage: | 9 Sample usage: |
10 adb logcat chromium:V | symbolize.py | 10 adb logcat chromium:V | symbolize.py |
(...skipping 10 matching lines...) Expand all Loading... | |
21 os.path.join(constants.DIR_SOURCE_ROOT, | 21 os.path.join(constants.DIR_SOURCE_ROOT, |
22 'third_party/android_platform/development/scripts')) | 22 'third_party/android_platform/development/scripts')) |
23 import symbol | 23 import symbol |
24 | 24 |
25 # Sample output from base/debug/stack_trace_android.cc | 25 # Sample output from base/debug/stack_trace_android.cc |
26 #00 0x693cd34f /path/to/some/libfoo.so+0x0007434f | 26 #00 0x693cd34f /path/to/some/libfoo.so+0x0007434f |
27 TRACE_LINE = re.compile('(?P<frame>\#[0-9]+ 0x[0-9a-f]{8,8}) ' | 27 TRACE_LINE = re.compile('(?P<frame>\#[0-9]+ 0x[0-9a-f]{8,8}) ' |
28 '(?P<lib>[^+]+)\+0x(?P<addr>[0-9a-f]{8,8})') | 28 '(?P<lib>[^+]+)\+0x(?P<addr>[0-9a-f]{8,8})') |
29 | 29 |
30 class Symbolizer(object): | 30 class Symbolizer(object): |
31 def __init__(self, file_in, file_out): | 31 def __init__(self, output): |
32 self.file_in = file_in | 32 self._output = output |
33 self.file_out = file_out | |
34 | 33 |
35 def ProcessInput(self): | 34 def write(self, data): |
bulach
2013/07/18 09:07:03
nit: it looks a bit weird to have "write(input_dat
scherkus (not reviewing)
2013/07/18 18:08:34
The idea is that an instance of this class can act
| |
36 for line in self.file_in: | 35 while True: |
37 match = re.search(TRACE_LINE, line) | 36 match = re.search(TRACE_LINE, data) |
38 if not match: | 37 if not match: |
39 self.file_out.write(line) | 38 self._output.write(data) |
40 self.file_out.flush() | 39 break |
41 continue | |
42 | 40 |
43 frame = match.group('frame') | 41 frame = match.group('frame') |
44 lib = match.group('lib') | 42 lib = match.group('lib') |
45 addr = match.group('addr') | 43 addr = match.group('addr') |
46 | 44 |
47 # TODO(scherkus): Doing a single lookup per line is pretty slow, | 45 # TODO(scherkus): Doing a single lookup per line is pretty slow, |
48 # especially with larger libraries. Consider caching strategies such as: | 46 # especially with larger libraries. Consider caching strategies such as: |
49 # 1) Have Python load the libraries and do symbol lookups instead of | 47 # 1) Have Python load the libraries and do symbol lookups instead of |
50 # calling out to addr2line each time. | 48 # calling out to addr2line each time. |
51 # 2) Have Python keep multiple addr2line instances open as subprocesses, | 49 # 2) Have Python keep multiple addr2line instances open as subprocesses, |
52 # piping addresses and reading back symbols as we find them | 50 # piping addresses and reading back symbols as we find them |
53 # 3) Read ahead the entire stack trace until we find no more, then batch | 51 # 3) Read ahead the entire stack trace until we find no more, then batch |
54 # the symbol lookups. | 52 # the symbol lookups. |
55 # | 53 # |
56 # TODO(scherkus): These results are memoized, which could result in | 54 # TODO(scherkus): These results are memoized, which could result in |
57 # incorrect lookups when running this script on long-lived instances | 55 # incorrect lookups when running this script on long-lived instances |
58 # (e.g., adb logcat) when doing incremental development. Consider clearing | 56 # (e.g., adb logcat) when doing incremental development. Consider clearing |
59 # the cache when modification timestamp of libraries change. | 57 # the cache when modification timestamp of libraries change. |
60 sym = symbol.SymbolInformation(lib, addr, False)[0][0] | 58 sym = symbol.SymbolInformation(lib, addr, False)[0][0] |
61 | 59 |
62 if not sym: | 60 if not sym: |
63 self.file_out.write(line) | 61 post = match.end('addr') |
64 self.file_out.flush() | 62 self._output.write(data[:post]) |
63 data = data[post:] | |
65 continue | 64 continue |
66 | 65 |
67 pre = line[0:match.start('frame')] | 66 pre = match.start('frame') |
68 post = line[match.end('addr'):] | 67 post = match.end('addr') |
69 | 68 |
70 self.file_out.write(pre) | 69 self._output.write(data[:pre]) |
71 self.file_out.write(frame) | 70 self._output.write(frame) |
72 self.file_out.write(' ') | 71 self._output.write(' ') |
73 self.file_out.write(sym) | 72 self._output.write(sym) |
74 self.file_out.write(post) | 73 |
75 self.file_out.flush() | 74 data = data[post:] |
75 | |
76 def flush(self): | |
77 self._output.flush() | |
76 | 78 |
77 | 79 |
78 def main(): | 80 def main(): |
79 symbolizer = Symbolizer(sys.stdin, sys.stdout) | 81 symbolizer = Symbolizer(sys.stdout) |
80 symbolizer.ProcessInput() | 82 for line in sys.stdin: |
83 symbolizer.write(line) | |
84 symbolizer.flush() | |
81 | 85 |
82 | 86 |
83 if __name__ == '__main__': | 87 if __name__ == '__main__': |
84 main() | 88 main() |
OLD | NEW |