OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 | 7 |
8 """Identifies address adjustments required for native crash dumps.""" | 8 """Identifies address adjustments required for native crash dumps.""" |
9 | 9 |
10 import glob | 10 import glob |
11 import os.path | 11 import os.path |
| 12 import re |
12 import subprocess | 13 import subprocess |
13 | 14 |
14 | 15 |
15 _BASE_APK = 'base.apk' | 16 _BASE_APK = 'base.apk' |
16 _LIBCHROME_SO = 'libchrome.so' | 17 _LIBCHROME_SO = 'libchrome.so' |
17 | 18 |
| 19 _BUILD_FINGERPRINT_RE = re.compile('.*Build fingerprint: (.*)$') |
| 20 |
18 | 21 |
19 def GetTargetAndroidVersionNumber(lines): | 22 def GetTargetAndroidVersionNumber(lines): |
20 """Return the Android major version number from the build fingerprint. | 23 """Return the Android major version number from the build fingerprint. |
21 | 24 |
22 Args: | 25 Args: |
23 lines: Lines read from the tombstone file, before preprocessing. | 26 lines: Lines read from the tombstone file, before preprocessing. |
24 Returns: | 27 Returns: |
25 5, 6, etc, or None if not determinable (developer build?) | 28 5, 6, etc, or None if not determinable (developer build?) |
26 """ | 29 """ |
27 # For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5. | 30 # For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5. |
28 for line in lines: | 31 for line in lines: |
29 if line.startswith('Build fingerprint: '): | 32 m = _BUILD_FINGERPRINT_RE.match(line) |
30 fingerprint = line.split()[2] | 33 if not m: |
| 34 continue |
| 35 fingerprint = m.group(1) |
| 36 try: |
31 version = fingerprint.split('/')[2].split(':')[1].split('.')[0] | 37 version = fingerprint.split('/')[2].split(':')[1].split('.')[0] |
32 try: | 38 return int(version) |
33 return int(version) | 39 except Exception: |
34 except ValueError: | 40 pass |
35 return None | |
36 return None | 41 return None |
37 | 42 |
38 | 43 |
39 def _HasElfHeader(path): | 44 def _HasElfHeader(path): |
40 """Return True if the file at the given path has an ELF magic header. | 45 """Return True if the file at the given path has an ELF magic header. |
41 | 46 |
42 Minimal check only, for 'ELF' in bytes 1 to 3 of the file. Filters out | 47 Minimal check only, for 'ELF' in bytes 1 to 3 of the file. Filters out |
43 the zero-byte false-positives such as libchromeview.so returned by glob. | 48 the zero-byte false-positives such as libchromeview.so returned by glob. |
44 | 49 |
45 Args: | 50 Args: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 # would return 0x1d6000. Ignores all non-LOAD lines. | 88 # would return 0x1d6000. Ignores all non-LOAD lines. |
84 for line in _ReadElfProgramHeaders(lib): | 89 for line in _ReadElfProgramHeaders(lib): |
85 elements = line.split() | 90 elements = line.split() |
86 if elements and elements[0] == 'LOAD': | 91 if elements and elements[0] == 'LOAD': |
87 vaddrs.append(int(elements[2], 16)) | 92 vaddrs.append(int(elements[2], 16)) |
88 if vaddrs: | 93 if vaddrs: |
89 return min(vaddrs) | 94 return min(vaddrs) |
90 return 0 | 95 return 0 |
91 | 96 |
92 | 97 |
93 def GetLoadVaddrs(stripped_libs_dir): | 98 def GetLoadVaddrs(stripped_libs=None, stripped_libs_dir=None): |
94 """Return a dict of minimum VirtAddr for libraries in the given directory. | 99 """Return a dict of minimum VirtAddr for libraries in the given directory. |
95 | 100 |
96 The dictionary returned may be passed to stack_core.ConvertTrace(). In | 101 The dictionary returned may be passed to stack_core.ConvertTrace(). In |
97 pre-M Android releases the addresses printed by debuggerd into tombstones | 102 pre-M Android releases the addresses printed by debuggerd into tombstones |
98 do not take account of non-zero vaddrs. Here we collect this information, | 103 do not take account of non-zero vaddrs. Here we collect this information, |
99 so that we can use it later to correct such debuggerd tombstones. | 104 so that we can use it later to correct such debuggerd tombstones. |
100 | 105 |
101 Args: | 106 Args: |
102 stripped_libs_dir: Path to directory containing apk's stripped libraries. | 107 stripped_libs_dir: Path to directory containing apk's stripped libraries. |
103 Returns: | 108 Returns: |
104 {'libchrome.so': 12345, ...} | 109 {'libchrome.so': 12345, ...} |
105 """ | 110 """ |
106 libs = glob.glob(os.path.join(stripped_libs_dir, '*.so')) | 111 if not stripped_libs: |
107 libs = [l for l in libs if _HasElfHeader(l)] | 112 stripped_libs = [] |
| 113 if stripped_libs_dir: |
| 114 stripped_libs.extend(glob.glob(os.path.join(stripped_libs_dir, '*.so'))) |
| 115 libs = [l for l in stripped_libs if _HasElfHeader(l)] |
108 | 116 |
109 load_vaddrs = {} | 117 load_vaddrs = {} |
110 for lib in libs: | 118 for lib in libs: |
111 min_vaddr = _FindMinLoadVaddr(lib) | 119 min_vaddr = _FindMinLoadVaddr(lib) |
112 if min_vaddr: | 120 if min_vaddr: |
113 # Store with the library basename as the key. This is because once on | 121 # Store with the library basename as the key. This is because once on |
114 # the device its path may not fully match its place in the APK staging | 122 # the device its path may not fully match its place in the APK staging |
115 # directory | 123 # directory |
116 load_vaddrs[os.path.basename(lib)] = min_vaddr | 124 load_vaddrs[os.path.basename(lib)] = min_vaddr |
117 | 125 |
118 # Direct load from APK causes debuggerd to tag trace lines as if from the | 126 # Direct load from APK causes debuggerd to tag trace lines as if from the |
119 # file .../base.apk. So if we encounter a libchrome.so with packed | 127 # file .../base.apk. So if we encounter a libchrome.so with packed |
120 # relocations, replicate this as base.apk so that later adjustment code | 128 # relocations, replicate this as base.apk so that later adjustment code |
121 # finds the appropriate adjustment. | 129 # finds the appropriate adjustment. |
122 if _LIBCHROME_SO in load_vaddrs: | 130 if _LIBCHROME_SO in load_vaddrs: |
123 load_vaddrs[_BASE_APK] = load_vaddrs[_LIBCHROME_SO] | 131 load_vaddrs[_BASE_APK] = load_vaddrs[_LIBCHROME_SO] |
124 | 132 |
125 return load_vaddrs | 133 return load_vaddrs |
OLD | NEW |