240 lines · python
1"""Check that compiler-generated register values work correctly"""2 3import re4import lldb5from lldbsuite.test.decorators import *6from lldbsuite.test.lldbtest import *7from lldbsuite.test import lldbutil8 9 10def re_expr_equals(val_type, val):11 # Match ({val_type}) ${sum_digits} = {val}12 return re.compile(r"\(" + val_type + r"\) \$\d+ = " + str(val))13 14 15class RegisterVariableTestCase(TestBase):16 @expectedFailureAll(compiler="clang", compiler_version=["<", "3.5"])17 @expectedFailureAll(18 compiler="gcc", compiler_version=[">=", "4.8.2"], archs=["i386"]19 )20 @expectedFailureAll(compiler="gcc", compiler_version=["<", "4.9"], archs=["x86_64"])21 def test_and_run_command(self):22 """Test expressions on register values."""23 24 # This test now ensures that each probable25 # register variable location is actually a register, and26 # if so, whether we can print out the variable there.27 # It only requires one of them to be handled in a non-error28 # way.29 register_variables_count = 030 31 self.build()32 exe = self.getBuildArtifact("a.out")33 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)34 35 # Break inside the main.36 lldbutil.run_break_set_by_source_regexp(self, "break", num_expected_locations=3)37 38 ####################39 # First breakpoint40 41 self.runCmd("run", RUN_SUCCEEDED)42 43 # The stop reason of the thread should be breakpoint.44 self.expect(45 "thread list",46 STOPPED_DUE_TO_BREAKPOINT,47 substrs=["stopped", "stop reason = breakpoint"],48 )49 50 # The breakpoint should have a hit count of 1.51 lldbutil.check_breakpoint(52 self, bpno=1, location_id=1, expected_location_hit_count=153 )54 55 # Try some variables that should be visible56 frame = (57 self.dbg.GetSelectedTarget()58 .GetProcess()59 .GetSelectedThread()60 .GetSelectedFrame()61 )62 if self.is_variable_in_register(frame, "a"):63 register_variables_count += 164 self.expect(65 "expr a",66 VARIABLES_DISPLAYED_CORRECTLY,67 patterns=[re_expr_equals("int", 2)],68 )69 70 if self.is_struct_pointer_in_register(frame, "b", self.TraceOn()):71 register_variables_count += 172 self.expect(73 "expr b->m1",74 VARIABLES_DISPLAYED_CORRECTLY,75 patterns=[re_expr_equals("int", 3)],76 )77 78 #####################79 # Second breakpoint80 81 self.runCmd("continue")82 83 # The stop reason of the thread should be breakpoint.84 self.expect(85 "thread list",86 STOPPED_DUE_TO_BREAKPOINT,87 substrs=["stopped", "stop reason = breakpoint"],88 )89 90 # The breakpoint should have a hit count of 1.91 lldbutil.check_breakpoint(92 self, bpno=1, location_id=2, expected_location_hit_count=193 )94 95 # Try some variables that should be visible96 frame = (97 self.dbg.GetSelectedTarget()98 .GetProcess()99 .GetSelectedThread()100 .GetSelectedFrame()101 )102 if self.is_struct_pointer_in_register(frame, "b", self.TraceOn()):103 register_variables_count += 1104 self.expect(105 "expr b->m2",106 VARIABLES_DISPLAYED_CORRECTLY,107 patterns=[re_expr_equals("int", 5)],108 )109 110 if self.is_variable_in_register(frame, "c"):111 register_variables_count += 1112 self.expect(113 "expr c",114 VARIABLES_DISPLAYED_CORRECTLY,115 patterns=[re_expr_equals("int", 5)],116 )117 118 #####################119 # Third breakpoint120 121 self.runCmd("continue")122 123 # The stop reason of the thread should be breakpoint.124 self.expect(125 "thread list",126 STOPPED_DUE_TO_BREAKPOINT,127 substrs=["stopped", "stop reason = breakpoint"],128 )129 130 # The breakpoint should have a hit count of 1.131 lldbutil.check_breakpoint(132 self, bpno=1, location_id=3, expected_location_hit_count=1133 )134 135 # Try some variables that should be visible136 frame = (137 self.dbg.GetSelectedTarget()138 .GetProcess()139 .GetSelectedThread()140 .GetSelectedFrame()141 )142 if self.is_variable_in_register(frame, "f"):143 register_variables_count += 1144 self.expect(145 "expr f",146 VARIABLES_DISPLAYED_CORRECTLY,147 patterns=[re_expr_equals("float", "3.1")],148 )149 150 # Validate that we verified at least one register variable151 self.assertGreater(152 register_variables_count,153 0,154 "expected to verify at least one variable in a register",155 )156 self.trace(157 "executed {} expressions with values in registers".format(158 register_variables_count159 )160 )161 162 self.runCmd("kill")163 164 def is_variable_in_register(self, frame, var_name):165 # Ensure we can lookup the variable.166 var = frame.FindVariable(var_name)167 self.trace("\nchecking {}...".format(var_name))168 if var is None or not var.IsValid():169 self.trace("{} cannot be found".format(var_name))170 return False171 172 # Check that we can get its value. If not, this173 # may be a variable that is just out of scope at this point.174 value = var.GetValue()175 self.trace("checking value...")176 if value is None:177 self.trace("value is invalid")178 return False179 else:180 self.trace("value is {}".format(value))181 182 # We have a variable and we can get its value. The variable is in a183 # register if we cannot get an address for it, assuming it is not a184 # struct pointer. (This is an approximation - compilers can do other185 # things with spitting up a value into multiple parts of multiple186 # registers, but what we're verifying here is much more than it was187 # doing before).188 var_addr = var.GetAddress()189 self.trace("checking address...")190 if var_addr.IsValid():191 # We have an address, it must not be in a register.192 self.trace(193 "var {} is not in a register: has a valid address {}".format(194 var_name, var_addr195 )196 )197 return False198 else:199 # We don't have an address but we can read the value.200 # It is likely stored in a register.201 self.trace(202 "var {} is in a register (we don't have an address for it)".format(203 var_name204 )205 )206 return True207 208 def is_struct_pointer_in_register(self, frame, var_name, trace):209 # Ensure we can lookup the variable.210 var = frame.FindVariable(var_name)211 if trace:212 print("\nchecking {}...".format(var_name))213 214 if var is None or not var.IsValid():215 self.trace("{} cannot be found".format(var_name))216 return False217 218 # Check that we can get its value. If not, this219 # may be a variable that is just out of scope at this point.220 value = var.GetValue()221 self.trace("checking value...")222 if value is None:223 if trace:224 print("value is invalid")225 return False226 else:227 if trace:228 print("value is {}".format(value))229 230 var_loc = var.GetLocation()231 if trace:232 print("checking location: {}".format(var_loc))233 if var_loc is None or var_loc.startswith("0x"):234 # The frame var is not in a register but rather a memory location.235 self.trace("frame var {} is not in a register".format(var_name))236 return False237 else:238 self.trace("frame var {} is in a register".format(var_name))239 return True240