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