blob: c64efa3a693193e174af87a9d275f98c5e7d522c [file] [log] [blame]
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Commands used to automate testing gdb pretty printers.
This script is part of a larger framework to test gdb pretty printers. It
runs the program, detects test cases, checks them, and prints results.
See on how to write a test case.
from __future__ import print_function
import re
import gdb
import sys
test_failures = 0
# Sometimes the inital run command can fail to trace the process.
# (e.g. you don't have ptrace permissions)
# In these cases gdb still sends us an exited event so we cannot
# see what "run" printed to check for a warning message, since
# we get taken to our exit handler before we can look.
# Instead check that at least one test has been run by the time
# we exit.
has_run_tests = False
class CheckResult(gdb.Command):
def __init__(self):
super(CheckResult, self).__init__(
"print_and_compare", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
global has_run_tests
has_run_tests = True
# Stack frame is:
# 0. StopForDebugger
# 1. ComparePrettyPrintToChars or ComparePrettyPrintToRegex
# 2. TestCase
compare_frame = gdb.newest_frame().older()
testcase_frame = compare_frame.older()
test_loc = testcase_frame.find_sal()
# Use interactive commands in the correct context to get the pretty
# printed version
value_str = self._get_value_string(compare_frame, testcase_frame)
# Ignore the convenience variable name and newline
value = value_str[value_str.find("= ") + 2:-1]
expectation_val = compare_frame.read_var("expectation")
check_literal = expectation_val.string(encoding="utf-8")
if "PrettyPrintToRegex" in
test_fails = not, value)
test_fails = value != check_literal
if test_fails:
global test_failures
print("FAIL: " + test_loc.symtab.filename +
":" + str(test_loc.line))
print("GDB printed:")
print(" " + repr(value))
print("Value should match:")
print(" " + repr(check_literal))
test_failures += 1
print("PASS: " + test_loc.symtab.filename +
":" + str(test_loc.line))
except RuntimeError as e:
# At this point, lots of different things could be wrong, so don't try to
# recover or figure it out. Don't exit either, because then it's
# impossible debug the framework itself.
print("FAIL: Something is wrong in the test framework.")
test_failures += 1
def _get_value_string(self, compare_frame, testcase_frame):
if "ComparePrettyPrint" in
s = gdb.execute("p value", to_string=True)
value_str = str(compare_frame.read_var("value"))
clean_expression_str = value_str.strip("'\"")
s = gdb.execute("p " + clean_expression_str, to_string=True)
if sys.version_info.major == 2:
return s.decode("utf-8")
return s
def exit_handler(event=None):
global test_failures
global has_run_tests
if not has_run_tests:
print("FAILED test program did not run correctly, check gdb warnings")
test_failures = -1
elif test_failures:
print("FAILED %d cases" % test_failures)
# Start code executed at load time
# Disable terminal paging
gdb.execute("set height 0")
gdb.execute("set python print-stack full")
test_failures = 0
test_bp = gdb.Breakpoint("StopForDebugger")
test_bp.enabled = True
test_bp.silent = True
test_bp.commands = "print_and_compare\ncontinue"
# "run" won't return if the program exits; ensure the script regains control.
# If the program didn't exit, something went wrong, but we don't
# know what. Fail on exit.
test_failures += 1