Make 'stack' able to find toolchains regardless of lunch.

This is needed by the internal stack decoding website, which
will be pulling symbols from the build servers anyway (so doesn't
need to be correctly lunched).

Bug: 16734486
Change-Id: I9190065148c0d4bb4eacec28bcc062fa95798917
This commit is contained in:
Elliott Hughes
2014-08-29 13:49:57 -07:00
parent 4123e0886b
commit c3c8619579
2 changed files with 57 additions and 37 deletions

View File

@@ -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')

View File

@@ -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()