1"""Check that compiler-generated register values work correctly""" 2 3import re 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbutil 8 9 10def re_expr_equals(val_type, val): 11 # Match ({val_type}) ${sum_digits} = {val} 12 return re.compile(r"\(" + val_type + "\) \$\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 probable 25 # register variable location is actually a register, and 26 # if so, whether we can print out the variable there. 27 # It only requires one of them to be handled in a non-error 28 # way. 29 register_variables_count = 0 30 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 breakpoint 40 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=1 53 ) 54 55 # Try some variables that should be visible 56 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 += 1 64 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 += 1 72 self.expect( 73 "expr b->m1", 74 VARIABLES_DISPLAYED_CORRECTLY, 75 patterns=[re_expr_equals("int", 3)], 76 ) 77 78 ##################### 79 # Second breakpoint 80 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=1 93 ) 94 95 # Try some variables that should be visible 96 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 += 1 104 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 += 1 112 self.expect( 113 "expr c", 114 VARIABLES_DISPLAYED_CORRECTLY, 115 patterns=[re_expr_equals("int", 5)], 116 ) 117 118 ##################### 119 # Third breakpoint 120 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=1 133 ) 134 135 # Try some variables that should be visible 136 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 += 1 144 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 variable 151 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_count 159 ) 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 False 171 172 # Check that we can get its value. If not, this 173 # 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 False 179 else: 180 self.trace("value is {}".format(value)) 181 182 # We have a variable and we can get its value. The variable is in a 183 # register if we cannot get an address for it, assuming it is not a 184 # struct pointer. (This is an approximation - compilers can do other 185 # things with spitting up a value into multiple parts of multiple 186 # registers, but what we're verifying here is much more than it was 187 # 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_addr 195 ) 196 ) 197 return False 198 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_name 204 ) 205 ) 206 return True 207 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 False 217 218 # Check that we can get its value. If not, this 219 # 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 False 226 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 False 237 else: 238 self.trace("frame var {} is in a register".format(var_name)) 239 return True 240