1"""
2Test the 'register' command.
3"""
4
5import os, sys, time
6import re
7import unittest2
8import lldb
9from lldbtest import *
10import lldbutil
11
12class RegisterCommandsTestCase(TestBase):
13
14    mydir = os.path.join("functionalities", "register")
15
16    def setUp(self):
17        TestBase.setUp(self)
18        self.has_teardown = False
19
20    def test_register_commands(self):
21        """Test commands related to registers, in particular vector registers."""
22        if not self.getArchitecture() in ['i386', 'x86_64']:
23            self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
24        self.buildDefault()
25        self.register_commands()
26
27    def test_fp_register_write(self):
28        """Test commands that write to registers, in particular floating-point registers."""
29        if not self.getArchitecture() in ['i386', 'x86_64']:
30            self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
31        self.buildDefault()
32        self.fp_register_write()
33
34    def test_register_expressions(self):
35        """Test expression evaluation with commands related to registers."""
36        if not self.getArchitecture() in ['i386', 'x86_64']:
37            self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
38        self.buildDefault()
39        self.register_expressions()
40
41    def test_convenience_registers(self):
42        """Test convenience registers."""
43        if not self.getArchitecture() in ['x86_64']:
44            self.skipTest("This test requires x86_64 as the architecture for the inferior")
45        self.buildDefault()
46        self.convenience_registers()
47
48    def test_convenience_registers_with_process_attach(self):
49        """Test convenience registers after a 'process attach'."""
50        if not self.getArchitecture() in ['x86_64']:
51            self.skipTest("This test requires x86_64 as the architecture for the inferior")
52        self.buildDefault()
53        self.convenience_registers_with_process_attach(test_16bit_regs=False)
54
55    @expectedFailureLinux("llvm.org/pr14600") # Linux doesn't support 16-bit convenience registers
56    @skipIfLinux # llvm.org/pr16301 LLDB occasionally exits with SIGABRT
57    def test_convenience_registers_16bit_with_process_attach(self):
58        """Test convenience registers after a 'process attach'."""
59        if not self.getArchitecture() in ['x86_64']:
60            self.skipTest("This test requires x86_64 as the architecture for the inferior")
61        self.buildDefault()
62        self.convenience_registers_with_process_attach(test_16bit_regs=True)
63
64    def common_setup(self):
65        exe = os.path.join(os.getcwd(), "a.out")
66
67        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
68
69        # Break in main().
70        lldbutil.run_break_set_by_symbol (self, "main", num_expected_locations=-1)
71
72        self.runCmd("run", RUN_SUCCEEDED)
73
74        # The stop reason of the thread should be breakpoint.
75        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
76            substrs = ['stopped', 'stop reason = breakpoint'])
77
78    def remove_log(self):
79        """ Remove the temporary log file generated by some tests."""
80        if os.path.exists(self.log_file):
81            os.remove(self.log_file)
82
83    # platform specific logging of the specified category
84    def log_enable(self, category):
85        self.platform = ""
86        if sys.platform.startswith("darwin"):
87            self.platform = "" # TODO: add support for "log enable darwin registers"
88        if sys.platform.startswith("linux"):
89            self.platform = "linux"
90
91        if self.platform != "":
92            self.log_file = os.path.join(os.getcwd(), 'TestRegisters.log')
93            self.runCmd("log enable " + self.platform + " " + str(category) + " registers -v -f " + self.log_file, RUN_SUCCEEDED)
94            if not self.has_teardown:
95                self.has_teardown = True
96                self.addTearDownHook(self.remove_log)
97
98    def register_commands(self):
99        """Test commands related to registers, in particular vector registers."""
100        self.common_setup()
101
102        # verify that logging does not assert
103        self.log_enable("registers")
104
105        self.expect("register read -a", MISSING_EXPECTED_REGISTERS,
106            substrs = ['registers were unavailable'], matching = False)
107        self.runCmd("register read xmm0")
108        self.runCmd("register read ymm15") # may be available
109
110        self.expect("register read -s 3",
111            substrs = ['invalid register set index: 3'], error = True)
112
113    def write_and_restore(self, frame, register, must_exist = True):
114        value = frame.FindValue(register, lldb.eValueTypeRegister)
115        if must_exist:
116            self.assertTrue(value.IsValid(), "finding a value for register " + register)
117        elif not value.IsValid():
118            return # If register doesn't exist, skip this test
119
120        error = lldb.SBError()
121        register_value = value.GetValueAsUnsigned(error, 0)
122        self.assertTrue(error.Success(), "reading a value for " + register)
123
124        self.runCmd("register write " + register + " 0xff0e")
125        self.expect("register read " + register,
126            substrs = [register + ' = 0x', 'ff0e'])
127
128        self.runCmd("register write " + register + " " + str(register_value))
129        self.expect("register read " + register,
130            substrs = [register + ' = 0x'])
131
132    def vector_write_and_read(self, frame, register, new_value, must_exist = True):
133        value = frame.FindValue(register, lldb.eValueTypeRegister)
134        if must_exist:
135            self.assertTrue(value.IsValid(), "finding a value for register " + register)
136        elif not value.IsValid():
137            return # If register doesn't exist, skip this test
138
139        self.runCmd("register write " + register + " \'" + new_value + "\'")
140        self.expect("register read " + register,
141            substrs = [register + ' = ', new_value])
142
143    def fp_register_write(self):
144        exe = os.path.join(os.getcwd(), "a.out")
145
146        # Create a target by the debugger.
147        target = self.dbg.CreateTarget(exe)
148        self.assertTrue(target, VALID_TARGET)
149
150        lldbutil.run_break_set_by_symbol (self, "main", num_expected_locations=-1)
151
152        # Launch the process, and do not stop at the entry point.
153        process = target.LaunchSimple(None, None, os.getcwd())
154
155        process = target.GetProcess()
156        self.assertTrue(process.GetState() == lldb.eStateStopped,
157                        PROCESS_STOPPED)
158
159        thread = process.GetThreadAtIndex(0)
160        self.assertTrue(thread.IsValid(), "current thread is valid")
161
162        currentFrame = thread.GetFrameAtIndex(0)
163        self.assertTrue(currentFrame.IsValid(), "current frame is valid")
164
165        self.write_and_restore(currentFrame, "fcw", False)
166        self.write_and_restore(currentFrame, "fsw", False)
167        self.write_and_restore(currentFrame, "ftw", False)
168        self.write_and_restore(currentFrame, "ip", False)
169        self.write_and_restore(currentFrame, "dp", False)
170        self.write_and_restore(currentFrame, "mxcsr", False)
171        self.write_and_restore(currentFrame, "mxcsrmask", False)
172
173        new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
174        self.vector_write_and_read(currentFrame, "stmm0", new_value)
175        new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a}"
176        self.vector_write_and_read(currentFrame, "stmm7", new_value)
177
178        new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}"
179        self.vector_write_and_read(currentFrame, "xmm0", new_value)
180        new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}"
181        self.vector_write_and_read(currentFrame, "xmm15", new_value, False)
182
183        has_avx = False
184        registerSets = currentFrame.GetRegisters() # Returns an SBValueList.
185        for registerSet in registerSets:
186            if 'advanced vector extensions' in registerSet.GetName().lower():
187                has_avx = True
188                break
189
190        if has_avx:
191            new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x0d 0x0e 0x0f}"
192            self.vector_write_and_read(currentFrame, "ymm0", new_value)
193            self.vector_write_and_read(currentFrame, "ymm15", new_value)
194            self.expect("expr $ymm0", substrs = ['vector_type'])
195        else:
196            self.runCmd("register read ymm0")
197
198    def register_expressions(self):
199        """Test expression evaluation with commands related to registers."""
200        self.common_setup()
201
202        self.expect("expr/x $eax",
203            substrs = ['unsigned int', ' = 0x'])
204
205        if self.getArchitecture() in ['x86_64']:
206            self.expect("expr -- ($rax & 0xffffffff) == $eax",
207                substrs = ['true'])
208
209        self.expect("expr $xmm0",
210            substrs = ['vector_type'])
211
212        self.expect("expr (unsigned int)$xmm0[0]",
213            substrs = ['unsigned int'])
214
215    def convenience_registers(self):
216        """Test convenience registers."""
217        self.common_setup()
218
219        # The command "register read -a" does output a derived register like eax...
220        self.expect("register read -a", matching=True,
221            substrs = ['eax'])
222
223        # ...however, the vanilla "register read" command should not output derived registers like eax.
224        self.expect("register read", matching=False,
225            substrs = ['eax'])
226
227        # Test reading of rax and eax.
228        self.expect("register read rax eax",
229            substrs = ['rax = 0x', 'eax = 0x'])
230
231        # Now write rax with a unique bit pattern and test that eax indeed represents the lower half of rax.
232        self.runCmd("register write rax 0x1234567887654321")
233        self.expect("register read rax 0x1234567887654321",
234            substrs = ['0x1234567887654321'])
235
236    def convenience_registers_with_process_attach(self, test_16bit_regs):
237        """Test convenience registers after a 'process attach'."""
238        exe = os.path.join(os.getcwd(), "a.out")
239
240        # Spawn a new process
241        pid = 0
242        if sys.platform.startswith('linux'):
243            pid = self.forkSubprocess(exe, ['wait_for_attach'])
244        else:
245            proc = self.spawnSubprocess(exe, ['wait_for_attach'])
246            pid = proc.pid
247        self.addTearDownHook(self.cleanupSubprocesses)
248
249        if self.TraceOn():
250            print "pid of spawned process: %d" % pid
251
252        self.runCmd("process attach -p %d" % pid)
253
254        # Check that "register read eax" works.
255        self.runCmd("register read eax")
256
257        if self.getArchitecture() in ['x86_64']:
258            self.expect("expr -- ($rax & 0xffffffff) == $eax",
259                substrs = ['true'])
260
261        if test_16bit_regs:
262            self.expect("expr -- $ax == (($ah << 8) | $al)",
263                substrs = ['true'])
264
265if __name__ == '__main__':
266    import atexit
267    lldb.SBDebugger.Initialize()
268    atexit.register(lambda: lldb.SBDebugger.Terminate())
269    unittest2.main()
270