Find abi before trying to decode the stack.
The CallStack function prints stacks to the log. Unfortunately, our
stack script defaults to arm, so if the data is actually arm64, we'll
do nothing. Modify the script to parse the input trying to determine
the abi before processing the rest of the lines. At the very least,
we'll be able to correctly choose between arm and arm64.
The only downside, is that, the old method could take dumps from different
abis, but no one I know does this.
Bug: 26569638
(cherry picked from commit bf8a940234)
Change-Id: I8dba5cc4910c4a81996999b8699915f1d55b4979
This commit is contained in:
@@ -29,7 +29,7 @@ def PrintUsage():
|
|||||||
print
|
print
|
||||||
print " usage: " + sys.argv[0] + " [options] [FILE]"
|
print " usage: " + sys.argv[0] + " [options] [FILE]"
|
||||||
print
|
print
|
||||||
print " --arch=arm|x86"
|
print " --arch=arm|arm64|mips|mips64|x86|x86_64"
|
||||||
print " the target architecture"
|
print " the target architecture"
|
||||||
print
|
print
|
||||||
print " FILE should contain a stack trace in it somewhere"
|
print " FILE should contain a stack trace in it somewhere"
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ def ConvertTrace(lines):
|
|||||||
|
|
||||||
class TraceConverter:
|
class TraceConverter:
|
||||||
process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
|
process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
|
||||||
abi_line = re.compile("(ABI: \'(.*)\')")
|
|
||||||
revision_line = re.compile("(Revision: \'(.*)\')")
|
revision_line = re.compile("(Revision: \'(.*)\')")
|
||||||
signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
|
signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
|
||||||
abort_message_line = re.compile("(Abort message: '.*')")
|
abort_message_line = re.compile("(Abort message: '.*')")
|
||||||
@@ -52,9 +51,6 @@ class TraceConverter:
|
|||||||
spacing = ""
|
spacing = ""
|
||||||
apk_info = dict()
|
apk_info = dict()
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.UpdateAbiRegexes()
|
|
||||||
|
|
||||||
register_names = {
|
register_names = {
|
||||||
"arm": "r0|r1|r2|r3|r4|r5|r6|r7|r8|r9|sl|fp|ip|sp|lr|pc|cpsr",
|
"arm": "r0|r1|r2|r3|r4|r5|r6|r7|r8|r9|sl|fp|ip|sp|lr|pc|cpsr",
|
||||||
"arm64": "x0|x1|x2|x3|x4|x5|x6|x7|x8|x9|x10|x11|x12|x13|x14|x15|x16|x17|x18|x19|x20|x21|x22|x23|x24|x25|x26|x27|x28|x29|x30|sp|pc|pstate",
|
"arm64": "x0|x1|x2|x3|x4|x5|x6|x7|x8|x9|x10|x11|x12|x13|x14|x15|x16|x17|x18|x19|x20|x21|x22|x23|x24|x25|x26|x27|x28|x29|x30|sp|pc|pstate",
|
||||||
@@ -175,6 +171,9 @@ class TraceConverter:
|
|||||||
def ConvertTrace(self, lines):
|
def ConvertTrace(self, lines):
|
||||||
lines = map(self.CleanLine, lines)
|
lines = map(self.CleanLine, lines)
|
||||||
try:
|
try:
|
||||||
|
if not symbol.ARCH:
|
||||||
|
symbol.SetAbi(lines)
|
||||||
|
self.UpdateAbiRegexes()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
self.ProcessLine(line)
|
self.ProcessLine(line)
|
||||||
self.PrintOutput(self.trace_lines, self.value_lines)
|
self.PrintOutput(self.trace_lines, self.value_lines)
|
||||||
@@ -281,13 +280,11 @@ class TraceConverter:
|
|||||||
abort_message_header = self.abort_message_line.search(line)
|
abort_message_header = self.abort_message_line.search(line)
|
||||||
thread_header = self.thread_line.search(line)
|
thread_header = self.thread_line.search(line)
|
||||||
register_header = self.register_line.search(line)
|
register_header = self.register_line.search(line)
|
||||||
abi_header = self.abi_line.search(line)
|
|
||||||
revision_header = self.revision_line.search(line)
|
revision_header = self.revision_line.search(line)
|
||||||
dalvik_jni_thread_header = self.dalvik_jni_thread_line.search(line)
|
dalvik_jni_thread_header = self.dalvik_jni_thread_line.search(line)
|
||||||
dalvik_native_thread_header = self.dalvik_native_thread_line.search(line)
|
dalvik_native_thread_header = self.dalvik_native_thread_line.search(line)
|
||||||
if process_header or signal_header or abort_message_header or thread_header or abi_header or \
|
if process_header or signal_header or abort_message_header or thread_header or \
|
||||||
register_header or dalvik_jni_thread_header or dalvik_native_thread_header or revision_header:
|
register_header or dalvik_jni_thread_header or dalvik_native_thread_header or revision_header:
|
||||||
ret = True
|
|
||||||
if self.trace_lines or self.value_lines:
|
if self.trace_lines or self.value_lines:
|
||||||
self.PrintOutput(self.trace_lines, self.value_lines)
|
self.PrintOutput(self.trace_lines, self.value_lines)
|
||||||
self.PrintDivider()
|
self.PrintDivider()
|
||||||
@@ -310,11 +307,7 @@ class TraceConverter:
|
|||||||
print dalvik_native_thread_header.group(1)
|
print dalvik_native_thread_header.group(1)
|
||||||
if revision_header:
|
if revision_header:
|
||||||
print revision_header.group(1)
|
print revision_header.group(1)
|
||||||
if abi_header:
|
return True
|
||||||
print abi_header.group(1)
|
|
||||||
symbol.ARCH = abi_header.group(2)
|
|
||||||
self.UpdateAbiRegexes()
|
|
||||||
return ret
|
|
||||||
trace_line_dict = self.MatchTraceLine(line)
|
trace_line_dict = self.MatchTraceLine(line)
|
||||||
if trace_line_dict is not None:
|
if trace_line_dict is not None:
|
||||||
ret = True
|
ret = True
|
||||||
@@ -404,7 +397,10 @@ 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()
|
||||||
for line in example_crash.split('\n'):
|
lines = example_crash.split('\n')
|
||||||
|
symbol.SetAbi(lines)
|
||||||
|
tc.UpdateAbiRegexes()
|
||||||
|
for line in lines:
|
||||||
tc.ProcessLine(line)
|
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)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ def FindSymbolsDir():
|
|||||||
|
|
||||||
SYMBOLS_DIR = FindSymbolsDir()
|
SYMBOLS_DIR = FindSymbolsDir()
|
||||||
|
|
||||||
ARCH = "arm"
|
ARCH = None
|
||||||
|
|
||||||
|
|
||||||
# These are private. Do not access them from other modules.
|
# These are private. Do not access them from other modules.
|
||||||
@@ -336,6 +336,61 @@ def FormatSymbolWithOffset(symbol, offset):
|
|||||||
return "%s+%d" % (symbol, offset)
|
return "%s+%d" % (symbol, offset)
|
||||||
|
|
||||||
|
|
||||||
|
def GetAbiFromToolchain(toolchain_var, bits):
|
||||||
|
toolchain = os.environ.get(toolchain_var)
|
||||||
|
if not toolchain:
|
||||||
|
return None
|
||||||
|
|
||||||
|
toolchain_match = re.search("\/(aarch64|arm|mips|x86)\/", toolchain)
|
||||||
|
if toolchain_match:
|
||||||
|
abi = toolchain_match.group(1)
|
||||||
|
if abi == "aarch64":
|
||||||
|
return "arm64"
|
||||||
|
elif bits == 64:
|
||||||
|
if abi == "x86":
|
||||||
|
return "x86_64"
|
||||||
|
elif abi == "mips":
|
||||||
|
return "mips64"
|
||||||
|
return abi
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def SetAbi(lines):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
abi_line = re.compile("ABI: \'(.*)\'")
|
||||||
|
trace_line = re.compile("\#[0-9]+[ \t]+..[ \t]+([0-9a-f]{8}|[0-9a-f]{16})([ \t]+|$)")
|
||||||
|
|
||||||
|
ARCH = None
|
||||||
|
for line in lines:
|
||||||
|
abi_match = abi_line.search(line)
|
||||||
|
if abi_match:
|
||||||
|
ARCH = abi_match.group(1)
|
||||||
|
break
|
||||||
|
trace_match = trace_line.search(line)
|
||||||
|
if trace_match:
|
||||||
|
# Try to guess the arch, we know the bitness.
|
||||||
|
if len(trace_match.group(1)) == 16:
|
||||||
|
# 64 bit
|
||||||
|
# Check for ANDROID_TOOLCHAIN, if it is set, we can figure out the
|
||||||
|
# arch this way. If this is not set, then default to arm64.
|
||||||
|
ARCH = GetAbiFromToolchain("ANDROID_TOOLCHAIN", 64)
|
||||||
|
if not ARCH:
|
||||||
|
ARCH = "arm64"
|
||||||
|
else:
|
||||||
|
# 32 bit
|
||||||
|
# Check for ANDROID_TOOLCHAIN_2ND_ARCH first, if set, use that.
|
||||||
|
# If not try ANDROID_TOOLCHAIN to find the arch.
|
||||||
|
# If this is not set, then default to arm.
|
||||||
|
ARCH = GetAbiFromToolchain("ANDROID_TOOLCHAIN_2ND_ARCH", 32)
|
||||||
|
if not ARCH:
|
||||||
|
ARCH = GetAbiFromToolchain("ANDROID_TOOLCHAIN", 32)
|
||||||
|
if not ARCH:
|
||||||
|
ARCH = "arm"
|
||||||
|
break
|
||||||
|
if not ARCH:
|
||||||
|
raise Exception("Could not determine arch from input")
|
||||||
|
|
||||||
|
|
||||||
class FindToolchainTests(unittest.TestCase):
|
class FindToolchainTests(unittest.TestCase):
|
||||||
def assert_toolchain_found(self, abi):
|
def assert_toolchain_found(self, abi):
|
||||||
@@ -350,6 +405,95 @@ class FindToolchainTests(unittest.TestCase):
|
|||||||
self.assert_toolchain_found("x86")
|
self.assert_toolchain_found("x86")
|
||||||
self.assert_toolchain_found("x86_64")
|
self.assert_toolchain_found("x86_64")
|
||||||
|
|
||||||
|
class SetArchTests(unittest.TestCase):
|
||||||
|
def test_abi_check(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
SetAbi(["ABI: 'arm'"])
|
||||||
|
self.assertEqual(ARCH, "arm")
|
||||||
|
SetAbi(["ABI: 'arm64'"])
|
||||||
|
self.assertEqual(ARCH, "arm64")
|
||||||
|
|
||||||
|
SetAbi(["ABI: 'mips'"])
|
||||||
|
self.assertEqual(ARCH, "mips")
|
||||||
|
SetAbi(["ABI: 'mips64'"])
|
||||||
|
self.assertEqual(ARCH, "mips64")
|
||||||
|
|
||||||
|
SetAbi(["ABI: 'x86'"])
|
||||||
|
self.assertEqual(ARCH, "x86")
|
||||||
|
SetAbi(["ABI: 'x86_64'"])
|
||||||
|
self.assertEqual(ARCH, "x86_64")
|
||||||
|
|
||||||
|
def test_32bit_trace_line_toolchain(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/arm/arm-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "arm")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/mips/arm-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "mips")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/x86/arm-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "x86")
|
||||||
|
|
||||||
|
def test_32bit_trace_line_toolchain_2nd(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN_2ND_ARCH"] = "linux-x86/arm/arm-linux-androideabi-4.9/bin"
|
||||||
|
os.environ["ANDROID_TOOLCHAIN_ARCH"] = "linux-x86/aarch64/aarch64-linux-android-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "arm")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN_2ND_ARCH"] = "linux-x86/mips/mips-linux-androideabi-4.9/bin"
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/unknown/unknown-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "mips")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN_2ND_ARCH"] = "linux-x86/x86/x86-linux-androideabi-4.9/bin"
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/unknown/unknown-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "x86")
|
||||||
|
|
||||||
|
def test_64bit_trace_line_toolchain(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/aarch/aarch-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 00000000000374e0"])
|
||||||
|
self.assertEqual(ARCH, "arm64")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/mips/arm-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 00000000000374e0"])
|
||||||
|
self.assertEqual(ARCH, "mips64")
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ["ANDROID_TOOLCHAIN"] = "linux-x86/x86/arm-linux-androideabi-4.9/bin"
|
||||||
|
SetAbi(["#00 pc 00000000000374e0"])
|
||||||
|
self.assertEqual(ARCH, "x86_64")
|
||||||
|
|
||||||
|
def test_default_abis(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
os.environ.clear()
|
||||||
|
SetAbi(["#00 pc 000374e0"])
|
||||||
|
self.assertEqual(ARCH, "arm")
|
||||||
|
SetAbi(["#00 pc 00000000000374e0"])
|
||||||
|
self.assertEqual(ARCH, "arm64")
|
||||||
|
|
||||||
|
def test_no_abi(self):
|
||||||
|
global ARCH
|
||||||
|
|
||||||
|
self.assertRaisesRegexp(Exception, "Could not determine arch from input", SetAbi, [])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user