• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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            if currentFrame.FindRegister("st0").IsValid():
324                st0regname = "st0"
325            elif currentFrame.FindRegister("stmm0").IsValid():
326                st0regname = "stmm0"
327            if st0regname is not None:
328                # reg          value
329                # must-have
330                reg_list.append(
331                    (st0regname, "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00}", True))
332                reg_list.append(
333                    ("xmm0",
334                     "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}",
335                     True))
336                reg_list.append(
337                    ("xmm15",
338                     "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
339                     False))
340        elif self.getArchitecture() in ['arm64', 'aarch64', 'arm64e', 'arm64_32']:
341            reg_list = [
342                # reg      value
343                # must-have
344                ("fpsr", "0xfbf79f9f", True),
345                ("s0", "1.25", True),
346                ("s31", "0.75", True),
347                ("d1", "123", True),
348                ("d17", "987", False),
349                ("v1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
350                ("v14",
351                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
352                 False),
353            ]
354        elif self.getArchitecture() in ['armv7'] and self.platformIsDarwin():
355            reg_list = [
356                # reg      value
357                # must-have
358                ("fpsr", "0xfbf79f9f", True),
359                ("s0", "1.25", True),
360                ("s31", "0.75", True),
361                ("d1", "123", True),
362                ("d17", "987", False),
363                ("q1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
364                ("q14",
365                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
366                 False),
367            ]
368        elif self.getArchitecture() in ['arm', 'armv7k']:
369            reg_list = [
370                # reg      value
371                # must-have
372                ("fpscr", "0xfbf79f9f", True),
373                ("s0", "1.25", True),
374                ("s31", "0.75", True),
375                ("d1", "123", True),
376                ("d17", "987", False),
377                ("q1", "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}", True),
378                ("q14",
379                 "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}",
380                 False),
381            ]
382
383        for (reg, val, must) in reg_list:
384            self.write_and_read(currentFrame, reg, val, must)
385
386        if self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
387            if st0regname is None:
388                self.fail("st0regname could not be determined")
389            self.runCmd(
390                "register write " +
391                st0regname +
392                " \"{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}\"")
393            self.expect(
394                "register read " +
395                st0regname +
396                " --format f",
397                substrs=[
398                    st0regname +
399                    ' = 0'])
400
401            has_avx = False
402            has_mpx = False
403            # Returns an SBValueList.
404            registerSets = currentFrame.GetRegisters()
405            for registerSet in registerSets:
406                if 'advanced vector extensions' in registerSet.GetName().lower():
407                    has_avx = True
408                # FreeBSD/NetBSD reports missing register sets differently
409                # at the moment and triggers false positive here.
410                # TODO: remove FreeBSD/NetBSD exception when we make unsupported
411                # register groups correctly disappear.
412                if ('memory protection extension' in registerSet.GetName().lower()
413                        and self.getPlatform() not in ["freebsd", "netbsd"]):
414                    has_mpx = True
415
416            if has_avx:
417                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}"
418                self.write_and_read(currentFrame, "ymm0", new_value)
419                self.write_and_read(currentFrame, "ymm7", new_value)
420                self.expect("expr $ymm0", substrs=['vector_type'])
421            else:
422                self.runCmd("register read ymm0")
423
424            if has_mpx:
425                # Test write and read for bnd0.
426                new_value_w = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10}"
427                self.runCmd("register write bnd0 \'" + new_value_w + "\'")
428                new_value_r = "{0x0807060504030201 0x100f0e0d0c0b0a09}"
429                self.expect("register read bnd0", substrs = ['bnd0 = ', new_value_r])
430                self.expect("expr $bnd0", substrs = ['vector_type'])
431
432                # Test write and for bndstatus.
433                new_value = "{0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08}"
434                self.write_and_read(currentFrame, "bndstatus", new_value)
435                self.expect("expr $bndstatus", substrs = ['vector_type'])
436            else:
437                self.runCmd("register read bnd0")
438
439    def convenience_registers(self):
440        """Test convenience registers."""
441        self.common_setup()
442
443        # The command "register read -a" does output a derived register like
444        # eax...
445        self.expect("register read -a", matching=True,
446                    substrs=['eax'])
447
448        # ...however, the vanilla "register read" command should not output derived registers like eax.
449        self.expect("register read", matching=False,
450                    substrs=['eax'])
451
452        # Test reading of rax and eax.
453        self.expect("register read rax eax",
454                    substrs=['rax = 0x', 'eax = 0x'])
455
456        # Now write rax with a unique bit pattern and test that eax indeed
457        # represents the lower half of rax.
458        self.runCmd("register write rax 0x1234567887654321")
459        self.expect("register read rax 0x1234567887654321",
460                    substrs=['0x1234567887654321'])
461
462    def convenience_registers_with_process_attach(self, test_16bit_regs):
463        """Test convenience registers after a 'process attach'."""
464        exe = self.getBuildArtifact("a.out")
465
466        # Spawn a new process
467        pid = self.spawnSubprocess(exe, ['wait_for_attach']).pid
468
469        if self.TraceOn():
470            print("pid of spawned process: %d" % pid)
471
472        self.runCmd("process attach -p %d" % pid)
473
474        # Check that "register read eax" works.
475        self.runCmd("register read eax")
476
477        if self.getArchitecture() in ['amd64', 'x86_64']:
478            self.expect("expr -- ($rax & 0xffffffff) == $eax",
479                        substrs=['true'])
480
481        if test_16bit_regs:
482            self.expect("expr -- $ax == (($ah << 8) | $al)",
483                        substrs=['true'])
484
485    @skipIfiOSSimulator
486    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
487    def test_invalid_invocation(self):
488        self.build()
489        self.common_setup()
490
491        self.expect("register read -a arg", error=True,
492                    substrs=["the --all option can't be used when registers names are supplied as arguments"])
493
494        self.expect("register read --set 0 r", error=True,
495                    substrs=["the --set <set> option can't be used when registers names are supplied as arguments"])
496
497        self.expect("register write a", error=True,
498                    substrs=["register write takes exactly 2 arguments: <reg-name> <value>"])
499        self.expect("register write a b c", error=True,
500                    substrs=["register write takes exactly 2 arguments: <reg-name> <value>"])
501
502    @skipIfiOSSimulator
503    @skipIf(archs=no_match(['amd64', 'arm', 'i386', 'x86_64']))
504    def test_write_unknown_register(self):
505        self.build()
506        self.common_setup()
507
508        self.expect("register write blub 1", error=True,
509                    substrs=["error: Register not found for 'blub'."])
510