Upgrade the 'stack' script to python3.
Also hook up the test to Android.bp. Test: unit test Test: Ran with a tombstone file as parameter. Test: Ran pasting in stack to stdin. Change-Id: I25f40569cc49b7487553611bcc25d061179bfa8d
This commit is contained in:
committed by
Christopher Ferris
parent
ea57fde601
commit
b136111f17
@@ -21,14 +21,6 @@ python_library_host {
|
||||
srcs: [
|
||||
"symbol.py",
|
||||
],
|
||||
version: {
|
||||
py2: {
|
||||
enabled: true,
|
||||
},
|
||||
py3: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
python_test_host {
|
||||
@@ -52,6 +44,17 @@ python_test_host {
|
||||
test_suites: ["general-tests"],
|
||||
}
|
||||
|
||||
python_test_host {
|
||||
name: "python-stack_core_test",
|
||||
main: "stack_core.py",
|
||||
srcs: [
|
||||
"example_crashes.py",
|
||||
"stack_core.py",
|
||||
],
|
||||
libs: ["python-symbol"],
|
||||
test_suites: ["general-tests"],
|
||||
}
|
||||
|
||||
python_test_host {
|
||||
name: "add3prf_test",
|
||||
srcs: [
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2014 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2013 The Android Open Source Project
|
||||
#
|
||||
@@ -42,10 +42,10 @@ def main():
|
||||
if args.syms:
|
||||
symbol.SYMBOLS_DIR = args.syms
|
||||
if args.file == '-':
|
||||
print "Reading native crash info from stdin"
|
||||
print("Reading native crash info from stdin")
|
||||
f = sys.stdin
|
||||
else:
|
||||
print "Searching for native crashes in %s" % args.file
|
||||
print("Searching for native crashes in %s" % args.file)
|
||||
f = open(args.file, "r")
|
||||
|
||||
lines = f.readlines()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2013 The Android Open Source Project
|
||||
#
|
||||
@@ -27,15 +27,15 @@ import example_crashes
|
||||
|
||||
def ConvertTrace(lines):
|
||||
tracer = TraceConverter()
|
||||
print "Reading symbols from", symbol.SYMBOLS_DIR
|
||||
print("Reading symbols from", symbol.SYMBOLS_DIR)
|
||||
tracer.ConvertTrace(lines)
|
||||
|
||||
class TraceConverter:
|
||||
process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
|
||||
revision_line = re.compile("(Revision: \'(.*)\')")
|
||||
signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
|
||||
abort_message_line = re.compile("(Abort message: '.*')")
|
||||
thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
|
||||
process_info_line = re.compile(r"(pid: [0-9]+, tid: [0-9]+.*)")
|
||||
revision_line = re.compile(r"(Revision: '(.*)')")
|
||||
signal_line = re.compile(r"(signal [0-9]+ \(.*\).*)")
|
||||
abort_message_line = re.compile(r"(Abort message: '.*')")
|
||||
thread_line = re.compile(r"(.*)(--- ){15}---")
|
||||
dalvik_jni_thread_line = re.compile("(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")
|
||||
dalvik_native_thread_line = re.compile("(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")
|
||||
register_line = re.compile("$a")
|
||||
@@ -43,14 +43,14 @@ class TraceConverter:
|
||||
sanitizer_trace_line = re.compile("$a")
|
||||
value_line = re.compile("$a")
|
||||
code_line = re.compile("$a")
|
||||
zipinfo_central_directory_line = re.compile("Central\s+directory\s+entry")
|
||||
zipinfo_central_directory_line = re.compile(r"Central\s+directory\s+entry")
|
||||
zipinfo_central_info_match = re.compile(
|
||||
"^\s*(\S+)$\s*offset of local header from start of archive:\s*(\d+)"
|
||||
".*^\s*compressed size:\s+(\d+)", re.M | re.S)
|
||||
unreachable_line = re.compile("((\d+ bytes in \d+ unreachable allocations)|"+\
|
||||
"(\d+ bytes unreachable at [0-9a-f]+)|"+\
|
||||
"(referencing \d+ unreachable bytes in \d+ allocation(s)?)|"+\
|
||||
"(and \d+ similar unreachable bytes in \d+ allocation(s)?))")
|
||||
r"^\s*(\S+)$\s*offset of local header from start of archive:\s*(\d+)"
|
||||
r".*^\s*compressed size:\s+(\d+)", re.M | re.S)
|
||||
unreachable_line = re.compile(r"((\d+ bytes in \d+ unreachable allocations)|"
|
||||
r"(\d+ bytes unreachable at [0-9a-f]+)|"
|
||||
r"(referencing \d+ unreachable bytes in \d+ allocation(s)?)|"
|
||||
r"(and \d+ similar unreachable bytes in \d+ allocation(s)?))")
|
||||
trace_lines = []
|
||||
value_lines = []
|
||||
last_frame = -1
|
||||
@@ -89,35 +89,35 @@ class TraceConverter:
|
||||
# 03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
|
||||
# Please note the spacing differences.
|
||||
self.trace_line = re.compile(
|
||||
".*" # Random start stuff.
|
||||
"\#(?P<frame>[0-9]+)" # Frame number.
|
||||
"[ \t]+..[ \t]+" # (space)pc(space).
|
||||
"(?P<offset>[0-9a-f]" + self.width + ")[ \t]+" # Offset (hex number given without
|
||||
r".*" # Random start stuff.
|
||||
r"\#(?P<frame>[0-9]+)" # Frame number.
|
||||
r"[ \t]+..[ \t]+" # (space)pc(space).
|
||||
r"(?P<offset>[0-9a-f]" + self.width + ")[ \t]+" # Offset (hex number given without
|
||||
# 0x prefix).
|
||||
"(?P<dso>\[[^\]]+\]|[^\r\n \t]*)" # Library name.
|
||||
"( \(offset (?P<so_offset>0x[0-9a-fA-F]+)\))?" # Offset into the file to find the start of the shared so.
|
||||
"(?P<symbolpresent> \((?P<symbol>.*)\))?") # Is the symbol there?
|
||||
r"(?P<dso>\[[^\]]+\]|[^\r\n \t]*)" # Library name.
|
||||
r"( \(offset (?P<so_offset>0x[0-9a-fA-F]+)\))?" # Offset into the file to find the start of the shared so.
|
||||
r"(?P<symbolpresent> \((?P<symbol>.*)\))?") # Is the symbol there?
|
||||
# pylint: disable-msg=C6310
|
||||
# Sanitizer output. This is different from debuggerd output, and it is easier to handle this as
|
||||
# its own regex. Example:
|
||||
# 08-19 05:29:26.283 397 403 I : #0 0xb6a15237 (/system/lib/libclang_rt.asan-arm-android.so+0x4f237)
|
||||
self.sanitizer_trace_line = re.compile(
|
||||
".*" # Random start stuff.
|
||||
"\#(?P<frame>[0-9]+)" # Frame number.
|
||||
"[ \t]+0x[0-9a-f]+[ \t]+" # PC, not interesting to us.
|
||||
"\(" # Opening paren.
|
||||
"(?P<dso>[^+]+)" # Library name.
|
||||
"\+" # '+'
|
||||
"0x(?P<offset>[0-9a-f]+)" # Offset (hex number given with
|
||||
r".*" # Random start stuff.
|
||||
r"\#(?P<frame>[0-9]+)" # Frame number.
|
||||
r"[ \t]+0x[0-9a-f]+[ \t]+" # PC, not interesting to us.
|
||||
r"\(" # Opening paren.
|
||||
r"(?P<dso>[^+]+)" # Library name.
|
||||
r"\+" # '+'
|
||||
r"0x(?P<offset>[0-9a-f]+)" # Offset (hex number given with
|
||||
# 0x prefix).
|
||||
"\)") # Closin paren.
|
||||
r"\)") # Closing paren.
|
||||
# pylint: disable-msg=C6310
|
||||
# Examples of matched value lines include:
|
||||
# bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
|
||||
# bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so (symbol)
|
||||
# 03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
|
||||
# Again, note the spacing differences.
|
||||
self.value_line = re.compile("(.*)([0-9a-f]" + self.width + ")[ \t]+([0-9a-f]" + self.width + ")[ \t]+([^\r\n \t]*)( \((.*)\))?")
|
||||
self.value_line = re.compile(r"(.*)([0-9a-f]" + self.width + r")[ \t]+([0-9a-f]" + self.width + r")[ \t]+([^\r\n \t]*)( \((.*)\))?")
|
||||
# Lines from 'code around' sections of the output will be matched before
|
||||
# value lines because otheriwse the 'code around' sections will be confused as
|
||||
# value lines.
|
||||
@@ -125,39 +125,35 @@ class TraceConverter:
|
||||
# Examples include:
|
||||
# 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
|
||||
# 03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
|
||||
self.code_line = re.compile("(.*)[ \t]*[a-f0-9]" + self.width +
|
||||
"[ \t]*[a-f0-9]" + self.width +
|
||||
"[ \t]*[a-f0-9]" + self.width +
|
||||
"[ \t]*[a-f0-9]" + self.width +
|
||||
"[ \t]*[a-f0-9]" + self.width +
|
||||
"[ \t]*[ \r\n]") # pylint: disable-msg=C6310
|
||||
self.code_line = re.compile(r"(.*)[ \t]*[a-f0-9]" + self.width +
|
||||
r"[ \t]*[a-f0-9]" + self.width +
|
||||
r"[ \t]*[a-f0-9]" + self.width +
|
||||
r"[ \t]*[a-f0-9]" + self.width +
|
||||
r"[ \t]*[a-f0-9]" + self.width +
|
||||
r"[ \t]*[ \r\n]") # pylint: disable-msg=C6310
|
||||
|
||||
def CleanLine(self, ln):
|
||||
# AndroidFeedback adds zero width spaces into its crash reports. These
|
||||
# should be removed or the regular expresssions will fail to match.
|
||||
return unicode(ln, errors='ignore')
|
||||
return ln.encode().decode(encoding='utf8', errors='ignore')
|
||||
|
||||
def PrintTraceLines(self, trace_lines):
|
||||
"""Print back trace."""
|
||||
maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
|
||||
print
|
||||
print "Stack Trace:"
|
||||
print " RELADDR " + self.spacing + "FUNCTION".ljust(maxlen) + " FILE:LINE"
|
||||
maxlen = max(len(tl[1]) for tl in trace_lines)
|
||||
print("\nStack Trace:")
|
||||
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)
|
||||
return
|
||||
print(" %8s %s %s" % (addr, symbol_with_offset.ljust(maxlen), location))
|
||||
|
||||
def PrintValueLines(self, value_lines):
|
||||
"""Print stack data values."""
|
||||
maxlen = max(map(lambda tl: len(tl[2]), self.value_lines))
|
||||
print
|
||||
print "Stack Data:"
|
||||
print " ADDR " + self.spacing + "VALUE " + "FUNCTION".ljust(maxlen) + " FILE:LINE"
|
||||
maxlen = max(len(tl[2]) for tl in self.value_lines)
|
||||
print("\nStack Data:")
|
||||
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)
|
||||
return
|
||||
print(" %8s %8s %s %s" % (addr, value, symbol_with_offset.ljust(maxlen), location))
|
||||
|
||||
def PrintOutput(self, trace_lines, value_lines):
|
||||
if self.trace_lines:
|
||||
@@ -166,8 +162,7 @@ class TraceConverter:
|
||||
self.PrintValueLines(self.value_lines)
|
||||
|
||||
def PrintDivider(self):
|
||||
print
|
||||
print "-----------------------------------------------------\n"
|
||||
print("\n-----------------------------------------------------\n")
|
||||
|
||||
def DeleteApkTmpFiles(self):
|
||||
for _, _, tmp_files in self.apk_info.values():
|
||||
@@ -175,7 +170,7 @@ class TraceConverter:
|
||||
os.unlink(tmp_file)
|
||||
|
||||
def ConvertTrace(self, lines):
|
||||
lines = map(self.CleanLine, lines)
|
||||
lines = [self.CleanLine(line) for line in lines]
|
||||
try:
|
||||
if not symbol.ARCH:
|
||||
symbol.SetAbi(lines)
|
||||
@@ -252,18 +247,18 @@ class TraceConverter:
|
||||
return None, None
|
||||
|
||||
if not "ANDROID_PRODUCT_OUT" in os.environ:
|
||||
print "ANDROID_PRODUCT_OUT environment variable not set."
|
||||
print("ANDROID_PRODUCT_OUT environment variable not set.")
|
||||
return None, None
|
||||
out_dir = os.environ["ANDROID_PRODUCT_OUT"]
|
||||
if not os.path.exists(out_dir):
|
||||
print "ANDROID_PRODUCT_OUT " + out_dir + " does not exist."
|
||||
print("ANDROID_PRODUCT_OUT", out_dir, "does not exist.")
|
||||
return None, None
|
||||
if apk.startswith("/"):
|
||||
apk_full_path = out_dir + apk
|
||||
else:
|
||||
apk_full_path = os.path.join(out_dir, apk)
|
||||
if not os.path.exists(apk_full_path):
|
||||
print "Cannot find apk " + apk
|
||||
print("Cannot find apk", apk)
|
||||
return None, None
|
||||
|
||||
cmd = subprocess.Popen(["zipinfo", "-v", apk_full_path], stdout=subprocess.PIPE)
|
||||
@@ -322,23 +317,23 @@ class TraceConverter:
|
||||
self.value_lines = []
|
||||
self.last_frame = -1
|
||||
if process_header:
|
||||
print process_header.group(1)
|
||||
print(process_header.group(1))
|
||||
if signal_header:
|
||||
print signal_header.group(1)
|
||||
print(signal_header.group(1))
|
||||
if abort_message_header:
|
||||
print abort_message_header.group(1)
|
||||
print(abort_message_header.group(1))
|
||||
if register_header:
|
||||
print register_header.group(1)
|
||||
print(register_header.group(1))
|
||||
if thread_header:
|
||||
print thread_header.group(1)
|
||||
print(thread_header.group(1))
|
||||
if dalvik_jni_thread_header:
|
||||
print dalvik_jni_thread_header.group(1)
|
||||
print(dalvik_jni_thread_header.group(1))
|
||||
if dalvik_native_thread_header:
|
||||
print dalvik_native_thread_header.group(1)
|
||||
print(dalvik_native_thread_header.group(1))
|
||||
if revision_header:
|
||||
print revision_header.group(1)
|
||||
print(revision_header.group(1))
|
||||
if unreachable_header:
|
||||
print unreachable_header.group(1)
|
||||
print(unreachable_header.group(1))
|
||||
return True
|
||||
trace_line_dict = self.MatchTraceLine(line)
|
||||
if trace_line_dict is not None:
|
||||
@@ -470,7 +465,7 @@ class RegisterPatternTests(unittest.TestCase):
|
||||
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)
|
||||
self.assertEqual(matched, is_register, line)
|
||||
tc.PrintOutput(tc.trace_lines, tc.value_lines)
|
||||
|
||||
def test_arm_registers(self):
|
||||
@@ -497,7 +492,7 @@ class LibmemunreachablePatternTests(unittest.TestCase):
|
||||
lines = example_crashes.libmemunreachable.split('\n')
|
||||
|
||||
symbol.SetAbi(lines)
|
||||
self.assertEquals(symbol.ARCH, "arm")
|
||||
self.assertEqual(symbol.ARCH, "arm")
|
||||
|
||||
tc.UpdateAbiRegexes()
|
||||
header_lines = 0
|
||||
@@ -508,8 +503,8 @@ class LibmemunreachablePatternTests(unittest.TestCase):
|
||||
header_lines += 1
|
||||
if tc.MatchTraceLine(line) is not None:
|
||||
trace_lines += 1
|
||||
self.assertEquals(header_lines, 3)
|
||||
self.assertEquals(trace_lines, 2)
|
||||
self.assertEqual(header_lines, 3)
|
||||
self.assertEqual(trace_lines, 2)
|
||||
tc.PrintOutput(tc.trace_lines, tc.value_lines)
|
||||
|
||||
class LongASANStackTests(unittest.TestCase):
|
||||
@@ -542,4 +537,4 @@ class ValueLinesTest(unittest.TestCase):
|
||||
self.assertEqual([], tc.value_lines)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
unittest.main(verbosity=2)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2013 The Android Open Source Project
|
||||
#
|
||||
@@ -28,12 +28,7 @@ import signal
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
try:
|
||||
ANDROID_BUILD_TOP = str(os.environ["ANDROID_BUILD_TOP"])
|
||||
if not ANDROID_BUILD_TOP:
|
||||
ANDROID_BUILD_TOP = "."
|
||||
except:
|
||||
ANDROID_BUILD_TOP = "."
|
||||
ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP", ".")
|
||||
|
||||
def FindSymbolsDir():
|
||||
saveddir = os.getcwd()
|
||||
@@ -41,8 +36,8 @@ def FindSymbolsDir():
|
||||
stream = None
|
||||
try:
|
||||
cmd = "build/soong/soong_ui.bash --dumpvar-mode --abs TARGET_OUT_UNSTRIPPED"
|
||||
stream = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout
|
||||
return os.path.join(ANDROID_BUILD_TOP, str(stream.read().strip()))
|
||||
stream = subprocess.Popen(cmd, stdout=subprocess.PIPE, encoding='utf8', shell=True).stdout
|
||||
return str(stream.read().strip())
|
||||
finally:
|
||||
if stream is not None:
|
||||
stream.close()
|
||||
@@ -96,7 +91,7 @@ class ProcessCache:
|
||||
return pipe
|
||||
|
||||
def SpawnProcess(self, cmd):
|
||||
return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding='utf8')
|
||||
|
||||
def TerminateProcess(self, pipe):
|
||||
pipe.stdin.close()
|
||||
@@ -156,7 +151,7 @@ def FindToolchain():
|
||||
|
||||
_CACHED_TOOLCHAIN = llvm_binutils_dir
|
||||
_CACHED_TOOLCHAIN_ARCH = ARCH
|
||||
print("Using %s toolchain from: %s" % (_CACHED_TOOLCHAIN_ARCH, _CACHED_TOOLCHAIN))
|
||||
print("Using", _CACHED_TOOLCHAIN_ARCH, "toolchain from:", _CACHED_TOOLCHAIN)
|
||||
return _CACHED_TOOLCHAIN
|
||||
|
||||
|
||||
@@ -303,6 +298,7 @@ def CallLlvmSymbolizerForSet(lib, unique_addrs):
|
||||
# reading inlines from the output.
|
||||
# The blank line will cause llvm-symbolizer to emit a blank line.
|
||||
child.stdin.write("\n")
|
||||
child.stdin.flush()
|
||||
first = False
|
||||
except IOError as e:
|
||||
# Remove the / in front of the library name to match other output.
|
||||
@@ -394,7 +390,7 @@ def CallObjdumpForSet(lib, unique_addrs):
|
||||
current_symbol_addr = 0 # The address of the current function.
|
||||
addr_index = 0 # The address that we are currently looking for.
|
||||
|
||||
stream = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
|
||||
stream = subprocess.Popen(cmd, stdout=subprocess.PIPE, encoding='utf8').stdout
|
||||
for line in stream:
|
||||
# Is it a function line like:
|
||||
# 000177b0 <android::IBinder::~IBinder()>:
|
||||
|
||||
Reference in New Issue
Block a user