mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 11:46:41 +00:00
240 lines
8.0 KiB
Python
240 lines
8.0 KiB
Python
"""Check that compiler-generated register values work correctly"""
|
|
|
|
import re
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
def re_expr_equals(val_type, val):
|
|
# Match ({val_type}) ${sum_digits} = {val}
|
|
return re.compile(r"\(" + val_type + r"\) \$\d+ = " + str(val))
|
|
|
|
|
|
class RegisterVariableTestCase(TestBase):
|
|
@expectedFailureAll(compiler="clang", compiler_version=["<", "3.5"])
|
|
@expectedFailureAll(
|
|
compiler="gcc", compiler_version=[">=", "4.8.2"], archs=["i386"]
|
|
)
|
|
@expectedFailureAll(compiler="gcc", compiler_version=["<", "4.9"], archs=["x86_64"])
|
|
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 = self.getBuildArtifact("a.out")
|
|
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
|
|
|
|
# Break inside the main.
|
|
lldbutil.run_break_set_by_source_regexp(self, "break", num_expected_locations=3)
|
|
|
|
####################
|
|
# First breakpoint
|
|
|
|
self.runCmd("run", RUN_SUCCEEDED)
|
|
|
|
# The stop reason of the thread should be breakpoint.
|
|
self.expect(
|
|
"thread list",
|
|
STOPPED_DUE_TO_BREAKPOINT,
|
|
substrs=["stopped", "stop reason = breakpoint"],
|
|
)
|
|
|
|
# The breakpoint should have a hit count of 1.
|
|
lldbutil.check_breakpoint(
|
|
self, bpno=1, location_id=1, expected_location_hit_count=1
|
|
)
|
|
|
|
# Try some variables that should be visible
|
|
frame = (
|
|
self.dbg.GetSelectedTarget()
|
|
.GetProcess()
|
|
.GetSelectedThread()
|
|
.GetSelectedFrame()
|
|
)
|
|
if self.is_variable_in_register(frame, "a"):
|
|
register_variables_count += 1
|
|
self.expect(
|
|
"expr a",
|
|
VARIABLES_DISPLAYED_CORRECTLY,
|
|
patterns=[re_expr_equals("int", 2)],
|
|
)
|
|
|
|
if self.is_struct_pointer_in_register(frame, "b", self.TraceOn()):
|
|
register_variables_count += 1
|
|
self.expect(
|
|
"expr b->m1",
|
|
VARIABLES_DISPLAYED_CORRECTLY,
|
|
patterns=[re_expr_equals("int", 3)],
|
|
)
|
|
|
|
#####################
|
|
# Second breakpoint
|
|
|
|
self.runCmd("continue")
|
|
|
|
# The stop reason of the thread should be breakpoint.
|
|
self.expect(
|
|
"thread list",
|
|
STOPPED_DUE_TO_BREAKPOINT,
|
|
substrs=["stopped", "stop reason = breakpoint"],
|
|
)
|
|
|
|
# The breakpoint should have a hit count of 1.
|
|
lldbutil.check_breakpoint(
|
|
self, bpno=1, location_id=2, expected_location_hit_count=1
|
|
)
|
|
|
|
# Try some variables that should be visible
|
|
frame = (
|
|
self.dbg.GetSelectedTarget()
|
|
.GetProcess()
|
|
.GetSelectedThread()
|
|
.GetSelectedFrame()
|
|
)
|
|
if self.is_struct_pointer_in_register(frame, "b", self.TraceOn()):
|
|
register_variables_count += 1
|
|
self.expect(
|
|
"expr b->m2",
|
|
VARIABLES_DISPLAYED_CORRECTLY,
|
|
patterns=[re_expr_equals("int", 5)],
|
|
)
|
|
|
|
if self.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
|
|
|
|
self.runCmd("continue")
|
|
|
|
# The stop reason of the thread should be breakpoint.
|
|
self.expect(
|
|
"thread list",
|
|
STOPPED_DUE_TO_BREAKPOINT,
|
|
substrs=["stopped", "stop reason = breakpoint"],
|
|
)
|
|
|
|
# The breakpoint should have a hit count of 1.
|
|
lldbutil.check_breakpoint(
|
|
self, bpno=1, location_id=3, expected_location_hit_count=1
|
|
)
|
|
|
|
# Try some variables that should be visible
|
|
frame = (
|
|
self.dbg.GetSelectedTarget()
|
|
.GetProcess()
|
|
.GetSelectedThread()
|
|
.GetSelectedFrame()
|
|
)
|
|
if self.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.assertGreater(
|
|
register_variables_count,
|
|
0,
|
|
"expected to verify at least one variable in a register",
|
|
)
|
|
self.trace(
|
|
"executed {} expressions with values in registers".format(
|
|
register_variables_count
|
|
)
|
|
)
|
|
|
|
self.runCmd("kill")
|
|
|
|
def is_variable_in_register(self, frame, var_name):
|
|
# Ensure we can lookup the variable.
|
|
var = frame.FindVariable(var_name)
|
|
self.trace("\nchecking {}...".format(var_name))
|
|
if var is None or not var.IsValid():
|
|
self.trace("{} 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()
|
|
self.trace("checking value...")
|
|
if value is None:
|
|
self.trace("value is invalid")
|
|
return False
|
|
else:
|
|
self.trace("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()
|
|
self.trace("checking address...")
|
|
if var_addr.IsValid():
|
|
# We have an address, it must not be in a register.
|
|
self.trace(
|
|
"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.
|
|
self.trace(
|
|
"var {} is in a register (we don't have an address for it)".format(
|
|
var_name
|
|
)
|
|
)
|
|
return True
|
|
|
|
def is_struct_pointer_in_register(self, frame, var_name, trace):
|
|
# Ensure we can lookup the variable.
|
|
var = frame.FindVariable(var_name)
|
|
if trace:
|
|
print("\nchecking {}...".format(var_name))
|
|
|
|
if var is None or not var.IsValid():
|
|
self.trace("{} 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()
|
|
self.trace("checking value...")
|
|
if value is None:
|
|
if trace:
|
|
print("value is invalid")
|
|
return False
|
|
else:
|
|
if trace:
|
|
print("value is {}".format(value))
|
|
|
|
var_loc = var.GetLocation()
|
|
if trace:
|
|
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.
|
|
self.trace("frame var {} is not in a register".format(var_name))
|
|
return False
|
|
else:
|
|
self.trace("frame var {} is in a register".format(var_name))
|
|
return True
|