Commit 276cc56b authored by jbudorick's avatar jbudorick Committed by Commit bot

[Android] Fix stack symbolization when packed relocations are on.

We had been looking in lib.stripped for the library when symbolizing
debuggerd traces. The libraries in lib.stripped are not the ones with
packed relocations, though, so the resulting symbolization was wrong.

This CL generates a wrapper script around the stack symbolization
script that points to the correct library to use for symbolization.
It also contains a few tests that intentionally crash in various ways.
These are all disabled by default and should only ever be run manually
for testing out instrumentation test crash tooling.

BUG=712265

Review-Url: https://codereview.chromium.org/2840193003
Cr-Commit-Position: refs/heads/master@{#468206}
parent b6da4355
...@@ -353,6 +353,8 @@ _VALID_OS_MACROS = ( ...@@ -353,6 +353,8 @@ _VALID_OS_MACROS = (
_ANDROID_SPECIFIC_PYDEPS_FILES = [ _ANDROID_SPECIFIC_PYDEPS_FILES = [
'build/android/test_runner.pydeps', 'build/android/test_runner.pydeps',
'build/android/test_wrapper/logdog_wrapper.pydeps', 'build/android/test_wrapper/logdog_wrapper.pydeps',
'build/secondary/third_party/android_platform/'
'development/scripts/stack.pydeps',
'net/tools/testserver/testserver.pydeps', 'net/tools/testserver/testserver.pydeps',
] ]
......
#!/usr/bin/env python
# Copyright 2017 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.
import argparse
import os
import sys
import textwrap
from util import build_utils
SCRIPT_TEMPLATE = textwrap.dedent(
"""\
#!/usr/bin/env python
#
# This file was generated by build/android/gyp/create_stack_script.py
import os
import sys
def main(argv):
script_directory = os.path.dirname(__file__)
resolve = lambda p: os.path.abspath(os.path.join(script_directory, p))
script_path = resolve('{script_path}')
script_args = {script_args}
script_path_args = {script_path_args}
for arg, path in script_path_args:
script_args.extend([arg, resolve(path)])
script_cmd = [script_path] + script_args + argv
print ' '.join(script_cmd)
os.execv(script_path, script_cmd)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
""")
def main(args):
parser = argparse.ArgumentParser()
build_utils.AddDepfileOption(parser)
parser.add_argument(
'--script-path',
help='Path to the wrapped script.')
parser.add_argument(
'--script-output-path',
help='Path to the output script.')
group = parser.add_argument_group('Path arguments')
group.add_argument('--output-directory')
group.add_argument('--packed-libs')
args, script_args = parser.parse_known_args(build_utils.ExpandFileArgs(args))
def relativize(p):
return os.path.relpath(p, os.path.dirname(args.script_output_path))
script_path = relativize(args.script_path)
script_path_args = []
if args.output_directory:
script_path_args.append(
('--output-directory', relativize(args.output_directory)))
if args.packed_libs:
for p in build_utils.ParseGnList(args.packed_libs):
script_path_args.append(('--packed-lib', relativize(p)))
with open(args.script_output_path, 'w') as script:
script.write(SCRIPT_TEMPLATE.format(
script_path=script_path,
script_args=script_args,
script_path_args=script_path_args))
os.chmod(args.script_output_path, 0750)
if args.depfile:
build_utils.WriteDepfile(args.depfile, args.script_output_path)
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
...@@ -638,6 +638,61 @@ template("test_runner_script") { ...@@ -638,6 +638,61 @@ template("test_runner_script") {
} }
} }
template("stack_script") {
forward_variables_from(invoker, [ "testonly" ])
_stack_target_name = invoker.stack_target_name
action(target_name) {
forward_variables_from(invoker,
[
"data_deps",
"deps",
])
if (!defined(deps)) {
deps = []
}
if (!defined(data_deps)) {
data_deps = []
}
data_deps +=
[ "//third_party/android_platform/development/scripts:stack_py" ]
script = "//build/android/gyp/create_stack_script.py"
depfile = "$target_gen_dir/$target_name.d"
_stack_script = "//third_party/android_platform/development/scripts/stack"
_generated_script = "$root_build_dir/bin/stack_${_stack_target_name}"
outputs = [
_generated_script,
]
data = [
_generated_script,
]
args = [
"--depfile",
rebase_path(depfile, root_build_dir),
"--output-directory",
rebase_path(root_build_dir, root_build_dir),
"--script-path",
rebase_path(_stack_script, root_build_dir),
"--script-output-path",
rebase_path(_generated_script, root_build_dir),
"--arch=$target_cpu",
]
if (defined(invoker.packed_libraries)) {
args += [
"--packed-libs",
invoker.packed_libraries,
]
}
}
}
if (enable_java_templates) { if (enable_java_templates) {
import("//build/config/zip.gni") import("//build/config/zip.gni")
import("//third_party/ijar/ijar.gni") import("//third_party/ijar/ijar.gni")
......
...@@ -2100,6 +2100,17 @@ if (enable_java_templates) { ...@@ -2100,6 +2100,17 @@ if (enable_java_templates) {
_extra_native_libs_deps += _extra_native_libs_deps +=
[ "//base/android/linker:chromium_android_linker" ] [ "//base/android/linker:chromium_android_linker" ]
} }
_create_stack_script_rule_name = "${_template_name}__stack_script"
_final_deps += [ ":${_create_stack_script_rule_name}" ]
stack_script(_create_stack_script_rule_name) {
stack_target_name = invoker.target_name
deps = _native_libs_deps
if (_native_libs_deps != [] && _enable_relocation_packing) {
packed_libraries = _native_libs_file_arg
deps += [ _native_libs_file_arg_dep ]
}
}
} }
if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) { if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) {
_extra_native_libs_even_when_incremental += invoker.loadable_modules _extra_native_libs_even_when_incremental += invoker.loadable_modules
......
...@@ -38,7 +38,8 @@ def _ComputePythonDependencies(): ...@@ -38,7 +38,8 @@ def _ComputePythonDependencies():
if not path.startswith(_SRC_ROOT): if not path.startswith(_SRC_ROOT):
continue continue
if path.endswith('.pyc'): if (path.endswith('.pyc')
or (path.endswith('c') and not os.path.splitext(path)[1])):
path = path[:-1] path = path[:-1]
src_paths.add(path) src_paths.add(path)
......
# Copyright 2017 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.
group("stack_py") {
_py_files = read_file(
"//build/secondary/third_party/android_platform/development/scripts/stack.pydeps",
"list lines")
set_sources_assignment_filter([ "#*" ])
sources = _py_files
data = sources
}
# Generated by running:
# build/print_python_deps.py --root third_party/android_platform/development/scripts --output build/secondary/third_party/android_platform/development/scripts/stack.pydeps third_party/android_platform/development/scripts/stack
../../../../build/android/pylib/__init__.py
../../../../build/android/pylib/constants/__init__.py
../../../../build/android/pylib/symbols/__init__.py
../../../../build/android/pylib/symbols/elf_symbolizer.py
../../../catapult/devil/devil/__init__.py
../../../catapult/devil/devil/android/__init__.py
../../../catapult/devil/devil/android/constants/__init__.py
../../../catapult/devil/devil/android/constants/chrome.py
../../../catapult/devil/devil/android/sdk/__init__.py
../../../catapult/devil/devil/android/sdk/keyevent.py
../../../catapult/devil/devil/android/sdk/version_codes.py
../../../catapult/devil/devil/constants/__init__.py
../../../catapult/devil/devil/constants/exit_codes.py
stack
stack_core.py
stack_libs.py
symbol.py
...@@ -1628,6 +1628,7 @@ chrome_test_java_sources = [ ...@@ -1628,6 +1628,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java", "javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java",
"javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java", "javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java",
"javatests/src/org/chromium/chrome/test/ParametersOnMultiTest.java", "javatests/src/org/chromium/chrome/test/ParametersOnMultiTest.java",
"javatests/src/org/chromium/chrome/test/crash/IntentionalCrashTest.java",
"javatests/src/org/chromium/chrome/test/util/ChromeSigninUtilsTest.java", "javatests/src/org/chromium/chrome/test/util/ChromeSigninUtilsTest.java",
"javatests/src/org/chromium/chrome/test/util/parameters/SigninParametersTest.java", "javatests/src/org/chromium/chrome/test/util/parameters/SigninParametersTest.java",
] ]
......
// Copyright 2017 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.
package org.chromium.chrome.test.crash;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
/** Tests that intentionally crash in different ways.
*
* These are all purposefully disabled and should only be run manually.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
public class IntentionalCrashTest {
@Rule
public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule(ChromeActivity.class);
@DisabledTest
@Test
public void testRendererCrash() {
try {
mActivityTestRule.startMainActivityWithURL("chrome://crash");
} catch (InterruptedException e) {
Assert.fail(e.toString());
}
}
@DisabledTest
@Test
public void testBrowserCrash() {
try {
mActivityTestRule.startMainActivityWithURL("chrome://inducebrowsercrashforrealz");
} catch (InterruptedException e) {
Assert.fail(e.toString());
}
}
@DisabledTest
@Test
public void testJavaCrash() {
try {
mActivityTestRule.startMainActivityWithURL("chrome://java-crash");
} catch (InterruptedException e) {
Assert.fail(e.toString());
}
}
@DisabledTest
@Test
public void testGpuCrash() {
try {
mActivityTestRule.startMainActivityWithURL("chrome://gpucrash");
} catch (InterruptedException e) {
Assert.fail(e.toString());
}
}
}
...@@ -145,6 +145,7 @@ def main(argv): ...@@ -145,6 +145,7 @@ def main(argv):
"output-directory=", "output-directory=",
"symbols-dir=", "symbols-dir=",
"symbols-zip=", "symbols-zip=",
"packed-lib=",
"arch=", "arch=",
"fallback-monochrome", "fallback-monochrome",
"verbose", "verbose",
...@@ -154,9 +155,9 @@ def main(argv): ...@@ -154,9 +155,9 @@ def main(argv):
zip_arg = None zip_arg = None
more_info = False more_info = False
packed_relocation_adjustments = "unknown"
fallback_monochrome = False fallback_monochrome = False
arch_defined = False arch_defined = False
packed_libs = []
for option, value in options: for option, value in options:
if option == "--help": if option == "--help":
PrintUsage() PrintUsage()
...@@ -171,10 +172,8 @@ def main(argv): ...@@ -171,10 +172,8 @@ def main(argv):
symbol.CHROME_SYMBOLS_DIR = os.path.join(symbol.CHROME_SRC, value) symbol.CHROME_SYMBOLS_DIR = os.path.join(symbol.CHROME_SRC, value)
elif option == "--output-directory": elif option == "--output-directory":
constants.SetOutputDirectory(value) constants.SetOutputDirectory(value)
elif option == "--packed-relocation-adjustments": elif option == "--packed-lib":
packed_relocation_adjustments = True packed_libs.append(os.path.expanduser(value))
elif option == "--no-packed-relocation-adjustments":
packed_relocation_adjustments = False
elif option == "--more-info": elif option == "--more-info":
more_info = True more_info = True
elif option == "--less-info": elif option == "--less-info":
...@@ -183,6 +182,11 @@ def main(argv): ...@@ -183,6 +182,11 @@ def main(argv):
fallback_monochrome = True fallback_monochrome = True
elif option == "--verbose": elif option == "--verbose":
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
elif option in (
'--packed-relocation-adjustments',
'--no-packed-relocation-adjustments'):
print ('--[no-]packed-relocation-adjustments options are deprecated. '
'Specify packed libs directory instead.')
if len(arguments) > 1: if len(arguments) > 1:
PrintUsage() PrintUsage()
...@@ -205,25 +209,16 @@ def main(argv): ...@@ -205,25 +209,16 @@ def main(argv):
if zip_arg: if zip_arg:
rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg) rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg)
if packed_relocation_adjustments == "unknown": version = stack_libs.GetTargetAndroidVersionNumber(lines)
version = stack_libs.GetTargetAndroidVersionNumber(lines) if version is None:
if version == None: print ("Unknown Android release, "
packed_relocation_adjustments = False "consider passing --packed-lib.")
print ("Unknown Android release, " elif version < _ANDROID_M_MAJOR_VERSION and not packed_libs:
+ "consider --[no-]packed-relocation-adjustments options") print ("Pre-M Android release detected, "
elif version >= _ANDROID_M_MAJOR_VERSION: "but --packed-lib not specified. Stack symbolization may fail.")
packed_relocation_adjustments = False
else:
packed_relocation_adjustments = True
print ("Pre-M Android release detected, "
+ "added --packed-relocation-adjustments option")
else:
packed_relocation_adjustments = False
if packed_relocation_adjustments: if (version is None or version < _ANDROID_M_MAJOR_VERSION) and packed_libs:
constants.CheckOutputDirectory() load_vaddrs = stack_libs.GetLoadVaddrs(stripped_libs=packed_libs)
stripped_libs_dir = constants.GetOutDirectory()
load_vaddrs = stack_libs.GetLoadVaddrs(stripped_libs_dir)
else: else:
load_vaddrs = {} load_vaddrs = {}
......
...@@ -9,12 +9,15 @@ ...@@ -9,12 +9,15 @@
import glob import glob
import os.path import os.path
import re
import subprocess import subprocess
_BASE_APK = 'base.apk' _BASE_APK = 'base.apk'
_LIBCHROME_SO = 'libchrome.so' _LIBCHROME_SO = 'libchrome.so'
_BUILD_FINGERPRINT_RE = re.compile('.*Build fingerprint: (.*)$')
def GetTargetAndroidVersionNumber(lines): def GetTargetAndroidVersionNumber(lines):
"""Return the Android major version number from the build fingerprint. """Return the Android major version number from the build fingerprint.
...@@ -26,13 +29,15 @@ def GetTargetAndroidVersionNumber(lines): ...@@ -26,13 +29,15 @@ def GetTargetAndroidVersionNumber(lines):
""" """
# For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5. # For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5.
for line in lines: for line in lines:
if line.startswith('Build fingerprint: '): m = _BUILD_FINGERPRINT_RE.match(line)
fingerprint = line.split()[2] if not m:
continue
fingerprint = m.group(1)
try:
version = fingerprint.split('/')[2].split(':')[1].split('.')[0] version = fingerprint.split('/')[2].split(':')[1].split('.')[0]
try: return int(version)
return int(version) except Exception:
except ValueError: pass
return None
return None return None
...@@ -90,7 +95,7 @@ def _FindMinLoadVaddr(lib): ...@@ -90,7 +95,7 @@ def _FindMinLoadVaddr(lib):
return 0 return 0
def GetLoadVaddrs(stripped_libs_dir): def GetLoadVaddrs(stripped_libs=None, stripped_libs_dir=None):
"""Return a dict of minimum VirtAddr for libraries in the given directory. """Return a dict of minimum VirtAddr for libraries in the given directory.
The dictionary returned may be passed to stack_core.ConvertTrace(). In The dictionary returned may be passed to stack_core.ConvertTrace(). In
...@@ -103,8 +108,11 @@ def GetLoadVaddrs(stripped_libs_dir): ...@@ -103,8 +108,11 @@ def GetLoadVaddrs(stripped_libs_dir):
Returns: Returns:
{'libchrome.so': 12345, ...} {'libchrome.so': 12345, ...}
""" """
libs = glob.glob(os.path.join(stripped_libs_dir, '*.so')) if not stripped_libs:
libs = [l for l in libs if _HasElfHeader(l)] stripped_libs = []
if stripped_libs_dir:
stripped_libs.extend(glob.glob(os.path.join(stripped_libs_dir, '*.so')))
libs = [l for l in stripped_libs if _HasElfHeader(l)]
load_vaddrs = {} load_vaddrs = {}
for lib in libs: for lib in libs:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment