OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # | |
3 # Copyright (C) 2015 The Android Open Source Project | |
rmcilroy
2015/10/23 16:25:10
Was this taken straight from the Android project w
simonb (inactive)
2015/10/26 12:38:31
No, the file is brand new and only in here. Local
rmcilroy
2015/10/26 16:42:17
Acknowledged.
| |
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 """Identifies address adjustments required for native crash dumps.""" | |
18 | |
19 import glob | |
20 import os.path | |
21 import subprocess | |
22 | |
23 | |
24 def _HasElfHeader(path): | |
25 """Return True if the file at the given path has an ELF magic header. | |
26 | |
27 Minimal check only, for 'ELF' in bytes 1 to 3 of the file. Filters out | |
28 the zero-byte false-positives such as libchromeview.so returned by glob. | |
29 | |
30 Args: | |
31 path: Path to file to check. | |
32 Returns: | |
33 True or False | |
34 """ | |
35 with open(path) as stream: | |
36 elf_header = stream.read(4) | |
37 return len(elf_header) == 4 and elf_header[1:4] == 'ELF' | |
38 | |
39 | |
40 def _ReadElfProgramHeaders(lib): | |
41 """Return an iterable of program headers, from 'readelf -l ...'. | |
42 | |
43 Uses the platform readelf in all cases. This is somewhat lazy, but suffices | |
44 in practice because program headers in ELF files are architecture-agnostic. | |
45 | |
46 Args: | |
47 lib: Library file to read. | |
48 Returns: | |
49 [readelf -l output line, ...] | |
50 """ | |
51 string = subprocess.check_output(['readelf', '-l', lib]) | |
52 return string.split('\n') | |
53 | |
54 | |
55 def _FindMinLoadVaddr(lib): | |
56 """Return the minimum VirtAddr field of all library LOAD segments. | |
57 | |
58 Args: | |
59 lib: Library file to read. | |
60 Returns: | |
61 Min VirtAddr field for all LOAD segments, or 0 if none found. | |
62 """ | |
63 vaddrs = [] | |
64 # Locate LOAD lines and find the smallest VirtAddr field, eg: | |
65 # Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align | |
66 # LOAD 0x000000 0x001d6000 0x001d6000 0x20f63fc 0x20f63fc R E 0x1000 | |
67 # LOAD 0x20f6970 0x022cd970 0x022cd970 0x182df8 0x1b4490 RW 0x1000 | |
68 # would return 0x1d6000. Ignores all non-LOAD lines. | |
69 for line in _ReadElfProgramHeaders(lib): | |
70 elements = line.split() | |
71 if elements and elements[0] == 'LOAD': | |
72 vaddrs.append(int(elements[2], 16)) | |
73 if vaddrs: | |
74 return min(vaddrs) | |
75 return 0 | |
76 | |
77 | |
78 def GetLoadVaddrs(apk_dir): | |
79 """Return a dictionary of minimum VirtAddr fields for libraries in apk_dir. | |
80 | |
81 The dictionary returned may be passed to stack_core.ConvertTrace(). In | |
82 pre-M Android releases the addresses printed by debuggerd into tombstones | |
83 do not take account of non-zero vaddrs. Here we collect this information, | |
84 so that we can use it later to correct such debuggerd tombstones. | |
85 | |
86 Args: | |
87 apk_dir: Path to APK staging directory. | |
88 Returns: | |
89 {'libchrome.so': 12345, ...} | |
90 """ | |
91 pathname = apk_dir + '/libs/*/*.so' | |
92 libs = [lib for lib in glob.glob(pathname) if _HasElfHeader(lib)] | |
93 | |
94 load_vaddrs = {} | |
95 for lib in libs: | |
96 min_vaddr = _FindMinLoadVaddr(lib) | |
97 if min_vaddr: | |
98 # Store with the library basename as the key. This is because once on | |
99 # the device its path may not fully match its place in the APK staging | |
100 # directory | |
101 load_vaddrs[os.path.basename(lib)] = min_vaddr | |
102 | |
103 # Direct load from APK causes debuggerd to tag trace lines as if from the | |
104 # file .../base.apk. So if we encounter a libchrome.so with packed | |
105 # relocations, replicate this as base.apk so that later adjustment code | |
106 # finds the appropriate adjustment. | |
107 if 'libchrome.so' in load_vaddrs: | |
108 load_vaddrs['base.apk'] = load_vaddrs['libchrome.so'] | |
109 | |
110 return load_vaddrs | |
OLD | NEW |