• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
3#
4#                     The LLVM Compiler Infrastructure
5#
6# This file is distributed under the University of Illinois Open Source
7# License. See LICENSE.TXT for details.
8#
9#===------------------------------------------------------------------------===#
10import glob
11import os
12import re
13import sys
14import string
15import subprocess
16
17pipes = {}
18next_inline_frameno = 0
19
20def patch_address(frameno, addr_s):
21  ''' Subtracts 1 or 2 from the top frame's address.
22  Top frame is normally the return address from asan_report*
23  call, which is not expected to return at all. Because of that, this
24  address often belongs to the next source code line, or even to a different
25  function. '''
26  if frameno == '0':
27    addr = int(addr_s, 16)
28    if os.uname()[4].startswith('arm'):
29      # Cancel the Thumb bit
30      addr = addr & (~1)
31    addr -= 1
32    return hex(addr)
33  return addr_s
34
35def postprocess_file_name(file_name, paths_to_cut):
36  for path_to_cut in paths_to_cut:
37    file_name = re.sub(".*" + path_to_cut, "", file_name)
38  file_name = re.sub(".*asan_[a-z_]*.(cc|h):[0-9]*", "[asan_rtl]", file_name)
39  file_name = re.sub(".*crtstuff.c:0", "???:0", file_name)
40  return file_name
41
42# TODO(glider): need some refactoring here
43def symbolize_addr2line(line, binary_prefix, paths_to_cut):
44  global next_inline_frameno
45  # Strip the log prefix ("I/asanwrapper( 1196): ").
46  line = re.sub(r'^.*?: ', '', line)
47  #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
48  match = re.match(r'^(\s*#)([0-9]+) *(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line, re.UNICODE)
49  if match:
50    frameno = match.group(2)
51    binary = match.group(4)
52    addr = match.group(5)
53    addr = patch_address(frameno, addr)
54
55    if binary.startswith('/'):
56      binary = binary[1:]
57    binary = os.path.join(binary_prefix, binary)
58
59    if not os.path.exists(binary):
60      print line.rstrip().encode('utf-8')
61      return
62
63    addr = hex(int(addr, 16))
64
65    if not pipes.has_key(binary):
66      pipes[binary] = subprocess.Popen(["addr2line", "-i", "-f", "-e", binary],
67                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
68    p = pipes[binary]
69    frames = []
70    try:
71      print >>p.stdin, addr
72      # This will trigger a "??" response from addr2line so we know when to stop
73      print >>p.stdin
74      while True:
75        function_name = p.stdout.readline().rstrip()
76        file_name     = p.stdout.readline().rstrip()
77        if function_name in ['??', '']:
78          break
79        file_name = postprocess_file_name(file_name, paths_to_cut)
80        frames.append((function_name, file_name))
81    except:
82      pass
83    if not frames:
84      frames.append(('', ''))
85      # Consume another pair of "??" lines
86      try:
87        p.stdout.readline()
88        p.stdout.readline()
89      except:
90        pass
91    for frame in frames:
92      inline_frameno = next_inline_frameno
93      next_inline_frameno += 1
94      print "%s%d" % (match.group(1).encode('utf-8'), inline_frameno), \
95          match.group(3).encode('utf-8'), "in", frame[0], frame[1]
96  else:
97    print line.rstrip().encode('utf-8')
98
99
100binary_prefix = os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'symbols')
101paths_to_cut = [os.getcwd() + '/', os.environ['ANDROID_BUILD_TOP'] + '/'] + sys.argv[1:]
102
103for line in sys.stdin:
104  line = line.decode('utf-8', 'replace')
105  symbolize_addr2line(line, binary_prefix, paths_to_cut)
106