diff --git a/scripts/stack_core.py b/scripts/stack_core.py index 1eb0c29d5..9b7ff2300 100755 --- a/scripts/stack_core.py +++ b/scripts/stack_core.py @@ -44,6 +44,7 @@ class TraceConverter: value_lines = [] last_frame = -1 width = "{8}" + spacing = "" def __init__(self): self.UpdateAbiRegexes() @@ -59,8 +60,10 @@ class TraceConverter: def UpdateAbiRegexes(self): if symbol.ARCH == "arm64" or symbol.ARCH == "mips64" or symbol.ARCH == "x86_64": self.width = "{16}" + self.spacing = " " else: self.width = "{8}" + self.spacing = "" self.register_line = re.compile("(([ ]*\\b(" + self.register_names[symbol.ARCH] + ")\\b +[0-9a-f]" + self.width + "){2,5})") @@ -104,12 +107,9 @@ class TraceConverter: def PrintTraceLines(self, trace_lines): """Print back trace.""" maxlen = max(map(lambda tl: len(tl[1]), trace_lines)) - spacing = "" - if symbol.ARCH == "arm64" or symbol.ARCH == "mips64" or symbol.ARCH == "x86_64": - spacing = " " print print "Stack Trace:" - print " RELADDR " + spacing + "FUNCTION".ljust(maxlen) + " FILE:LINE" + print " RELADDR " + self.spacing + "FUNCTION".ljust(maxlen) + " FILE:LINE" for tl in self.trace_lines: (addr, symbol_with_offset, location) = tl print " %8s %s %s" % (addr, symbol_with_offset.ljust(maxlen), location) @@ -120,7 +120,7 @@ class TraceConverter: maxlen = max(map(lambda tl: len(tl[2]), self.value_lines)) print print "Stack Data:" - print " ADDR VALUE " + "FUNCTION".ljust(maxlen) + " FILE:LINE" + print " ADDR " + self.spacing + "VALUE " + "FUNCTION".ljust(maxlen) + " FILE:LINE" for vl in self.value_lines: (addr, value, symbol_with_offset, location) = vl print " %8s %8s %s %s" % (addr, value, symbol_with_offset.ljust(maxlen), location) @@ -256,12 +256,12 @@ class TraceConverter: class RegisterPatternTests(unittest.TestCase): def assert_register_matches(self, abi, example_crash, stupid_pattern): tc = TraceConverter() - symbol.ARCH = abi - tc.UpdateAbiRegexes() for line in example_crash.split('\n'): + tc.ProcessLine(line) is_register = (re.search(stupid_pattern, line) is not None) matched = (tc.register_line.search(line) is not None) self.assertEquals(matched, is_register, line) + tc.PrintOutput(tc.trace_lines, tc.value_lines) def test_arm_registers(self): self.assert_register_matches("arm", example_crashes.arm, '\\b(r0|r4|r8|ip)\\b') diff --git a/scripts/symbol.py b/scripts/symbol.py index 5669b9db2..a211c7ce0 100755 --- a/scripts/symbol.py +++ b/scripts/symbol.py @@ -23,6 +23,7 @@ import glob import os import re import subprocess +import unittest ANDROID_BUILD_TOP = os.environ["ANDROID_BUILD_TOP"] if not ANDROID_BUILD_TOP: @@ -44,7 +45,11 @@ SYMBOLS_DIR = FindSymbolsDir() ARCH = "arm" -TOOLCHAIN = None + +# These are private. Do not access them from other modules. +_CACHED_TOOLCHAIN = None +_CACHED_TOOLCHAIN_ARCH = None + def ToolPath(tool, toolchain=None): """Return a fully-qualified path to the specified tool""" @@ -52,42 +57,38 @@ def ToolPath(tool, toolchain=None): toolchain = FindToolchain() return glob.glob(os.path.join(toolchain, "*-" + tool))[0] + def FindToolchain(): - """Returns the toolchain matching ARCH. Assumes that you're lunched - such that the necessary toolchain is either your primary or secondary. - TODO: we could make this 'just work' for most users by just globbing the - newest toolchains for every architecture out of prebuilts/, but other - parts of this tool assume you're lunched correctly anyway.""" - global TOOLCHAIN - if TOOLCHAIN is not None: - return TOOLCHAIN + """Returns the toolchain matching ARCH.""" + global _CACHED_TOOLCHAIN, _CACHED_TOOLCHAIN_ARCH + if _CACHED_TOOLCHAIN is not None and _CACHED_TOOLCHAIN_ARCH == ARCH: + return _CACHED_TOOLCHAIN # We use slightly different names from GCC, and there's only one toolchain - # for x86/x86_64. - gcc_arch = ARCH - if gcc_arch == "arm64": - gcc_arch = "aarch64" - elif gcc_arch == "mips": - gcc_arch = "mipsel" - elif gcc_arch == "x86": - gcc_arch = "x86_64" + # for x86/x86_64. Note that these are the names of the top-level directory + # rather than the _different_ names used lower down the directory hierarchy! + gcc_dir = ARCH + if gcc_dir == "arm64": + gcc_dir = "aarch64" + elif gcc_dir == "mips64": + gcc_dir = "mips" + elif gcc_dir == "x86_64": + gcc_dir = "x86" - tc1 = os.environ["ANDROID_TOOLCHAIN"] - tc2 = os.environ["ANDROID_TOOLCHAIN_2ND_ARCH"] + available_toolchains = glob.glob("%s/prebuilts/gcc/linux-x86/%s/*-linux-*/bin/" % (ANDROID_BUILD_TOP, gcc_dir)) + if len(available_toolchains) == 0: + raise Exception("Could not find tool chain for %s" % (ARCH)) - if ("/" + gcc_arch + "-linux-") in tc1: - toolchain = tc1 - elif ("/" + gcc_arch + "-linux-") in tc2: - toolchain = tc2 - else: - raise Exception("Could not find tool chain for %s" % (gcc_arch)) + toolchain = sorted(available_toolchains)[-1] if not os.path.exists(ToolPath("addr2line", toolchain)): raise Exception("No addr2line for %s" % (toolchain)) - TOOLCHAIN = toolchain - print "Using toolchain from: %s" % TOOLCHAIN - return TOOLCHAIN + _CACHED_TOOLCHAIN = toolchain + _CACHED_TOOLCHAIN_ARCH = ARCH + print "Using %s toolchain from: %s" % (_CACHED_TOOLCHAIN_ARCH, _CACHED_TOOLCHAIN) + return _CACHED_TOOLCHAIN + def SymbolInformation(lib, addr): """Look up symbol information about an address. @@ -179,7 +180,6 @@ def CallAddr2LineForSet(lib, unique_addrs): if not lib: return None - symbols = SYMBOLS_DIR + lib if not os.path.exists(symbols): return None @@ -227,11 +227,11 @@ def StripPC(addr): The stripped program counter address. """ global ARCH - if ARCH == "arm": return addr & ~1 return addr + def CallObjdumpForSet(lib, unique_addrs): """Use objdump to find out the names of the containing functions. @@ -326,7 +326,27 @@ def CallCppFilt(mangled_symbol): process.stdout.close() return demangled_symbol + def FormatSymbolWithOffset(symbol, offset): if offset == 0: return symbol return "%s+%d" % (symbol, offset) + + + +class FindToolchainTests(unittest.TestCase): + def assert_toolchain_found(self, abi): + global ARCH + ARCH = abi + FindToolchain() # Will throw on failure. + + def test_toolchains_found(self): + self.assert_toolchain_found("arm") + self.assert_toolchain_found("arm64") + self.assert_toolchain_found("mips") + self.assert_toolchain_found("x86") + self.assert_toolchain_found("x86_64") + + +if __name__ == '__main__': + unittest.main()