Chromium Code Reviews| Index: third_party/android_platform/development/scripts/stack_libs.py |
| diff --git a/third_party/android_platform/development/scripts/stack_libs.py b/third_party/android_platform/development/scripts/stack_libs.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..7e61b394bc47b319bf5c9588bbd289cb7d9f634a |
| --- /dev/null |
| +++ b/third_party/android_platform/development/scripts/stack_libs.py |
| @@ -0,0 +1,110 @@ |
| +#!/usr/bin/env python |
| +# |
| +# 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.
|
| +# |
| +# Licensed under the Apache License, Version 2.0 (the "License"); |
| +# you may not use this file except in compliance with the License. |
| +# You may obtain a copy of the License at |
| +# |
| +# http://www.apache.org/licenses/LICENSE-2.0 |
| +# |
| +# Unless required by applicable law or agreed to in writing, software |
| +# distributed under the License is distributed on an "AS IS" BASIS, |
| +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| +# See the License for the specific language governing permissions and |
| +# limitations under the License. |
| + |
| +"""Identifies address adjustments required for native crash dumps.""" |
| + |
| +import glob |
| +import os.path |
| +import subprocess |
| + |
| + |
| +def _HasElfHeader(path): |
| + """Return True if the file at the given path has an ELF magic header. |
| + |
| + Minimal check only, for 'ELF' in bytes 1 to 3 of the file. Filters out |
| + the zero-byte false-positives such as libchromeview.so returned by glob. |
| + |
| + Args: |
| + path: Path to file to check. |
| + Returns: |
| + True or False |
| + """ |
| + with open(path) as stream: |
| + elf_header = stream.read(4) |
| + return len(elf_header) == 4 and elf_header[1:4] == 'ELF' |
| + |
| + |
| +def _ReadElfProgramHeaders(lib): |
| + """Return an iterable of program headers, from 'readelf -l ...'. |
| + |
| + Uses the platform readelf in all cases. This is somewhat lazy, but suffices |
| + in practice because program headers in ELF files are architecture-agnostic. |
| + |
| + Args: |
| + lib: Library file to read. |
| + Returns: |
| + [readelf -l output line, ...] |
| + """ |
| + string = subprocess.check_output(['readelf', '-l', lib]) |
| + return string.split('\n') |
| + |
| + |
| +def _FindMinLoadVaddr(lib): |
| + """Return the minimum VirtAddr field of all library LOAD segments. |
| + |
| + Args: |
| + lib: Library file to read. |
| + Returns: |
| + Min VirtAddr field for all LOAD segments, or 0 if none found. |
| + """ |
| + vaddrs = [] |
| + # Locate LOAD lines and find the smallest VirtAddr field, eg: |
| + # Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
| + # LOAD 0x000000 0x001d6000 0x001d6000 0x20f63fc 0x20f63fc R E 0x1000 |
| + # LOAD 0x20f6970 0x022cd970 0x022cd970 0x182df8 0x1b4490 RW 0x1000 |
| + # would return 0x1d6000. Ignores all non-LOAD lines. |
| + for line in _ReadElfProgramHeaders(lib): |
| + elements = line.split() |
| + if elements and elements[0] == 'LOAD': |
| + vaddrs.append(int(elements[2], 16)) |
| + if vaddrs: |
| + return min(vaddrs) |
| + return 0 |
| + |
| + |
| +def GetLoadVaddrs(apk_dir): |
| + """Return a dictionary of minimum VirtAddr fields for libraries in apk_dir. |
| + |
| + The dictionary returned may be passed to stack_core.ConvertTrace(). In |
| + pre-M Android releases the addresses printed by debuggerd into tombstones |
| + do not take account of non-zero vaddrs. Here we collect this information, |
| + so that we can use it later to correct such debuggerd tombstones. |
| + |
| + Args: |
| + apk_dir: Path to APK staging directory. |
| + Returns: |
| + {'libchrome.so': 12345, ...} |
| + """ |
| + pathname = apk_dir + '/libs/*/*.so' |
| + libs = [lib for lib in glob.glob(pathname) if _HasElfHeader(lib)] |
| + |
| + load_vaddrs = {} |
| + for lib in libs: |
| + min_vaddr = _FindMinLoadVaddr(lib) |
| + if min_vaddr: |
| + # Store with the library basename as the key. This is because once on |
| + # the device its path may not fully match its place in the APK staging |
| + # directory |
| + load_vaddrs[os.path.basename(lib)] = min_vaddr |
| + |
| + # Direct load from APK causes debuggerd to tag trace lines as if from the |
| + # file .../base.apk. So if we encounter a libchrome.so with packed |
| + # relocations, replicate this as base.apk so that later adjustment code |
| + # finds the appropriate adjustment. |
| + if 'libchrome.so' in load_vaddrs: |
| + load_vaddrs['base.apk'] = load_vaddrs['libchrome.so'] |
| + |
| + return load_vaddrs |