diff options
author | Krzysztof KosiĆski <krzysio@google.com> | 2021-03-11 18:05:01 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2021-04-09 13:21:32 -0700 |
commit | b136111f17bf943f5548d6efa456fecfc94bd2fa (patch) | |
tree | be2d18f246383481842a9054386f46bad54bd5ea | |
parent | ea57fde6012237f26d7e0b5c565d03ac0279ec1d (diff) | |
download | development-b136111f17bf943f5548d6efa456fecfc94bd2fa.tar.gz |
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
-rw-r--r-- | scripts/Android.bp | 19 | ||||
-rwxr-xr-x | scripts/example_crashes.py | 2 | ||||
-rwxr-xr-x | scripts/stack | 6 | ||||
-rwxr-xr-x | scripts/stack_core.py | 141 | ||||
-rwxr-xr-x | scripts/symbol.py | 20 |
5 files changed, 90 insertions, 98 deletions
diff --git a/scripts/Android.bp b/scripts/Android.bp index afbb6c7ee..aad32ca29 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -21,14 +21,6 @@ python_library_host { srcs: [ "symbol.py", ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: true, - }, - }, } python_test_host { @@ -53,6 +45,17 @@ python_test_host { } 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: [ "add3prf.py", diff --git a/scripts/example_crashes.py b/scripts/example_crashes.py index be72f8885..5d4751cfd 100755 --- a/scripts/example_crashes.py +++ b/scripts/example_crashes.py @@ -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"); diff --git a/scripts/stack b/scripts/stack index ef28980fc..aaa32f417 100755 --- a/scripts/stack +++ b/scripts/stack @@ -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() diff --git a/scripts/stack_core.py b/scripts/stack_core.py index ee63b532d..3f22e3874 100755 --- a/scripts/stack_core.py +++ b/scripts/stack_core.py @@ -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 - # 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? - # pylint: disable-msg=C6310 + 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). + 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 - # 0x prefix). - "\)") # Closin paren. - # pylint: disable-msg=C6310 + 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). + 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) diff --git a/scripts/symbol.py b/scripts/symbol.py index 6f0d4934b..23b87379e 100755 --- a/scripts/symbol.py +++ b/scripts/symbol.py @@ -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()>: |