Home | History | Annotate | Download | only in android
      1 #!/usr/bin/env python
      2 #
      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
      5 # found in the LICENSE file.
      6 
      7 """Symbolizes stack traces generated by Chromium for Android.
      8 
      9 Sample usage:
     10   adb logcat chromium:V | symbolize.py
     11 """
     12 
     13 import os
     14 import re
     15 import sys
     16 
     17 from pylib import constants
     18 
     19 # Uses symbol.py from third_party/android_platform, not python's.
     20 sys.path.insert(0,
     21                 os.path.join(constants.DIR_SOURCE_ROOT,
     22                             'third_party/android_platform/development/scripts'))
     23 import symbol
     24 
     25 # Sample output from base/debug/stack_trace_android.cc
     26 #00 0x693cd34f /path/to/some/libfoo.so+0x0007434f
     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})')
     29 
     30 class Symbolizer(object):
     31   def __init__(self, output):
     32     self._output = output
     33 
     34   def write(self, data):
     35     while True:
     36       match = re.search(TRACE_LINE, data)
     37       if not match:
     38         self._output.write(data)
     39         break
     40 
     41       frame = match.group('frame')
     42       lib = match.group('lib')
     43       addr = match.group('addr')
     44 
     45       # TODO(scherkus): Doing a single lookup per line is pretty slow,
     46       # especially with larger libraries. Consider caching strategies such as:
     47       # 1) Have Python load the libraries and do symbol lookups instead of
     48       #    calling out to addr2line each time.
     49       # 2) Have Python keep multiple addr2line instances open as subprocesses,
     50       #    piping addresses and reading back symbols as we find them
     51       # 3) Read ahead the entire stack trace until we find no more, then batch
     52       #    the symbol lookups.
     53       #
     54       # TODO(scherkus): These results are memoized, which could result in
     55       # incorrect lookups when running this script on long-lived instances
     56       # (e.g., adb logcat) when doing incremental development. Consider clearing
     57       # the cache when modification timestamp of libraries change.
     58       sym = symbol.SymbolInformation(lib, addr, False)[0][0]
     59 
     60       if not sym:
     61         post = match.end('addr')
     62         self._output.write(data[:post])
     63         data = data[post:]
     64         continue
     65 
     66       pre = match.start('frame')
     67       post = match.end('addr')
     68 
     69       self._output.write(data[:pre])
     70       self._output.write(frame)
     71       self._output.write(' ')
     72       self._output.write(sym)
     73 
     74       data = data[post:]
     75 
     76   def flush(self):
     77     self._output.flush()
     78 
     79 
     80 def main():
     81   symbolizer = Symbolizer(sys.stdout)
     82   for line in sys.stdin:
     83     symbolizer.write(line)
     84   symbolizer.flush()
     85 
     86 
     87 if __name__ == '__main__':
     88   main()
     89