1ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng#!/usr/bin/env python
2ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
3ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# Copyright (C) 2009 The Android Open Source Project
4ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng#
5ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# Licensed under the Apache License, Version 2.0 (the 'License');
6ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# you may not use this file except in compliance with the License.
7ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# You may obtain a copy of the License at
8ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng#
9ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng#      http://www.apache.org/licenses/LICENSE-2.0
10ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng#
11ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# Unless required by applicable law or agreed to in writing, software
12ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# distributed under the License is distributed on an 'AS IS' BASIS,
13ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# See the License for the specific language governing permissions and
15ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# limitations under the License.
16ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
17ab007efd2fc18a92330ae0be88561b085167df01Ben Chengimport os
18ab007efd2fc18a92330ae0be88561b085167df01Ben Chengimport re
19ab007efd2fc18a92330ae0be88561b085167df01Ben Chengimport string
20ab007efd2fc18a92330ae0be88561b085167df01Ben Chengimport sys
21ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
22ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
23ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# match "#00  pc 0003f52e  /system/lib/libdvm.so" for example
24ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
25ab007efd2fc18a92330ae0be88561b085167df01Ben Chengtrace_line = re.compile("(.*)(\#[0-9]+)  (..) ([0-9a-f]{8})  ([^\r\n \t]*)")
26ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
27ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# returns a list containing the function name and the file/lineno
28ab007efd2fc18a92330ae0be88561b085167df01Ben Chengdef CallAddr2Line(lib, addr):
29ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global symbols_dir
30ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global addr2line_cmd
31ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global cppfilt_cmd
32ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
33ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if lib != "":
34ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    cmd = addr2line_cmd + \
35ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng        " -f -e " + symbols_dir + lib + " 0x" + addr
36ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream = os.popen(cmd)
37ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    lines = stream.readlines()
38ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    list = map(string.strip, lines)
39ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  else:
40ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    list = []
41ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if list != []:
42ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    # Name like "move_forward_type<JavaVMOption>" causes troubles
43ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    mangled_name = re.sub('<', '\<', list[0]);
44ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    mangled_name = re.sub('>', '\>', mangled_name);
45ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    cmd = cppfilt_cmd + " " + mangled_name
46ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream = os.popen(cmd)
47ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    list[0] = stream.readline()
48ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream.close()
49ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    list = map(string.strip, list)
50ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  else:
51ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    list = [ "(unknown)", "(unknown)" ]
52ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  return list
53ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
54ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
55ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
56ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# similar to CallAddr2Line, but using objdump to find out the name of the
57ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# containing function of the specified address
58ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
59ab007efd2fc18a92330ae0be88561b085167df01Ben Chengdef CallObjdump(lib, addr):
60ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global objdump_cmd
61ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global symbols_dir
62ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
63ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  unknown = "(unknown)"
64ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  uname = os.uname()[0]
65ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if uname == "Darwin":
66ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    proc = os.uname()[-1]
67ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    if proc == "i386":
68ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      uname = "darwin-x86"
69ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    else:
70ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      uname = "darwin-ppc"
71ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  elif uname == "Linux":
72ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    uname = "linux-x86"
73ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if lib != "":
74ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    next_addr = string.atoi(addr, 16) + 1
75ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    cmd = objdump_cmd \
76ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng        + " -C -d --start-address=0x" + addr + " --stop-address=" \
77ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng        + str(next_addr) \
78ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng        + " " + symbols_dir + lib
79ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream = os.popen(cmd)
80ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    lines = stream.readlines()
81ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    map(string.strip, lines)
82ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream.close()
83ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  else:
84ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    return unknown
85ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
86ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # output looks like
87ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  #
88ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # file format elf32-littlearm
89ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  #
90ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # Disassembly of section .text:
91ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  #
92ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # 0000833c <func+0x4>:
93ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  #        833c:       701a            strb    r2, [r3, #0]
94ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  #
95ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # we want to extract the "func" part
96ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  num_lines = len(lines)
97ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if num_lines < 2:
98ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    return unknown
99ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  func_name = lines[num_lines-2]
100ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  func_regexp = re.compile("(^.*\<)(.*)(\+.*\>:$)")
101ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  components = func_regexp.match(func_name)
102ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if components is None:
103ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    return unknown
104ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  return components.group(2)
105ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
106ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
107ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# determine the symbols directory in the local build
108ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
109ab007efd2fc18a92330ae0be88561b085167df01Ben Chengdef FindSymbolsDir():
110ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global symbols_dir
111ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
112ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  try:
113ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    path = os.environ['ANDROID_PRODUCT_OUT'] + "/symbols"
114ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  except:
115ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    cmd = "CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core " \
11677f31fe7280610cd47519616f061953215d28dbfYing Wang      + "SRC_TARGET_DIR=build/target make -f build/core/config.mk " \
117ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      + "dumpvar-abs-TARGET_OUT_UNSTRIPPED"
118ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream = os.popen(cmd)
119ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    str = stream.read()
120ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    stream.close()
121ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    path = str.strip()
122ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
123ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if (not os.path.exists(path)):
124ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    print path + " not found!"
125ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    sys.exit(1)
126ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
127ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  symbols_dir = path
128ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
129ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
130ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# determine the path of binutils
131ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
132ab007efd2fc18a92330ae0be88561b085167df01Ben Chengdef SetupToolsPath():
133ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global addr2line_cmd
134ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global objdump_cmd
135ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global cppfilt_cmd
136ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  global symbols_dir
137ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
138ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  uname = os.uname()[0]
139ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if uname == "Darwin":
140aaf01f48ee2c84019edf8c76d0770a69994112b4Romain Guy    uname = "darwin-x86"
141ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  elif uname == "Linux":
142ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    uname = "linux-x86"
1431526670628fc1a44cbe553253bdcd23f078c13beBen Cheng  gcc_version = os.environ["TARGET_GCC_VERSION"]
1441526670628fc1a44cbe553253bdcd23f078c13beBen Cheng  prefix = "./prebuilts/gcc/" + uname + "/arm/arm-linux-androideabi-" + \
1451526670628fc1a44cbe553253bdcd23f078c13beBen Cheng           gcc_version + "/bin/"
1469d396e37ac695916671614ab89797652ed02538cJing Yu  addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"
147ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
148ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if (not os.path.exists(addr2line_cmd)):
149ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    try:
150f5172c7564e0d84bf02b9add47809ce10a9cff4fJing Yu      prefix = os.environ['ANDROID_BUILD_TOP'] + "/prebuilts/gcc/" + \
1511526670628fc1a44cbe553253bdcd23f078c13beBen Cheng               uname + "/arm/arm-linux-androideabi-" + gcc_version + "/bin/"
152ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    except:
153ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      prefix = "";
154ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
1559d396e37ac695916671614ab89797652ed02538cJing Yu    addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"
156ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    if (not os.path.exists(addr2line_cmd)):
157ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      print addr2line_cmd + " not found!"
158ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      sys.exit(1)
159ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
1609d396e37ac695916671614ab89797652ed02538cJing Yu  objdump_cmd = prefix + "arm-linux-androideabi-objdump"
1619d396e37ac695916671614ab89797652ed02538cJing Yu  cppfilt_cmd = prefix + "arm-linux-androideabi-c++filt"
162ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
163ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
164ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# look up the function and file/line number for a raw stack trace line
165ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# groups[0]: log tag
166ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# groups[1]: stack level
167ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# groups[2]: "pc"
168ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# groups[3]: code address
169ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng# groups[4]: library name
170ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
171ab007efd2fc18a92330ae0be88561b085167df01Ben Chengdef SymbolTranslation(groups):
172ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  lib_name = groups[4]
173ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  code_addr = groups[3]
174ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  caller = CallObjdump(lib_name, code_addr)
175ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  func_line_pair = CallAddr2Line(lib_name, code_addr)
176ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
177ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # If a callee is inlined to the caller, objdump will see the caller's
178ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # address but addr2line will report the callee's address. So the printed
179ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # format is desgined to be "caller<-callee  file:line"
180ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  if (func_line_pair[0] != caller):
181ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    print groups[0] + groups[1] + " " + caller + "<-" + \
182ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng          '  '.join(func_line_pair[:]) + " "
183ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  else:
184ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    print groups[0] + groups[1] + " " + '  '.join(func_line_pair[:]) + " "
185ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
186ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng###############################################################################
187ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
188ab007efd2fc18a92330ae0be88561b085167df01Ben Chengif __name__ == '__main__':
189ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # pass the options to adb
190ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  adb_cmd  = "adb " + ' '.join(sys.argv[1:])
191ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
192ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # setup addr2line_cmd and objdump_cmd
193ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  SetupToolsPath()
194ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
195ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # setup the symbols directory
196ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  FindSymbolsDir()
197ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
198ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # invoke the adb command and filter its output
199ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  stream = os.popen(adb_cmd)
200ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  while (True):
201ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    line = stream.readline()
202ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
203ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    # EOF reached
204ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    if (line == ''):
205ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      break
206ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
207ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    # remove the trailing \n
208ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    line = line.strip()
209ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
210ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    # see if this is a stack trace line
211ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    match = trace_line.match(line)
212ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    if (match):
213ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      groups = match.groups()
214ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      # translate raw address into symbols
215ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      SymbolTranslation(groups)
216ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng    else:
217ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng      print line
2189611ceb4608f8b64313b1c74a7ec36b64ef2daefAndy McFadden      sys.stdout.flush()
219ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng
220ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  # adb itself aborts
221ab007efd2fc18a92330ae0be88561b085167df01Ben Cheng  stream.close()
222