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:
@@ -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')
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user