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