OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # | 2 # |
3 # Copyright (C) 2013 The Android Open Source Project | 3 # Copyright (C) 2013 The Android Open Source Project |
4 # | 4 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # you may not use this file except in compliance with 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 | 7 # You may obtain a copy of the License at |
8 # | 8 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 9 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 10 # |
11 # Unless required by applicable law or agreed to in writing, software | 11 # Unless required by applicable law or agreed to in writing, software |
12 # distributed under the License is distributed on an "AS IS" BASIS, | 12 # distributed under the License is distributed on an "AS IS" BASIS, |
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 # See the License for the specific language governing permissions and | 14 # See the License for the specific language governing permissions and |
15 # limitations under the License. | 15 # limitations under the License. |
16 | 16 |
17 """Module for looking up symbolic debugging information. | 17 """Module for looking up symbolic debugging information. |
18 | 18 |
19 The information can include symbol names, offsets, and source locations. | 19 The information can include symbol names, offsets, and source locations. |
20 """ | 20 """ |
21 | 21 |
22 import os | 22 import os |
23 import re | 23 import re |
| 24 import sys |
24 import subprocess | 25 import subprocess |
25 | 26 |
26 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)), | 27 CHROME_SRC = os.path.join(os.path.realpath(os.path.dirname(__file__)), |
27 os.pardir, os.pardir, os.pardir, os.pardir) | 28 os.pardir, os.pardir, os.pardir, os.pardir) |
28 ANDROID_BUILD_TOP = CHROME_SRC | 29 ANDROID_BUILD_TOP = CHROME_SRC |
29 SYMBOLS_DIR = CHROME_SRC | 30 SYMBOLS_DIR = CHROME_SRC |
30 CHROME_SYMBOLS_DIR = CHROME_SRC | 31 CHROME_SYMBOLS_DIR = CHROME_SRC |
31 | 32 |
32 ARCH = "arm" | 33 ARCH = "arm" |
33 | 34 |
34 TOOLCHAIN_INFO = None | 35 TOOLCHAIN_INFO = None |
35 | 36 |
| 37 sys.path.insert(0, os.path.join(CHROME_SRC, 'build', 'android')) |
| 38 from pylib.symbols import elf_symbolizer |
| 39 |
36 def Uname(): | 40 def Uname(): |
37 """'uname' for constructing prebuilt/<...> and out/host/<...> paths.""" | 41 """'uname' for constructing prebuilt/<...> and out/host/<...> paths.""" |
38 uname = os.uname()[0] | 42 uname = os.uname()[0] |
39 if uname == "Darwin": | 43 if uname == "Darwin": |
40 proc = os.uname()[-1] | 44 proc = os.uname()[-1] |
41 if proc == "i386" or proc == "x86_64": | 45 if proc == "i386" or proc == "x86_64": |
42 return "darwin-x86" | 46 return "darwin-x86" |
43 return "darwin-ppc" | 47 return "darwin-ppc" |
44 if uname == "Linux": | 48 if uname == "Linux": |
45 return "linux-x86" | 49 return "linux-x86" |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 each address has a list of associated symbols and locations | 237 each address has a list of associated symbols and locations |
234 or an empty list if no symbol information was found. | 238 or an empty list if no symbol information was found. |
235 | 239 |
236 If the function has been inlined then the list may contain | 240 If the function has been inlined then the list may contain |
237 more than one element with the symbols for the most deeply | 241 more than one element with the symbols for the most deeply |
238 nested inlined location appearing first. | 242 nested inlined location appearing first. |
239 """ | 243 """ |
240 if not lib: | 244 if not lib: |
241 return None | 245 return None |
242 | 246 |
243 | |
244 symbols = SYMBOLS_DIR + lib | 247 symbols = SYMBOLS_DIR + lib |
245 if not os.path.isfile(symbols): | 248 if not os.path.isfile(symbols): |
246 return None | 249 return None |
247 | 250 |
| 251 addrs = sorted(unique_addrs) |
| 252 result = {} |
| 253 |
| 254 def _Callback(sym, addr): |
| 255 records = [] |
| 256 while sym: # Traverse all the inlines following the |inlined_by| chain. |
| 257 if sym.source_path: |
| 258 location = '%s:%d' % (sym.source_path, sym.source_line) |
| 259 else: |
| 260 location = None |
| 261 records += [(sym.name, location)] |
| 262 sym = sym.inlined_by |
| 263 result[addr] = records |
| 264 |
248 (label, platform, target) = FindToolchain() | 265 (label, platform, target) = FindToolchain() |
249 cmd = [ToolPath("addr2line"), "--functions", "--inlines", | 266 symbolizer = elf_symbolizer.ELFSymbolizer( |
250 "--demangle", "--exe=" + symbols] | 267 elf_file_path=symbols, |
251 child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | 268 addr2line_path=ToolPath("addr2line"), |
| 269 callback=_Callback, |
| 270 inlines=True) |
252 | 271 |
253 result = {} | |
254 addrs = sorted(unique_addrs) | |
255 for addr in addrs: | 272 for addr in addrs: |
256 child.stdin.write("0x%s\n" % addr) | 273 symbolizer.SymbolizeAsync(int(addr, 16), addr) |
257 child.stdin.flush() | 274 symbolizer.Join() |
258 records = [] | |
259 first = True | |
260 while True: | |
261 symbol = child.stdout.readline().strip() | |
262 if symbol == "??": | |
263 symbol = None | |
264 location = child.stdout.readline().strip() | |
265 if location == "??:0": | |
266 location = None | |
267 if symbol is None and location is None: | |
268 break | |
269 records.append((symbol, location)) | |
270 if first: | |
271 # Write a blank line as a sentinel so we know when to stop | |
272 # reading inlines from the output. | |
273 # The blank line will cause addr2line to emit "??\n??:0\n". | |
274 child.stdin.write("\n") | |
275 first = False | |
276 result[addr] = records | |
277 child.stdin.close() | |
278 child.stdout.close() | |
279 return result | 275 return result |
280 | 276 |
281 | 277 |
282 def StripPC(addr): | 278 def StripPC(addr): |
283 """Strips the Thumb bit a program counter address when appropriate. | 279 """Strips the Thumb bit a program counter address when appropriate. |
284 | 280 |
285 Args: | 281 Args: |
286 addr: the program counter address | 282 addr: the program counter address |
287 | 283 |
288 Returns: | 284 Returns: |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 process.stdin.write("\n") | 378 process.stdin.write("\n") |
383 process.stdin.close() | 379 process.stdin.close() |
384 demangled_symbol = process.stdout.readline().strip() | 380 demangled_symbol = process.stdout.readline().strip() |
385 process.stdout.close() | 381 process.stdout.close() |
386 return demangled_symbol | 382 return demangled_symbol |
387 | 383 |
388 def FormatSymbolWithOffset(symbol, offset): | 384 def FormatSymbolWithOffset(symbol, offset): |
389 if offset == 0: | 385 if offset == 0: |
390 return symbol | 386 return symbol |
391 return "%s+%d" % (symbol, offset) | 387 return "%s+%d" % (symbol, offset) |
OLD | NEW |