1"""
2Test the 'register' command.
3"""
4
5from __future__ import print_function
6
7
8import os
9import sys
10import lldb
11from lldbsuite.test.decorators import *
12from lldbsuite.test.lldbtest import *
13from lldbsuite.test import lldbutil
14
15
16class RegisterCommandsTestCase(TestBase):
17
18    mydir = TestBase.compute_mydir(__file__)
19    NO_DEBUG_INFO_TESTCASE = True
20
21    def setUp(self):
22        TestBase.setUp(self)
23        self.has_teardown = False
24
25    def tearDown(self):
26        self.dbg.GetSelectedTarget().GetProcess().Destroy()
27        TestBase.tearDown(self)
28
29    @skipIfiOSSimulator
30    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
31    @expectedFailureNetBSD
32    def test_register_commands(self):
33        """Test commands related to registers, in particular vector registers."""
34        self.build()
35        self.common_setup()
36
37        # verify that logging does not assert
38        self.log_enable("registers")
39
40        self.expect("register read -a", MISSING_EXPECTED_REGISTERS,
41                    substrs=['registers were unavailable'], matching=False)
42
43        if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
44            self.runCmd("register read xmm0")
45            self.runCmd("register read ymm15")  # may be available
46            self.runCmd("register read bnd0")  # may be available
47        elif self.getArchitecture() in ['arm', 'armv7', 'armv7k', 'arm64', 'arm64e', 'arm64_32']:
48            self.runCmd("register read s0")
49            self.runCmd("register read q15")  # may be available
50
51        self.expect(
52            "register read -s 4",
53            substrs=['invalid register set index: 4'],
54            error=True)
55
56    @skipIfiOSSimulator
57    # Writing of mxcsr register fails, presumably due to a kernel/hardware
58    # problem
59    @skipIfTargetAndroid(archs=["i386"])
60    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
61    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37995")
62    def test_fp_register_write(self):
63        """Test commands that write to registers, in particular floating-point registers."""
64        self.build()
65        self.fp_register_write()
66
67    @skipIfiOSSimulator
68    # "register read fstat" always return 0xffff
69    @expectedFailureAndroid(archs=["i386"])
70    @skipIfFreeBSD  # llvm.org/pr25057
71    @skipIf(archs=no_match(['amd64', 'i386', 'x86_64']))
72    @skipIfOutOfTreeDebugserver
73    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37995")
74    @expectedFailureNetBSD
75    def test_fp_special_purpose_register_read(self):
76        """Test commands that read fpu special purpose registers."""
77        self.build()
78        self.fp_special_purpose_register_read()
79
80    @skipIfiOSSimulator
81    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
82    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
83    def test_register_expressions(self):
84        """Test expression evaluation with commands related to registers."""
85        self.build()
86        self.common_setup()
87
88        if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
89            gpr = "eax"
90            vector = "xmm0"
91        elif self.getArchitecture() in ['arm64', 'aarch64', 'arm64e', 'arm64_32']:
92            gpr = "w0"
93            vector = "v0"
94        elif self.getArchitecture() in ['arm', 'armv7', 'armv7k']:
95            gpr = "r0"
96            vector = "q0"
97
98        self.expect("expr/x $%s" % gpr, substrs=['unsigned int', ' = 0x'])
99        self.expect("expr $%s" % vector, substrs=['vector_type'])
100        self.expect(
101            "expr (unsigned int)$%s[0]" %
102            vector, substrs=['unsigned int'])
103
104        if self.getArchitecture() in ['amd64', 'x86_64']:
105            self.expect(
106                "expr -- ($rax & 0xffffffff) == $eax",
107                substrs=['true'])
108
109    @skipIfiOSSimulator
110    @skipIf(archs=no_match(['amd64', 'x86_64']))
111    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
112    def test_convenience_registers(self):
113        """Test convenience registers."""
114        self.build()
115        self.convenience_registers()
116
117    @skipIfiOSSimulator
118    @skipIf(archs=no_match(['amd64', 'x86_64']))
119    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
120    @expectedFailureNetBSD
121    def test_convenience_registers_with_process_attach(self):
122        """Test convenience registers after a 'process attach'."""
123        self.build()
124        self.convenience_registers_with_process_attach(test_16bit_regs=False)
125
126    @skipIfiOSSimulator
127    @skipIf(archs=no_match(['amd64', 'x86_64']))
128    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
129    @expectedFailureNetBSD
130    def test_convenience_registers_16bit_with_process_attach(self):
131        """Test convenience registers after a 'process attach'."""
132        self.build()
133        self.convenience_registers_with_process_attach(test_16bit_regs=True)
134
135    def common_setup(self):
136        exe = self.getBuildArtifact("a.out")
137
138        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
139
140        # Break in main().
141        lldbutil.run_break_set_by_symbol(
142            self, "main", num_expected_locations=-1)
143
144        self.runCmd("run", RUN_SUCCEEDED)
145
146        # The stop reason of the thread should be breakpoint.
147        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
148                    substrs=['stopped', 'stop reason = breakpoint'])
149
150    # platform specific logging of the specified category
151    def log_enable(self, category):
152        # This intentionally checks the host platform rather than the target
153        # platform as logging is host side.
154        self.platform = ""
155        if (sys.platform.startswith("freebsd") or
156                sys.platform.startswith("linux") or
157                sys.platform.startswith("netbsd")):
158            self.platform = "posix"
159
160        if self.platform != "":
161            self.log_file = self.getBuildArtifact('TestRegisters.log')
162            self.runCmd(
163                "log enable " +
164                self.platform +
165                " " +
166                str(category) +
167                " registers -v -f " +
168                self.log_file,
169                RUN_SUCCEEDED)
170            if not self.has_teardown:
171                def remove_log(self):
172                    if os.path.exists(self.log_file):
173                        os.remove(self.log_file)
174                self.has_teardown = True
175                self.addTearDownHook(remove_log)
176
177    def write_and_read(self, frame, register, new_value, must_exist=True):
178        value = frame.FindValue(register, lldb.eValueTypeRegister)
179        if must_exist:
180            self.assertTrue(
181                value.IsValid(),
182                "finding a value for register " +
183                register)
184        elif not value.IsValid():
185            return  # If register doesn't exist, skip this test
186
187        # Also test the 're' alias.
188        self.runCmd("re write " + register + " \'" + new_value + "\'")
189        self.expect(
190            "register read " +
191            register,
192            substrs=[
193                register +
194                ' = ',
195                new_value])
196
197    def fp_special_purpose_register_read(self):
198        exe = self.getBuildArtifact("a.out")
199
200        # Create a target by the debugger.
201        target = self.dbg.CreateTarget(exe)
202        self.assertTrue(target, VALID_TARGET)
203
204        # Launch the process and stop.
205        self.expect("run", PROCESS_STOPPED, substrs=['stopped'])
206
207        # Check stop reason; Should be either signal SIGTRAP or EXC_BREAKPOINT
208        output = self.res.GetOutput()
209        matched = False
210        substrs = [
211            'stop reason = EXC_BREAKPOINT',
212            'stop reason = signal SIGTRAP']
213        for str1 in substrs:
214            matched = output.find(str1) != -1
215            with recording(self, False) as sbuf:
216                print("%s sub string: %s" % ('Expecting', str1), file=sbuf)
217                print("Matched" if matched else "Not Matched", file=sbuf)
218            if matched:
219                break
220        self.assertTrue(matched, STOPPED_DUE_TO_SIGNAL)
221
222        process = target.GetProcess()
223        self.assertTrue(process.GetState() == lldb.eStateStopped,
224                        PROCESS_STOPPED)
225
226        thread = process.GetThreadAtIndex(0)
227        self.assertTrue(thread.IsValid(), "current thread is valid")
228
229        currentFrame = thread.GetFrameAtIndex(0)
230        self.assertTrue(currentFrame.IsValid(), "current frame is valid")
231
232        # Extract the value of fstat and ftag flag at the point just before
233        # we start pushing floating point values on st% register stack
234        value = currentFrame.FindValue("fstat", lldb.eValueTypeRegister)
235        error = lldb.SBError()
236        reg_value_fstat_initial = value.GetValueAsUnsigned(error, 0)
237
238        self.assertTrue(error.Success(), "reading a value for fstat")
239        value = currentFrame.FindValue("ftag", lldb.eValueTypeRegister)
240        error = lldb.SBError()
241        reg_value_ftag_initial = value.GetValueAsUnsigned(error, 0)
242
243        self.assertTrue(error.Success(), "reading a value for ftag")
244        fstat_top_pointer_initial = (reg_value_fstat_initial & 0x3800) >> 11
245
246        # Execute 'si' aka 'thread step-inst' instruction 5 times and with
247        # every execution verify the value of fstat and ftag registers
248        for x in range(0, 5):
249            # step into the next instruction to push a value on 'st' register
250            # stack
251            self.runCmd("si", RUN_SUCCEEDED)
252
253            # Verify fstat and save it to be used for verification in next
254            # execution of 'si' command
255            if not (reg_value_fstat_initial & 0x3800):
256                self.expect("register read fstat", substrs=[
257                            'fstat' + ' = ', str("0x%0.4x" % ((reg_value_fstat_initial & ~(0x3800)) | 0x3800))])
258                reg_value_fstat_initial = (
259                    (reg_value_fstat_initial & ~(0x3800)) | 0x3800)
260                fstat_top_pointer_initial = 7
261            else:
262                self.expect("register read fstat", substrs=[
263                            'fstat' + ' = ', str("0x%0.4x" % (reg_value_fstat_initial - 0x0800))])
264                reg_value_fstat_initial = (reg_value_fstat_initial - 0x0800)
265                fstat_top_pointer_initial -= 1
266
267            # Verify ftag and save it to be used for verification in next
268            # execution of 'si' command
269            self.expect(
270                "register read ftag", substrs=[
271                    'ftag' + ' = ', str(
272                        "0x%0.4x" %
273                        (reg_value_ftag_initial | (
274                            1 << fstat_top_pointer_initial)))])
275            reg_value_ftag_initial = reg_value_ftag_initial | (
276                1 << fstat_top_pointer_initial)
277
278    def fp_register_write(self):
279        exe = self.getBuildArtifact("a.out")
280
281        # Create a target by the debugger.
282        target = self.dbg.CreateTarget(exe)
283        self.assertTrue(target, VALID_TARGET)
284
285        # Launch the process, stop at the entry point.
286        error = lldb.SBError()
287        process = target.Launch(
288                lldb.SBListener(),
289                None, None, # argv, envp
290                None, None, None, # stdin/out/err
291                self.get_process_working_directory(),
292                0, # launch flags
293                True, # stop at entry
294                error)
295        self.assertTrue(error.Success(), "Launch succeeds. Error is :" + str(error))
296
297        self.assertTrue(
298            process.GetState() == lldb.eStateStopped,
299            PROCESS_STOPPED)
300
301        thread = process.GetThreadAtIndex(0)
302        self.assertTrue(thread.IsValid(), "current thread is valid")
303
304        currentFrame = thread.GetFrameAtIndex(0)
305        self.assertTrue(currentFrame.IsValid(), "current frame is valid")
306
307        if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
308            reg_list = [
309                # reg          value        must-have
310                ("fcw", "0x0000ff0e", False),
311                ("fsw", "0x0000ff0e", False),
312                ("ftw", "0x0000ff0e", False),
313                ("ip", "0x0000ff0e", False),
314                ("dp", "0x0000ff0e", False),
315                ("mxcsr", "0x0000ff0e", False),
316                ("mxcsrmask", "0x0000ff0e", False),
317            ]
318
319            st0regname = None
320            if currentFrame.FindRegister("st0").IsValid():
321                st0regname = "st0"
322            elif currentFrame.FindRegister("stmm0").IsValid():
323                st0regname = "stmm0"
324            if st0regname is not None:
325                # reg          value
326                # must-have
327                reg_list.append(
328                    (st0regname, "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00}", True))
329                reg_list.append(
330                    ("xmm0",
331                     "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
332                     True))
333                reg_list.append(
334                    ("xmm15",
335                     "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
336                     False))
337        elif self.getArchitecture() in ['arm64', 'aarch64', 'arm64e', 'arm64_32']:
338            reg_list = [
339                # reg      value
340                # must-have
341                ("fpsr", "0xfbf79f9f", True),
342                ("s0", "1.25", True),
343                ("s31", "0.75", True),
344                ("d1", "123", True),
345                ("d17", "987", False),
346                ("v1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
347                ("v14",
348                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
349                 False),
350            ]
351        elif self.getArchitecture() in ['armv7'] and self.platformIsDarwin():
352            reg_list = [
353                # reg      value
354                # must-have
355                ("fpsr", "0xfbf79f9f", True),
356                ("s0", "1.25", True),
357                ("s31", "0.75", True),
358                ("d1", "123", True),
359                ("d17", "987", False),
360                ("q1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
361                ("q14",
362                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
363                 False),
364            ]
365        elif self.getArchitecture() in ['arm', 'armv7k']:
366            reg_list = [
367                # reg      value
368                # must-have
369                ("fpscr", "0xfbf79f9f", True),
370                ("s0", "1.25", True),
371                ("s31", "0.75", True),
372                ("d1", "123", True),
373                ("d17", "987", False),
374                ("q1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
375                ("q14",
376                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
377                 False),
378            ]
379
380        for (reg, val, must) in reg_list:
381            self.write_and_read(currentFrame, reg, val, must)
382
383        if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
384            if st0regname is None:
385                self.fail("st0regname could not be determined")
386            self.runCmd(
387                "register write " +
388                st0regname +
389                " \"{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}\"")
390            self.expect(
391                "register read " +
392                st0regname +
393                " --format f",
394                substrs=[
395                    st0regname +
396                    ' = 0'])
397
398            has_avx = False
399            has_mpx = False
400            # Returns an SBValueList.
401            registerSets = currentFrame.GetRegisters()
402            for registerSet in registerSets:
403                if 'advanced vector extensions' in registerSet.GetName().lower():
404                    has_avx = True
405                if 'memory protection extension' in registerSet.GetName().lower():
406                    has_mpx = True
407
408            if has_avx:
409                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}"
410                self.write_and_read(currentFrame, "ymm0", new_value)
411                self.write_and_read(currentFrame, "ymm7", new_value)
412                self.expect("expr $ymm0", substrs=['vector_type'])
413            else:
414                self.runCmd("register read ymm0")
415
416            if has_mpx:
417                # Test write and read for bnd0.
418                new_value_w = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10}"
419                self.runCmd("register write bnd0 \'" + new_value_w + "\'")
420                new_value_r = "{0x0807060504030201 0x100f0e0d0c0b0a09}"
421                self.expect("register read bnd0", substrs = ['bnd0 = ', new_value_r])
422                self.expect("expr $bnd0", substrs = ['vector_type'])
423
424                # Test write and for bndstatus.
425                new_value = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08}"
426                self.write_and_read(currentFrame, "bndstatus", new_value)
427                self.expect("expr $bndstatus", substrs = ['vector_type'])
428            else:
429                self.runCmd("register read bnd0")
430
431    def convenience_registers(self):
432        """Test convenience registers."""
433        self.common_setup()
434
435        # The command "register read -a" does output a derived register like
436        # eax...
437        self.expect("register read -a", matching=True,
438                    substrs=['eax'])
439
440        # ...however, the vanilla "register read" command should not output derived registers like eax.
441        self.expect("register read", matching=False,
442                    substrs=['eax'])
443
444        # Test reading of rax and eax.
445        self.expect("register read rax eax",
446                    substrs=['rax = 0x', 'eax = 0x'])
447
448        # Now write rax with a unique bit pattern and test that eax indeed
449        # represents the lower half of rax.
450        self.runCmd("register write rax 0x1234567887654321")
451        self.expect("register read rax 0x1234567887654321",
452                    substrs=['0x1234567887654321'])
453
454    def convenience_registers_with_process_attach(self, test_16bit_regs):
455        """Test convenience registers after a 'process attach'."""
456        exe = self.getBuildArtifact("a.out")
457
458        # Spawn a new process
459        pid = self.spawnSubprocess(exe, ['wait_for_attach']).pid
460        self.addTearDownHook(self.cleanupSubprocesses)
461
462        if self.TraceOn():
463            print("pid of spawned process: %d" % pid)
464
465        self.runCmd("process attach -p %d" % pid)
466
467        # Check that "register read eax" works.
468        self.runCmd("register read eax")
469
470        if self.getArchitecture() in ['amd64', 'x86_64']:
471            self.expect("expr -- ($rax & 0xffffffff) == $eax",
472                        substrs=['true'])
473
474        if test_16bit_regs:
475            self.expect("expr -- $ax == (($ah << 8) | $al)",
476                        substrs=['true'])
477
478    @skipIfiOSSimulator
479    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
480    def test_invalid_invocation(self):
481        self.build()
482        self.common_setup()
483
484        self.expect("register read -a arg", error=True,
485                    substrs=["the --all option can't be used when registers names are supplied as arguments"])
486
487        self.expect("register read --set 0 r", error=True,
488                    substrs=["the --set <set> option can't be used when registers names are supplied as arguments"])
489
490        self.expect("register write a", error=True,
491                    substrs=["register write takes exactly 2 arguments: <reg-name> <value>"])
492        self.expect("register write a b c", error=True,
493                    substrs=["register write takes exactly 2 arguments: <reg-name> <value>"])
494
495    @skipIfiOSSimulator
496    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
497    def test_write_unknown_register(self):
498        self.build()
499        self.common_setup()
500
501        self.expect("register write blub 1", error=True,
502                    substrs=["error: Register not found for 'blub'."])
503