mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
109 lines
3.2 KiB
Python
Executable File
109 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
|
|
"""
|
|
This script uses a regex to validate the output of our backtraces.
|
|
The layout we assume is:
|
|
|
|
<frame number> <library name> <address> <demangled name> + <offset>
|
|
|
|
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<index>\d+) +(?P<object>\S+) +(?P<address>0x[0-9a-fA-F]{16}) '
|
|
r'(?P<routine>[^+]+) [+] (?P<offset>\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()
|