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