Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(551)

Unified Diff: third_party/android_platform/development/scripts/stack_libs.py

Issue 1412223008: stack: Adjust Pre-M Android incorrect debuggerd addresses. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix bot breakage Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..ee5a67e0a0272c76c5f6a056448b23a120782ec7
--- /dev/null
+++ b/third_party/android_platform/development/scripts/stack_libs.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Identifies address adjustments required for native crash dumps."""
+
+import glob
+import os.path
+import subprocess
+
+
+_BASE_APK = 'base.apk'
+_LIBCHROME_SO = 'libchrome.so'
+
+
+def GetTargetAndroidVersionNumber(lines):
+ """Return the Android major version number from the build fingerprint.
+
+ Args:
+ lines: Lines read from the tombstone file, before preprocessing.
+ Returns:
+ 5, 6, etc, or None if not determinable (developer build?)
+ """
+ # For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5.
+ for line in lines:
+ if line.startswith('Build fingerprint: '):
+ fingerprint = line.split()[2]
+ version = fingerprint.split('/')[2].split(':')[1].split('.')[0]
+ try:
+ return int(version)
+ except ValueError:
+ return None
+ return None
+
+
+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

Powered by Google App Engine
This is Rietveld 408576698