#!/usr/bin/env python3 """ This script uses a regex to validate the output of our backtraces. The layout we assume is:
+ It currently just checks that the backtrace results in at least one correctly formatted entry. It does not directly validate the input since the output would not be robust against standard library changes. TODO: We could have the user pass in the frame number, library name, and demangled name. These we can always validate as true in a robust way. On the other hand, address and offset are more difficult to validate in a robust way in the face of small codegen differences, so without any further thought I imagine we can just check the format. 11 libswiftCore.dylib 0x000000000dce84d0l _fatalErrorMessage(StaticString, StaticString, StaticString, UInt, flags : UInt32) -> () + 444 """ import argparse import re import sys # ----------------------------------------------------------------------------- # Constants DESCRIPTION = """ Checks that a stacktrace dump follows canonical formatting. """ TARGET_PATTERN = re.compile( r'(?P\d+) +(?P\S+) +(?P
0x[0-9a-fA-F]{16}) ' r'(?P[^+]+) [+] (?P\d+)') RESULTS_FORMAT = """Stack Trace Entry: \tIndex: '%(index)s' \tObject File: '%(object)s' \tAddress: '%(address)s' \tRoutine: '%(routine)s' \tOffset: '%(offset)s' """ # ----------------------------------------------------------------------------- def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=DESCRIPTION) parser.add_argument( '-u', '--check-unavailable', action='store_true', help='Checks if any symbols were unavailable') return parser.parse_args() def main(): args = parse_args() lines = sys.stdin.readlines() found_stack_trace_start = False found_stack_trace_entry = False for line in lines: line = line.rstrip('\n') # First see if we found the start of our stack trace start. If so, set # the found stack trace flag and continue. if line == 'Current stack trace:': assert not found_stack_trace_start found_stack_trace_start = True continue # Otherwise, if we have not yet found the stack trace start, continue. # We need to find the stack trace start line. if not found_stack_trace_start: continue # Ok, we are in the middle of matching a stack trace entry. matches = TARGET_PATTERN.match(line) # If we fail to match, we have exited the stack trace entry region if matches is None: break # At this point, we know that we have some sort of match. found_stack_trace_entry = True print(RESULTS_FORMAT.format(**matches.groupdict())) # Check for unavailable symbols, if that was requested. if args.check_unavailable: assert 'unavailable' not in matches.group('routine') # Once we have processed all of the lines, make sure that we found at least # one stack trace entry. assert found_stack_trace_entry if __name__ == '__main__': main()