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