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