xref: /llvm-project/lldb/test/API/commands/register/register/register_command/TestRegisters.py (revision 5056a4b556077da79afe34f54b5447c19a77d97d)
1"""
2Test the 'register' command.
3"""
4
5import os
6import sys
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class RegisterCommandsTestCase(TestBase):
14    NO_DEBUG_INFO_TESTCASE = True
15
16    def setUp(self):
17        TestBase.setUp(self)
18        self.has_teardown = False
19
20    def tearDown(self):
21        self.dbg.GetSelectedTarget().GetProcess().Destroy()
22        TestBase.tearDown(self)
23
24    # on macOS, detect if the current machine is arm64 and supports SME
25    def get_sme_available(self):
26        if self.getArchitecture() != "arm64":
27            return None
28        try:
29            sysctl_output = subprocess.check_output(
30                ["sysctl", "hw.optional.arm.FEAT_SME"]
31            ).decode("utf-8")
32        except subprocess.CalledProcessError:
33            return None
34        m = re.match(r"hw\.optional\.arm\.FEAT_SME: (\w+)", sysctl_output)
35        if m:
36            if int(m.group(1)) == 1:
37                return True
38            else:
39                return False
40        return None
41
42    @skipIfiOSSimulator
43    @skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
44    @expectedFailureAll(oslist=["freebsd", "netbsd"], bugnumber="llvm.org/pr48371")
45    def test_register_commands(self):
46        """Test commands related to registers, in particular vector registers."""
47        self.build()
48        self.common_setup()
49
50        # verify that logging does not assert
51        self.log_enable("registers")
52
53        error_str_matched = False
54        if self.get_sme_available() and self.platformIsDarwin():
55            # On Darwin AArch64 SME machines, we will have unavailable
56            # registers when not in Streaming SVE Mode/SME, so
57            # `register read -a` will report that some registers
58            # could not be read.  This is expected.
59            error_str_matched = True
60
61        if self.getArchitecture() == "x86_64" and self.platformIsDarwin():
62            # debugserver on x86 will provide ds/es/ss/gsbase when the
63            # kernel provides them, but most of the time they will be
64            # unavailable.  So "register read -a" will report that
65            # 4 registers were unavailable, it is expected.
66            error_str_matched = True
67
68        self.expect(
69            "register read -a",
70            MISSING_EXPECTED_REGISTERS,
71            substrs=["registers were unavailable"],
72            matching=error_str_matched,
73        )
74
75        all_registers = self.res.GetOutput()
76
77        if self.getArchitecture() in ["amd64", "i386", "x86_64"]:
78            self.runCmd("register read xmm0")
79            if "ymm15 = " in all_registers:
80                self.runCmd("register read ymm15")  # may be available
81            if "bnd0 = " in all_registers:
82                self.runCmd("register read bnd0")  # may be available
83        elif self.getArchitecture() in [
84            "arm",
85            "armv7",
86            "armv7k",
87            "arm64",
88            "arm64e",
89            "arm64_32",
90        ]:
91            self.runCmd("register read s0")
92            if "q15 = " in all_registers:
93                self.runCmd("register read q15")  # may be available
94
95        self.expect(
96            "register read -s 8", substrs=["invalid register set index: 8"], error=True
97        )
98
99    @skipIfiOSSimulator
100    # Writing of mxcsr register fails, presumably due to a kernel/hardware
101    # problem
102    @skipIfTargetAndroid(archs=["i386"])
103    @skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
104    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37995")
105    def test_fp_register_write(self):
106        """Test commands that write to registers, in particular floating-point registers."""
107        self.build()
108        self.fp_register_write()
109
110    @skipIfiOSSimulator
111    # "register read fstat" always return 0xffff
112    @expectedFailureAndroid(archs=["i386"])
113    @skipIf(archs=no_match(["amd64", "i386", "x86_64"]))
114    @skipIfOutOfTreeDebugserver
115    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37995")
116    def test_fp_special_purpose_register_read(self):
117        """Test commands that read fpu special purpose registers."""
118        self.build()
119        self.fp_special_purpose_register_read()
120
121    @skipIfiOSSimulator
122    @skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
123    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
124    def test_register_expressions(self):
125        """Test expression evaluation with commands related to registers."""
126        self.build()
127        self.common_setup()
128
129        if self.getArchitecture() in ["amd64", "i386", "x86_64"]:
130            gpr = "eax"
131            vector = "xmm0"
132        elif self.getArchitecture() in ["arm64", "aarch64", "arm64e", "arm64_32"]:
133            gpr = "w0"
134            vector = "v0"
135        elif self.getArchitecture() in ["arm", "armv7", "armv7k"]:
136            gpr = "r0"
137            vector = "q0"
138
139        self.expect("expr/x $%s" % gpr, substrs=["unsigned int", " = 0x"])
140        self.expect("expr $%s" % vector, substrs=["vector_type"])
141        self.expect("expr (unsigned int)$%s[0]" % vector, substrs=["unsigned int"])
142
143        if self.getArchitecture() in ["amd64", "x86_64"]:
144            self.expect("expr -- ($rax & 0xffffffff) == $eax", substrs=["true"])
145
146    @skipIfiOSSimulator
147    @skipIf(archs=no_match(["amd64", "x86_64"]))
148    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr37683")
149    def test_convenience_registers(self):
150        """Test convenience registers."""
151        self.build()
152        self.convenience_registers()
153
154    @skipIfiOSSimulator
155    @skipIf(archs=no_match(["amd64", "x86_64"]))
156    def test_convenience_registers_with_process_attach(self):
157        """Test convenience registers after a 'process attach'."""
158        self.build()
159        self.convenience_registers_with_process_attach(test_16bit_regs=False)
160
161    @skipIfiOSSimulator
162    @skipIf(archs=no_match(["amd64", "x86_64"]))
163    def test_convenience_registers_16bit_with_process_attach(self):
164        """Test convenience registers after a 'process attach'."""
165        self.build()
166        self.convenience_registers_with_process_attach(test_16bit_regs=True)
167
168    def common_setup(self):
169        exe = self.getBuildArtifact("a.out")
170
171        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
172
173        # Break in main().
174        lldbutil.run_break_set_by_symbol(self, "main", num_expected_locations=-1)
175
176        self.runCmd("run", RUN_SUCCEEDED)
177
178        # The stop reason of the thread should be breakpoint.
179        self.expect(
180            "thread list",
181            STOPPED_DUE_TO_BREAKPOINT,
182            substrs=["stopped", "stop reason = breakpoint"],
183        )
184
185    # platform specific logging of the specified category
186    def log_enable(self, category):
187        # This intentionally checks the host platform rather than the target
188        # platform as logging is host side.
189        self.platform = ""
190        if (
191            sys.platform.startswith("freebsd")
192            or sys.platform.startswith("linux")
193            or sys.platform.startswith("netbsd")
194        ):
195            self.platform = "posix"
196
197        if self.platform != "":
198            self.log_file = self.getBuildArtifact("TestRegisters.log")
199            self.runCmd(
200                "log enable "
201                + self.platform
202                + " "
203                + str(category)
204                + " registers -v -f "
205                + self.log_file,
206                RUN_SUCCEEDED,
207            )
208            if not self.has_teardown:
209
210                def remove_log(self):
211                    if os.path.exists(self.log_file):
212                        os.remove(self.log_file)
213
214                self.has_teardown = True
215                self.addTearDownHook(remove_log)
216
217    def write_and_read(self, frame, register, new_value, must_exist=True):
218        value = frame.FindValue(register, lldb.eValueTypeRegister)
219        if must_exist:
220            self.assertTrue(value.IsValid(), "finding a value for register " + register)
221        elif not value.IsValid():
222            return  # If register doesn't exist, skip this test
223
224        # Also test the 're' alias.
225        self.runCmd("re write " + register + " '" + new_value + "'")
226        self.expect("register read " + register, substrs=[register + " = ", new_value])
227
228    # This test relies on ftag containing the 'abridged' value.  Linux
229    # and *BSD targets have been ported to report the full value instead
230    # consistently with GDB.  They are covered by the new-style
231    # lldb/test/Shell/Register/x86*-fp-read.test.
232    @skipUnlessDarwin
233    def fp_special_purpose_register_read(self):
234        target = self.createTestTarget()
235
236        # Launch the process and stop.
237        self.expect("run", PROCESS_STOPPED, substrs=["stopped"])
238
239        # Check stop reason; Should be either signal SIGTRAP or EXC_BREAKPOINT
240        output = self.res.GetOutput()
241        matched = False
242        substrs = ["stop reason = EXC_BREAKPOINT", "stop reason = signal SIGTRAP"]
243        for str1 in substrs:
244            matched = output.find(str1) != -1
245            with recording(self, False) as sbuf:
246                print("%s sub string: %s" % ("Expecting", str1), file=sbuf)
247                print("Matched" if matched else "Not Matched", file=sbuf)
248            if matched:
249                break
250        self.assertTrue(matched, STOPPED_DUE_TO_SIGNAL)
251
252        process = target.GetProcess()
253        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
254
255        thread = process.GetThreadAtIndex(0)
256        self.assertTrue(thread.IsValid(), "current thread is valid")
257
258        currentFrame = thread.GetFrameAtIndex(0)
259        self.assertTrue(currentFrame.IsValid(), "current frame is valid")
260
261        # Extract the value of fstat and ftag flag at the point just before
262        # we start pushing floating point values on st% register stack
263        value = currentFrame.FindValue("fstat", lldb.eValueTypeRegister)
264        error = lldb.SBError()
265        reg_value_fstat_initial = value.GetValueAsUnsigned(error, 0)
266
267        self.assertSuccess(error, "reading a value for fstat")
268        value = currentFrame.FindValue("ftag", lldb.eValueTypeRegister)
269        error = lldb.SBError()
270        reg_value_ftag_initial = value.GetValueAsUnsigned(error, 0)
271
272        self.assertSuccess(error, "reading a value for ftag")
273        fstat_top_pointer_initial = (reg_value_fstat_initial & 0x3800) >> 11
274
275        # Execute 'si' aka 'thread step-inst' instruction 5 times and with
276        # every execution verify the value of fstat and ftag registers
277        for x in range(0, 5):
278            # step into the next instruction to push a value on 'st' register
279            # stack
280            self.runCmd("si", RUN_SUCCEEDED)
281
282            # Verify fstat and save it to be used for verification in next
283            # execution of 'si' command
284            if not (reg_value_fstat_initial & 0x3800):
285                self.expect(
286                    "register read fstat",
287                    substrs=[
288                        "fstat" + " = ",
289                        str(
290                            "0x%0.4x" % ((reg_value_fstat_initial & ~(0x3800)) | 0x3800)
291                        ),
292                    ],
293                )
294                reg_value_fstat_initial = (reg_value_fstat_initial & ~(0x3800)) | 0x3800
295                fstat_top_pointer_initial = 7
296            else:
297                self.expect(
298                    "register read fstat",
299                    substrs=[
300                        "fstat" + " = ",
301                        str("0x%0.4x" % (reg_value_fstat_initial - 0x0800)),
302                    ],
303                )
304                reg_value_fstat_initial = reg_value_fstat_initial - 0x0800
305                fstat_top_pointer_initial -= 1
306
307            # Verify ftag and save it to be used for verification in next
308            # execution of 'si' command
309            self.expect(
310                "register read ftag",
311                substrs=[
312                    "ftag" + " = ",
313                    str(
314                        "0x%0.4x"
315                        % (reg_value_ftag_initial | (1 << fstat_top_pointer_initial))
316                    ),
317                ],
318            )
319            reg_value_ftag_initial = reg_value_ftag_initial | (
320                1 << fstat_top_pointer_initial
321            )
322
323    def fp_register_write(self):
324        target = self.createTestTarget()
325
326        # Launch the process, stop at the entry point.
327        error = lldb.SBError()
328        flags = target.GetLaunchInfo().GetLaunchFlags()
329        process = target.Launch(
330            lldb.SBListener(),
331            None,
332            None,  # argv, envp
333            None,
334            None,
335            None,  # stdin/out/err
336            self.get_process_working_directory(),
337            flags,  # launch flags
338            True,  # stop at entry
339            error,
340        )
341        self.assertSuccess(error, "Launch succeeds")
342
343        self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
344
345        thread = process.GetThreadAtIndex(0)
346        self.assertTrue(thread.IsValid(), "current thread is valid")
347
348        currentFrame = thread.GetFrameAtIndex(0)
349        self.assertTrue(currentFrame.IsValid(), "current frame is valid")
350
351        if self.getArchitecture() in ["amd64", "i386", "x86_64"]:
352            reg_list = [
353                # reg          value        must-have
354                ("fcw", "0x0000ff0e", False),
355                ("fsw", "0x0000ff0e", False),
356                ("ftw", "0x0000ff0e", False),
357                ("ip", "0x0000ff0e", False),
358                ("dp", "0x0000ff0e", False),
359                ("mxcsr", "0x0000ff0e", False),
360                ("mxcsrmask", "0x0000ff0e", False),
361            ]
362
363            st0regname = None
364            # Darwin is using stmmN by default but support stN as an alias.
365            # Therefore, we need to check for stmmN first.
366            if currentFrame.FindRegister("stmm0").IsValid():
367                st0regname = "stmm0"
368            elif currentFrame.FindRegister("st0").IsValid():
369                st0regname = "st0"
370            if st0regname is not None:
371                # reg          value
372                # must-have
373                reg_list.append(
374                    (
375                        st0regname,
376                        "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00}",
377                        True,
378                    )
379                )
380                reg_list.append(
381                    (
382                        "xmm0",
383                        "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
384                        True,
385                    )
386                )
387                reg_list.append(
388                    (
389                        "xmm15",
390                        "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
391                        False,
392                    )
393                )
394        elif self.getArchitecture() in ["arm64", "aarch64", "arm64e", "arm64_32"]:
395            reg_list = [
396                # reg      value
397                # must-have
398                ("fpsr", "0xfbf79f9f", True),
399                ("s0", "1.25", True),
400                ("s31", "0.75", True),
401                ("d1", "123", True),
402                ("d17", "987", False),
403                (
404                    "v1",
405                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
406                    True,
407                ),
408                (
409                    "v14",
410                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
411                    False,
412                ),
413            ]
414        elif self.getArchitecture() in ["armv7"] and self.platformIsDarwin():
415            reg_list = [
416                # reg      value
417                # must-have
418                ("fpsr", "0xfbf79f9f", True),
419                ("s0", "1.25", True),
420                ("s31", "0.75", True),
421                ("d1", "123", True),
422                ("d17", "987", False),
423                (
424                    "q1",
425                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
426                    True,
427                ),
428                (
429                    "q14",
430                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
431                    False,
432                ),
433            ]
434        elif self.getArchitecture() in ["arm", "armv7k"]:
435            reg_list = [
436                # reg      value
437                # must-have
438                ("fpscr", "0xfbf79f9f", True),
439                ("s0", "1.25", True),
440                ("s31", "0.75", True),
441                ("d1", "123", True),
442                ("d17", "987", False),
443                (
444                    "q1",
445                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
446                    True,
447                ),
448                (
449                    "q14",
450                    "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
451                    False,
452                ),
453            ]
454
455        for reg, val, must in reg_list:
456            self.write_and_read(currentFrame, reg, val, must)
457
458        if self.getArchitecture() in ["amd64", "i386", "x86_64"]:
459            if st0regname is None:
460                self.fail("st0regname could not be determined")
461            self.runCmd(
462                "register write "
463                + st0regname
464                + ' "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"'
465            )
466            self.expect(
467                "register read " + st0regname + " --format f",
468                substrs=[st0regname + " = 0"],
469            )
470
471            # Check if AVX/MPX registers are defined at all.
472            registerSets = currentFrame.GetRegisters()
473            registers = frozenset(
474                reg.GetName() for registerSet in registerSets for reg in registerSet
475            )
476            has_avx_regs = "ymm0" in registers
477            has_mpx_regs = "bnd0" in registers
478            # Check if they are actually present.
479            self.runCmd("register read -a")
480            output = self.res.GetOutput()
481            has_avx = "ymm0 =" in output
482            has_mpx = "bnd0 =" in output
483
484            if has_avx:
485                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}"
486                self.write_and_read(currentFrame, "ymm0", new_value)
487                self.write_and_read(currentFrame, "ymm7", new_value)
488                self.expect("expr $ymm0", substrs=["vector_type"])
489            elif has_avx_regs:
490                self.expect("register read ymm0", substrs=["error: unavailable"])
491            else:
492                self.expect(
493                    "register read ymm0",
494                    substrs=["Invalid register name 'ymm0'"],
495                    error=True,
496                )
497
498            if has_mpx:
499                # Test write and read for bnd0.
500                new_value_w = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10}"
501                self.runCmd("register write bnd0 '" + new_value_w + "'")
502                new_value_r = "{0x0807060504030201 0x100f0e0d0c0b0a09}"
503                self.expect("register read bnd0", substrs=["bnd0 = ", new_value_r])
504                self.expect("expr $bnd0", substrs=["vector_type"])
505
506                # Test write and for bndstatus.
507                new_value = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08}"
508                self.write_and_read(currentFrame, "bndstatus", new_value)
509                self.expect("expr $bndstatus", substrs=["vector_type"])
510            elif has_mpx_regs:
511                self.expect("register read bnd0", substrs=["error: unavailable"])
512            else:
513                self.expect(
514                    "register read bnd0",
515                    substrs=["Invalid register name 'bnd0'"],
516                    error=True,
517                )
518
519    def convenience_registers(self):
520        """Test convenience registers."""
521        self.common_setup()
522
523        # The command "register read -a" does output a derived register like
524        # eax...
525        self.expect("register read -a", matching=True, substrs=["eax"])
526
527        # ...however, the vanilla "register read" command should not output derived registers like eax.
528        self.expect("register read", matching=False, substrs=["eax"])
529
530        # Test reading of rax and eax.
531        self.expect("register read rax eax", substrs=["rax = 0x", "eax = 0x"])
532
533        # Now write rax with a unique bit pattern and test that eax indeed
534        # represents the lower half of rax.
535        self.runCmd("register write rax 0x1234567887654321")
536        self.expect("register read rax", substrs=["0x1234567887654321"])
537
538    def convenience_registers_with_process_attach(self, test_16bit_regs):
539        """Test convenience registers after a 'process attach'."""
540        exe = self.getBuildArtifact("a.out")
541
542        # Spawn a new process
543        pid = self.spawnSubprocess(exe, ["wait_for_attach"]).pid
544
545        if self.TraceOn():
546            print("pid of spawned process: %d" % pid)
547
548        self.runCmd("process attach -p %d" % pid)
549
550        # Check that "register read eax" works.
551        self.runCmd("register read eax")
552
553        if self.getArchitecture() in ["amd64", "x86_64"]:
554            self.expect("expr -- ($rax & 0xffffffff) == $eax", substrs=["true"])
555
556        if test_16bit_regs:
557            self.expect("expr -- $ax == (($ah << 8) | $al)", substrs=["true"])
558
559    @skipIfiOSSimulator
560    @skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
561    def test_invalid_invocation(self):
562        self.build()
563        self.common_setup()
564
565        self.expect(
566            "register read -a arg",
567            error=True,
568            substrs=[
569                "the --all option can't be used when registers names are supplied as arguments"
570            ],
571        )
572
573        self.expect(
574            "register read --set 0 r",
575            error=True,
576            substrs=[
577                "the --set <set> option can't be used when registers names are supplied as arguments"
578            ],
579        )
580
581        self.expect(
582            "register write a",
583            error=True,
584            substrs=["register write takes exactly 2 arguments: <reg-name> <value>"],
585        )
586        self.expect(
587            "register write a b c",
588            error=True,
589            substrs=["register write takes exactly 2 arguments: <reg-name> <value>"],
590        )
591
592    @skipIfiOSSimulator
593    @skipIf(archs=no_match(["amd64", "arm", "i386", "x86_64"]))
594    def test_write_unknown_register(self):
595        self.build()
596        self.common_setup()
597
598        self.expect(
599            "register write blub 1",
600            error=True,
601            substrs=["error: Register not found for 'blub'."],
602        )
603
604    def test_info_unknown_register(self):
605        self.build()
606        self.common_setup()
607
608        self.expect(
609            "register info blub",
610            error=True,
611            substrs=["error: No register found with name 'blub'."],
612        )
613
614    def test_info_many_registers(self):
615        self.build()
616        self.common_setup()
617
618        # Only 1 register allowed at this time.
619        self.expect(
620            "register info abc def",
621            error=True,
622            substrs=["error: register info takes exactly 1 argument"],
623        )
624
625    @skipIf(archs=no_match(["aarch64"]))
626    def test_info_register(self):
627        # The behaviour of this command is generic but the specific registers
628        # are not, so this is written for AArch64 only.
629        # Text alignment and ordering are checked in the DumpRegisterInfo and
630        # RegisterFlags unit tests.
631        self.build()
632        self.common_setup()
633
634        # Standard register. Doesn't invalidate anything, doesn't have an alias.
635        self.expect(
636            "register info x1",
637            substrs=[
638                "Name: x1",
639                "Size: 8 bytes (64 bits)",
640                "In sets: General Purpose Registers",
641            ],
642        )
643        self.expect(
644            "register info x1", substrs=["Invalidates:", "Name: x1 ("], matching=False
645        )
646
647        # These registers invalidate others as they are subsets of those registers.
648        self.expect("register info w1", substrs=["Invalidates: x1"])
649        self.expect("register info s0", substrs=["Invalidates: v0, d0"])
650
651        # This has an alternative name according to the ABI.
652        self.expect("register info x30", substrs=["Name: lr (x30)"])
653
654    @skipIfXmlSupportMissing
655    @skipUnlessPlatform(["linux", "freebsd"])
656    @skipIf(archs=no_match(["aarch64"]))
657    def test_register_read_fields(self):
658        """Test that when debugging a live process, we see the fields of certain
659        registers."""
660        self.build()
661        self.common_setup()
662
663        # N/Z/C/V bits will always be present, so check only for those.
664        self.expect(
665            "register read cpsr",
666            patterns=["= \(N = [0|1], Z = [0|1], C = [0|1], V = [0|1]"],
667        )
668        self.expect(
669            "register read fpsr", patterns=["= \(QC = [0|1], IDC = [0|1], IXC = [0|1]"]
670        )
671        # AHP/DN/FZ always present, others may vary.
672        self.expect(
673            "register read fpcr", patterns=["= \(AHP = [0|1], DN = [0|1], FZ = [0|1]"]
674        )
675
676        # Should get enumerator descriptions for RMode.
677        self.expect(
678            "register info fpcr",
679            substrs=["RMode: 0 = RN, 1 = RP, 2 = RM, 3 = RZ"],
680        )
681
682    @skipUnlessPlatform(["linux"])
683    @skipIf(archs=no_match(["x86_64"]))
684    def test_fs_gs_base(self):
685        """
686        Tests fs_base register can be read and equals to pthread_self() return value
687        and gs_base register equals zero.
688        """
689        self.build()
690        target = self.createTestTarget()
691        # Launch the process and stop.
692        self.expect("run", PROCESS_STOPPED, substrs=["stopped"])
693
694        process = target.GetProcess()
695
696        thread = process.GetThreadAtIndex(0)
697        self.assertTrue(thread.IsValid(), "current thread is valid")
698
699        current_frame = thread.GetFrameAtIndex(0)
700        self.assertTrue(current_frame.IsValid(), "current frame is valid")
701
702        reg_fs_base = current_frame.FindRegister("fs_base")
703        self.assertTrue(reg_fs_base.IsValid(), "fs_base is not available")
704        reg_gs_base = current_frame.FindRegister("gs_base")
705        self.assertTrue(reg_gs_base.IsValid(), "gs_base is not available")
706        self.assertEqual(reg_gs_base.GetValueAsSigned(-1), 0, f"gs_base should be zero")
707
708        # Evaluate pthread_self() and compare against fs_base register read.
709        pthread_self_code = "(uint64_t)pthread_self()"
710        pthread_self_val = current_frame.EvaluateExpression(pthread_self_code)
711        self.assertTrue(
712            pthread_self_val.IsValid(), f"{pthread_self_code} evaluation has failed"
713        )
714        self.assertNotEqual(
715            reg_fs_base.GetValueAsSigned(-1), -1, f"fs_base returned -1 which is wrong"
716        )
717
718        self.assertEqual(
719            reg_fs_base.GetValueAsUnsigned(0),
720            pthread_self_val.GetValueAsUnsigned(0),
721            "fs_base does not equal to pthread_self() value.",
722        )
723
724    def test_process_must_be_stopped(self):
725        """Check that all register commands error when the process is not stopped."""
726        self.build()
727        exe = self.getBuildArtifact("a.out")
728        pid = self.spawnSubprocess(exe, ["wait_for_attach"]).pid
729        # Async so we can enter commands while the process is running.
730        self.setAsync(True)
731        self.runCmd("process attach --continue -p %d" % pid)
732
733        err_msg = "Command requires a process which is currently stopped."
734        self.expect("register read pc", substrs=[err_msg], error=True)
735        self.expect("register write pc 0", substrs=[err_msg], error=True)
736        self.expect("register info pc", substrs=[err_msg], error=True)
737