3 # Copyright (C) 2009 The Android Open Source Project
5 # Licensed under the Apache License, Version 2.0 (the 'License');
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an 'AS IS' BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
22 ###############################################################################
23 # match "#00 pc 0003f52e /system/lib/libdvm.so" for example
24 ###############################################################################
25 trace_line = re.compile("(.*)(\#[0-9]+) (..) ([0-9a-f]{8}) ([^\r\n \t]*)")
27 # returns a list containing the function name and the file/lineno
28 def CallAddr2Line(lib, addr):
34 cmd = addr2line_cmd + \
35 " -f -e " + symbols_dir + lib + " 0x" + addr
36 stream = os.popen(cmd)
37 lines = stream.readlines()
38 list = map(string.strip, lines)
42 # Name like "move_forward_type<JavaVMOption>" causes troubles
43 mangled_name = re.sub('<', '\<', list[0]);
44 mangled_name = re.sub('>', '\>', mangled_name);
45 cmd = cppfilt_cmd + " " + mangled_name
46 stream = os.popen(cmd)
47 list[0] = stream.readline()
49 list = map(string.strip, list)
51 list = [ "(unknown)", "(unknown)" ]
55 ###############################################################################
56 # similar to CallAddr2Line, but using objdump to find out the name of the
57 # containing function of the specified address
58 ###############################################################################
59 def CallObjdump(lib, addr):
71 elif uname == "Linux":
74 next_addr = string.atoi(addr, 16) + 1
76 + " -C -d --start-address=0x" + addr + " --stop-address=" \
78 + " " + symbols_dir + lib
79 stream = os.popen(cmd)
80 lines = stream.readlines()
81 map(string.strip, lines)
88 # file format elf32-littlearm
90 # Disassembly of section .text:
92 # 0000833c <func+0x4>:
93 # 833c: 701a strb r2, [r3, #0]
95 # we want to extract the "func" part
96 num_lines = len(lines)
99 func_name = lines[num_lines-2]
100 func_regexp = re.compile("(^.*\<)(.*)(\+.*\>:$)")
101 components = func_regexp.match(func_name)
102 if components is None:
104 return components.group(2)
106 ###############################################################################
107 # determine the symbols directory in the local build
108 ###############################################################################
109 def FindSymbolsDir():
113 path = os.environ['ANDROID_PRODUCT_OUT'] + "/symbols"
115 cmd = "CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core " \
116 + "SRC_TARGET_DIR=build/target make -f build/core/config.mk " \
117 + "dumpvar-abs-TARGET_OUT_UNSTRIPPED"
118 stream = os.popen(cmd)
123 if (not os.path.exists(path)):
124 print path + " not found!"
129 ###############################################################################
130 # determine the path of binutils
131 ###############################################################################
132 def SetupToolsPath():
138 uname = os.uname()[0]
139 if uname == "Darwin":
141 elif uname == "Linux":
143 gcc_version = os.environ["TARGET_GCC_VERSION"]
144 prefix = "./prebuilts/gcc/" + uname + "/arm/arm-linux-androideabi-" + \
145 gcc_version + "/bin/"
146 addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"
148 if (not os.path.exists(addr2line_cmd)):
150 prefix = os.environ['ANDROID_BUILD_TOP'] + "/prebuilts/gcc/" + \
151 uname + "/arm/arm-linux-androideabi-" + gcc_version + "/bin/"
155 addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"
156 if (not os.path.exists(addr2line_cmd)):
157 print addr2line_cmd + " not found!"
160 objdump_cmd = prefix + "arm-linux-androideabi-objdump"
161 cppfilt_cmd = prefix + "arm-linux-androideabi-c++filt"
163 ###############################################################################
164 # look up the function and file/line number for a raw stack trace line
166 # groups[1]: stack level
168 # groups[3]: code address
169 # groups[4]: library name
170 ###############################################################################
171 def SymbolTranslation(groups):
173 code_addr = groups[3]
174 caller = CallObjdump(lib_name, code_addr)
175 func_line_pair = CallAddr2Line(lib_name, code_addr)
177 # If a callee is inlined to the caller, objdump will see the caller's
178 # address but addr2line will report the callee's address. So the printed
179 # format is desgined to be "caller<-callee file:line"
180 if (func_line_pair[0] != caller):
181 print groups[0] + groups[1] + " " + caller + "<-" + \
182 ' '.join(func_line_pair[:]) + " "
184 print groups[0] + groups[1] + " " + ' '.join(func_line_pair[:]) + " "
186 ###############################################################################
188 if __name__ == '__main__':
189 # pass the options to adb
190 adb_cmd = "adb " + ' '.join(sys.argv[1:])
192 # setup addr2line_cmd and objdump_cmd
195 # setup the symbols directory
198 # invoke the adb command and filter its output
199 stream = os.popen(adb_cmd)
201 line = stream.readline()
207 # remove the trailing \n
210 # see if this is a stack trace line
211 match = trace_line.match(line)
213 groups = match.groups()
214 # translate raw address into symbols
215 SymbolTranslation(groups)