OSDN Git Service

Merge "Doc change: css for n5 device video frame." into klp-dev
[android-x86/build.git] / tools / adbs
1 #!/usr/bin/env python
2
3 # Copyright (C) 2009 The Android Open Source Project
4 #
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
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 import os
18 import re
19 import string
20 import sys
21
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]*)")
26
27 # returns a list containing the function name and the file/lineno
28 def CallAddr2Line(lib, addr):
29   global symbols_dir
30   global addr2line_cmd
31   global cppfilt_cmd
32
33   if lib != "":
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)
39   else:
40     list = []
41   if list != []:
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()
48     stream.close()
49     list = map(string.strip, list)
50   else:
51     list = [ "(unknown)", "(unknown)" ]
52   return list
53
54
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):
60   global objdump_cmd
61   global symbols_dir
62
63   unknown = "(unknown)"
64   uname = os.uname()[0]
65   if uname == "Darwin":
66     proc = os.uname()[-1]
67     if proc == "i386":
68       uname = "darwin-x86"
69     else:
70       uname = "darwin-ppc"
71   elif uname == "Linux":
72     uname = "linux-x86"
73   if lib != "":
74     next_addr = string.atoi(addr, 16) + 1
75     cmd = objdump_cmd \
76         + " -C -d --start-address=0x" + addr + " --stop-address=" \
77         + str(next_addr) \
78         + " " + symbols_dir + lib
79     stream = os.popen(cmd)
80     lines = stream.readlines()
81     map(string.strip, lines)
82     stream.close()
83   else:
84     return unknown
85
86   # output looks like
87   #
88   # file format elf32-littlearm
89   #
90   # Disassembly of section .text:
91   #
92   # 0000833c <func+0x4>:
93   #        833c:       701a            strb    r2, [r3, #0]
94   #
95   # we want to extract the "func" part
96   num_lines = len(lines)
97   if num_lines < 2:
98     return unknown
99   func_name = lines[num_lines-2]
100   func_regexp = re.compile("(^.*\<)(.*)(\+.*\>:$)")
101   components = func_regexp.match(func_name)
102   if components is None:
103     return unknown
104   return components.group(2)
105
106 ###############################################################################
107 # determine the symbols directory in the local build
108 ###############################################################################
109 def FindSymbolsDir():
110   global symbols_dir
111
112   try:
113     path = os.environ['ANDROID_PRODUCT_OUT'] + "/symbols"
114   except:
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)
119     str = stream.read()
120     stream.close()
121     path = str.strip()
122
123   if (not os.path.exists(path)):
124     print path + " not found!"
125     sys.exit(1)
126
127   symbols_dir = path
128
129 ###############################################################################
130 # determine the path of binutils
131 ###############################################################################
132 def SetupToolsPath():
133   global addr2line_cmd
134   global objdump_cmd
135   global cppfilt_cmd
136   global symbols_dir
137
138   uname = os.uname()[0]
139   if uname == "Darwin":
140     uname = "darwin-x86"
141   elif uname == "Linux":
142     uname = "linux-x86"
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"
147
148   if (not os.path.exists(addr2line_cmd)):
149     try:
150       prefix = os.environ['ANDROID_BUILD_TOP'] + "/prebuilts/gcc/" + \
151                uname + "/arm/arm-linux-androideabi-" + gcc_version + "/bin/"
152     except:
153       prefix = "";
154
155     addr2line_cmd = prefix + "arm-linux-androideabi-addr2line"
156     if (not os.path.exists(addr2line_cmd)):
157       print addr2line_cmd + " not found!"
158       sys.exit(1)
159
160   objdump_cmd = prefix + "arm-linux-androideabi-objdump"
161   cppfilt_cmd = prefix + "arm-linux-androideabi-c++filt"
162
163 ###############################################################################
164 # look up the function and file/line number for a raw stack trace line
165 # groups[0]: log tag
166 # groups[1]: stack level
167 # groups[2]: "pc"
168 # groups[3]: code address
169 # groups[4]: library name
170 ###############################################################################
171 def SymbolTranslation(groups):
172   lib_name = groups[4]
173   code_addr = groups[3]
174   caller = CallObjdump(lib_name, code_addr)
175   func_line_pair = CallAddr2Line(lib_name, code_addr)
176
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[:]) + " "
183   else:
184     print groups[0] + groups[1] + " " + '  '.join(func_line_pair[:]) + " "
185
186 ###############################################################################
187
188 if __name__ == '__main__':
189   # pass the options to adb
190   adb_cmd  = "adb " + ' '.join(sys.argv[1:])
191
192   # setup addr2line_cmd and objdump_cmd
193   SetupToolsPath()
194
195   # setup the symbols directory
196   FindSymbolsDir()
197
198   # invoke the adb command and filter its output
199   stream = os.popen(adb_cmd)
200   while (True):
201     line = stream.readline()
202
203     # EOF reached
204     if (line == ''):
205       break
206
207     # remove the trailing \n
208     line = line.strip()
209
210     # see if this is a stack trace line
211     match = trace_line.match(line)
212     if (match):
213       groups = match.groups()
214       # translate raw address into symbols
215       SymbolTranslation(groups)
216     else:
217       print line
218       sys.stdout.flush()
219
220   # adb itself aborts
221   stream.close()