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 17 @expectedFailureAll(compiler="clang", compiler_version=['<', '3.5']) 18 @expectedFailureAll(compiler="gcc", compiler_version=[ 19 '>=', '4.8.2'], archs=["i386"]) 20 @expectedFailureAll(compiler="gcc", compiler_version=[ 21 '<', '4.9'], archs=["x86_64"]) 22 def test_and_run_command(self): 23 """Test expressions on register values.""" 24 25 # This test now ensures that each probable 26 # register variable location is actually a register, and 27 # if so, whether we can print out the variable there. 28 # It only requires one of them to be handled in a non-error 29 # way. 30 register_variables_count = 0 31 32 self.build() 33 exe = self.getBuildArtifact("a.out") 34 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 35 36 # Break inside the main. 37 lldbutil.run_break_set_by_source_regexp( 38 self, "break", num_expected_locations=3) 39 40 #################### 41 # First breakpoint 42 43 self.runCmd("run", RUN_SUCCEEDED) 44 45 # The stop reason of the thread should be breakpoint. 46 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 47 substrs=['stopped', 48 'stop reason = breakpoint']) 49 50 # The breakpoint should have a hit count of 1. 51 lldbutil.check_breakpoint(self, bpno = 1, location_id = 1, expected_location_hit_count = 1) 52 53 # Try some variables that should be visible 54 frame = self.dbg.GetSelectedTarget().GetProcess( 55 ).GetSelectedThread().GetSelectedFrame() 56 if self.is_variable_in_register(frame, 'a'): 57 register_variables_count += 1 58 self.expect("expr a", VARIABLES_DISPLAYED_CORRECTLY, 59 patterns=[re_expr_equals('int', 2)]) 60 61 if self.is_struct_pointer_in_register(frame, 'b', self.TraceOn()): 62 register_variables_count += 1 63 self.expect("expr b->m1", VARIABLES_DISPLAYED_CORRECTLY, 64 patterns=[re_expr_equals('int', 3)]) 65 66 ##################### 67 # Second breakpoint 68 69 self.runCmd("continue") 70 71 # The stop reason of the thread should be breakpoint. 72 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 73 substrs=['stopped', 74 'stop reason = breakpoint']) 75 76 # The breakpoint should have a hit count of 1. 77 lldbutil.check_breakpoint(self, bpno = 1, location_id = 2, expected_location_hit_count = 1) 78 79 # Try some variables that should be visible 80 frame = self.dbg.GetSelectedTarget().GetProcess( 81 ).GetSelectedThread().GetSelectedFrame() 82 if self.is_struct_pointer_in_register(frame, 'b', self.TraceOn()): 83 register_variables_count += 1 84 self.expect("expr b->m2", VARIABLES_DISPLAYED_CORRECTLY, 85 patterns=[re_expr_equals('int', 5)]) 86 87 if self.is_variable_in_register(frame, 'c'): 88 register_variables_count += 1 89 self.expect("expr c", VARIABLES_DISPLAYED_CORRECTLY, 90 patterns=[re_expr_equals('int', 5)]) 91 92 ##################### 93 # Third breakpoint 94 95 self.runCmd("continue") 96 97 # The stop reason of the thread should be breakpoint. 98 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 99 substrs=['stopped', 100 'stop reason = breakpoint']) 101 102 # The breakpoint should have a hit count of 1. 103 lldbutil.check_breakpoint(self, bpno = 1, location_id = 3, expected_location_hit_count = 1) 104 105 # Try some variables that should be visible 106 frame = self.dbg.GetSelectedTarget().GetProcess( 107 ).GetSelectedThread().GetSelectedFrame() 108 if self.is_variable_in_register(frame, 'f'): 109 register_variables_count += 1 110 self.expect("expr f", VARIABLES_DISPLAYED_CORRECTLY, 111 patterns=[re_expr_equals('float', '3.1')]) 112 113 # Validate that we verified at least one register variable 114 self.assertTrue( 115 register_variables_count > 0, 116 "expected to verify at least one variable in a register") 117 self.trace("executed {} expressions with values in registers".format(register_variables_count)) 118 119 self.runCmd("kill") 120 121 122 def is_variable_in_register(self, frame, var_name): 123 # Ensure we can lookup the variable. 124 var = frame.FindVariable(var_name) 125 self.trace("\nchecking {}...".format(var_name)) 126 if var is None or not var.IsValid(): 127 self.trace("{} cannot be found".format(var_name)) 128 return False 129 130 # Check that we can get its value. If not, this 131 # may be a variable that is just out of scope at this point. 132 value = var.GetValue() 133 self.trace("checking value...") 134 if value is None: 135 self.trace("value is invalid") 136 return False 137 else: 138 self.trace("value is {}".format(value)) 139 140 # We have a variable and we can get its value. The variable is in a 141 # register if we cannot get an address for it, assuming it is not a 142 # struct pointer. (This is an approximation - compilers can do other 143 # things with spitting up a value into multiple parts of multiple 144 # registers, but what we're verifying here is much more than it was 145 # doing before). 146 var_addr = var.GetAddress() 147 self.trace("checking address...") 148 if var_addr.IsValid(): 149 # We have an address, it must not be in a register. 150 self.trace("var {} is not in a register: has a valid address {}".format(var_name, var_addr)) 151 return False 152 else: 153 # We don't have an address but we can read the value. 154 # It is likely stored in a register. 155 self.trace("var {} is in a register (we don't have an address for it)".format(var_name)) 156 return True 157 158 159 def is_struct_pointer_in_register(self, frame, var_name, trace): 160 # Ensure we can lookup the variable. 161 var = frame.FindVariable(var_name) 162 if trace: 163 print("\nchecking {}...".format(var_name)) 164 165 if var is None or not var.IsValid(): 166 self.trace("{} cannot be found".format(var_name)) 167 return False 168 169 # Check that we can get its value. If not, this 170 # may be a variable that is just out of scope at this point. 171 value = var.GetValue() 172 self.trace("checking value...") 173 if value is None: 174 if trace: 175 print("value is invalid") 176 return False 177 else: 178 if trace: 179 print("value is {}".format(value)) 180 181 var_loc = var.GetLocation() 182 if trace: 183 print("checking location: {}".format(var_loc)) 184 if var_loc is None or var_loc.startswith("0x"): 185 # The frame var is not in a register but rather a memory location. 186 self.trace("frame var {} is not in a register".format(var_name)) 187 return False 188 else: 189 self.trace("frame var {} is in a register".format(var_name)) 190 return True 191 192