forked from OSchip/llvm-project
make TestRegisterVariables slightly more resilient
This test sets the compiler optimization level to -O1 and makes some assumptions about how local frame vars will be stored (i.e. in registers). These assumptions are not always true. I did a first-pass set of improvements that: (1) no longer assumes that every one of the target locations has every variable in a register. Sometimes the compiler is even smarter and skips the register entirely. (2) simply expects one of the 5 or so variables it checks to be in a register. This test probably passes on a whole lot more systems than it used to now. This is certainly true on OS X. llvm-svn: 265498
This commit is contained in:
parent
bfc9131454
commit
58c4dd7a71
|
@ -2,6 +2,12 @@ LEVEL = ../../../make
|
|||
|
||||
C_SOURCES := test.c
|
||||
|
||||
CFLAGS ?= -g -O1
|
||||
CFLAGS := -g -O1
|
||||
|
||||
$(info OS: $(OS))
|
||||
HOST_OS = $(shell uname -s)
|
||||
ifeq "$(HOST_OS)" "Darwin"
|
||||
FRAMEWORK_INCLUDES = -isysroot $(shell xcrun -show-sdk-path)
|
||||
endif
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
|
|
@ -2,23 +2,107 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
|
||||
import os, time
|
||||
import re
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
# This method attempts to figure out if a given variable
|
||||
# is in a register.
|
||||
#
|
||||
# Return:
|
||||
# True if the value has a readable value and is in a register
|
||||
# False otherwise
|
||||
def is_variable_in_register(frame, var_name):
|
||||
# Ensure we can lookup the variable.
|
||||
var = frame.FindVariable(var_name)
|
||||
# print("\nchecking {}...".format(var_name))
|
||||
if var is None or not var.IsValid():
|
||||
# print("{} cannot be found".format(var_name))
|
||||
return False
|
||||
|
||||
# Check that we can get its value. If not, this
|
||||
# may be a variable that is just out of scope at this point.
|
||||
value = var.GetValue()
|
||||
# print("checking value...")
|
||||
if value is None:
|
||||
# print("value is invalid")
|
||||
return False
|
||||
# else:
|
||||
# print("value is {}".format(value))
|
||||
|
||||
# We have a variable and we can get its value. The variable is in
|
||||
# a register if we cannot get an address for it, assuming it is
|
||||
# not a struct pointer. (This is an approximation - compilers can
|
||||
# do other things with spitting up a value into multiple parts of
|
||||
# multiple registers, but what we're verifying here is much more
|
||||
# than it was doing before).
|
||||
var_addr = var.GetAddress()
|
||||
# print("checking address...")
|
||||
if var_addr.IsValid():
|
||||
# We have an address, it must not be in a register.
|
||||
# print("var {} is not in a register: has a valid address {}".format(var_name, var_addr))
|
||||
return False
|
||||
else:
|
||||
# We don't have an address but we can read the value.
|
||||
# It is likely stored in a register.
|
||||
# print("var {} is in a register (we don't have an address for it)".format(var_name))
|
||||
return True
|
||||
|
||||
|
||||
def is_struct_pointer_in_register(frame, var_name):
|
||||
# Ensure we can lookup the variable.
|
||||
var = frame.FindVariable(var_name)
|
||||
# print("\nchecking {}...".format(var_name))
|
||||
if var is None or not var.IsValid():
|
||||
# print("{} cannot be found".format(var_name))
|
||||
return False
|
||||
|
||||
# Check that we can get its value. If not, this
|
||||
# may be a variable that is just out of scope at this point.
|
||||
value = var.GetValue()
|
||||
# print("checking value...")
|
||||
if value is None:
|
||||
# print("value is invalid")
|
||||
return False
|
||||
# else:
|
||||
# print("value is {}".format(value))
|
||||
|
||||
var_loc = var.GetLocation()
|
||||
# print("checking location: {}".format(var_loc))
|
||||
if var_loc is None or var_loc.startswith("0x"):
|
||||
# The frame var is not in a register but rather a memory location.
|
||||
# print("frame var {} is not in a register".format(var_name))
|
||||
return False
|
||||
else:
|
||||
# print("frame var {} is in a register".format(var_name))
|
||||
return True
|
||||
|
||||
|
||||
def re_expr_equals(val_type, val):
|
||||
# Match ({val_type}) ${sum_digits} = {val}
|
||||
return re.compile(r'\(' + val_type + '\) \$\d+ = ' + str(val))
|
||||
|
||||
|
||||
class RegisterVariableTestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@expectedFailureAll(oslist=['macosx'], compiler='clang', compiler_version=['<', '7.0.0'], debug_info="dsym")
|
||||
@expectedFailureAll(compiler="clang")
|
||||
@expectedFailureAll(compiler="gcc", compiler_version=['>=', '4.8.2'])
|
||||
|
||||
@expectedFailureAll(compiler="clang", compiler_version=['<', '3.5'])
|
||||
@expectedFailureAll(compiler="gcc", compiler_version=['=', '4.8.2'])
|
||||
def test_and_run_command(self):
|
||||
"""Test expressions on register values."""
|
||||
|
||||
# This test now ensures that each probable
|
||||
# register variable location is actually a register, and
|
||||
# if so, whether we can print out the variable there.
|
||||
# It only requires one of them to be handled in a non-error
|
||||
# way.
|
||||
register_variables_count = 0
|
||||
|
||||
self.build()
|
||||
exe = os.path.join(os.getcwd(), "a.out")
|
||||
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
|
||||
|
@ -41,11 +125,16 @@ class RegisterVariableTestCase(TestBase):
|
|||
substrs = [' resolved, hit count = 1'])
|
||||
|
||||
# Try some variables that should be visible
|
||||
self.expect("expr a", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
substrs = ['(int) $0 = 2'])
|
||||
frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
|
||||
if is_variable_in_register(frame, 'a'):
|
||||
register_variables_count += 1
|
||||
self.expect("expr a", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
patterns = [re_expr_equals('int', 2)])
|
||||
|
||||
self.expect("expr b->m1", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
substrs = ['(int) $1 = 3'])
|
||||
if is_struct_pointer_in_register(frame, 'b'):
|
||||
register_variables_count += 1
|
||||
self.expect("expr b->m1", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
patterns = [re_expr_equals('int', 3)])
|
||||
|
||||
#####################
|
||||
# Second breakpoint
|
||||
|
@ -62,11 +151,16 @@ class RegisterVariableTestCase(TestBase):
|
|||
substrs = [' resolved, hit count = 1'])
|
||||
|
||||
# Try some variables that should be visible
|
||||
self.expect("expr b->m2", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
substrs = ['(int) $2 = 5'])
|
||||
frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
|
||||
if is_struct_pointer_in_register(frame, 'b'):
|
||||
register_variables_count += 1
|
||||
self.expect("expr b->m2", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
patterns = [re_expr_equals('int', 5)])
|
||||
|
||||
self.expect("expr c", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
substrs = ['(int) $3 = 5'])
|
||||
if is_variable_in_register(frame, 'c'):
|
||||
register_variables_count += 1
|
||||
self.expect("expr c", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
patterns = [re_expr_equals('int', 5)])
|
||||
|
||||
#####################
|
||||
# Third breakpoint
|
||||
|
@ -83,7 +177,14 @@ class RegisterVariableTestCase(TestBase):
|
|||
substrs = [' resolved, hit count = 1'])
|
||||
|
||||
# Try some variables that should be visible
|
||||
self.expect("expr f", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
substrs = ['(float) $4 = 3.1'])
|
||||
frame = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
|
||||
if is_variable_in_register(frame, 'f'):
|
||||
register_variables_count += 1
|
||||
self.expect("expr f", VARIABLES_DISPLAYED_CORRECTLY,
|
||||
patterns = [re_expr_equals('float', '3.1')])
|
||||
|
||||
# Validate that we verified at least one register variable
|
||||
self.assertTrue(register_variables_count > 0, "expected to verify at least one variable in a register")
|
||||
# print("executed {} expressions with values in registers".format(register_variables_count))
|
||||
|
||||
self.runCmd("kill")
|
||||
|
|
Loading…
Reference in New Issue