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