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

This commit is contained in:
Elliott Hughes
2014-08-29 22:29:42 +00:00
committed by Gerrit Code Review
2 changed files with 57 additions and 37 deletions

View File

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