Home | History | Annotate | Download | only in register
      1 """
      2 Test the 'register' command.
      3 """
      4 
      5 import os, sys, time
      6 import re
      7 import unittest2
      8 import lldb
      9 from lldbtest import *
     10 import lldbutil
     11 
     12 class RegisterCommandsTestCase(TestBase):
     13 
     14     mydir = os.path.join("functionalities", "register")
     15 
     16     def setUp(self):
     17         TestBase.setUp(self)
     18         self.has_teardown = False
     19 
     20     def test_register_commands(self):
     21         """Test commands related to registers, in particular vector registers."""
     22         if not self.getArchitecture() in ['i386', 'x86_64']:
     23             self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
     24         self.buildDefault()
     25         self.register_commands()
     26 
     27     def test_fp_register_write(self):
     28         """Test commands that write to registers, in particular floating-point registers."""
     29         if not self.getArchitecture() in ['i386', 'x86_64']:
     30             self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
     31         self.buildDefault()
     32         self.fp_register_write()
     33 
     34     def test_register_expressions(self):
     35         """Test expression evaluation with commands related to registers."""
     36         if not self.getArchitecture() in ['i386', 'x86_64']:
     37             self.skipTest("This test requires i386 or x86_64 as the architecture for the inferior")
     38         self.buildDefault()
     39         self.register_expressions()
     40 
     41     def test_convenience_registers(self):
     42         """Test convenience registers."""
     43         if not self.getArchitecture() in ['x86_64']:
     44             self.skipTest("This test requires x86_64 as the architecture for the inferior")
     45         self.buildDefault()
     46         self.convenience_registers()
     47 
     48     def test_convenience_registers_with_process_attach(self):
     49         """Test convenience registers after a 'process attach'."""
     50         if not self.getArchitecture() in ['x86_64']:
     51             self.skipTest("This test requires x86_64 as the architecture for the inferior")
     52         self.buildDefault()
     53         self.convenience_registers_with_process_attach(test_16bit_regs=False)
     54 
     55     @expectedFailureLinux("llvm.org/pr14600") # Linux doesn't support 16-bit convenience registers
     56     @skipIfLinux # llvm.org/pr16301 LLDB occasionally exits with SIGABRT 
     57     def test_convenience_registers_16bit_with_process_attach(self):
     58         """Test convenience registers after a 'process attach'."""
     59         if not self.getArchitecture() in ['x86_64']:
     60             self.skipTest("This test requires x86_64 as the architecture for the inferior")
     61         self.buildDefault()
     62         self.convenience_registers_with_process_attach(test_16bit_regs=True)
     63 
     64     def common_setup(self):
     65         exe = os.path.join(os.getcwd(), "a.out")
     66 
     67         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
     68 
     69         # Break in main().
     70         lldbutil.run_break_set_by_symbol (self, "main", num_expected_locations=-1)
     71 
     72         self.runCmd("run", RUN_SUCCEEDED)
     73 
     74         # The stop reason of the thread should be breakpoint.
     75         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
     76             substrs = ['stopped', 'stop reason = breakpoint'])
     77 
     78     def remove_log(self):
     79         """ Remove the temporary log file generated by some tests."""
     80         if os.path.exists(self.log_file):
     81             os.remove(self.log_file)
     82 
     83     # platform specific logging of the specified category
     84     def log_enable(self, category):
     85         self.platform = ""
     86         if sys.platform.startswith("darwin"):
     87             self.platform = "" # TODO: add support for "log enable darwin registers"
     88         if sys.platform.startswith("linux"):
     89             self.platform = "linux"
     90 
     91         if self.platform != "":
     92             self.log_file = os.path.join(os.getcwd(), 'TestRegisters.log')
     93             self.runCmd("log enable " + self.platform + " " + str(category) + " registers -v -f " + self.log_file, RUN_SUCCEEDED)
     94             if not self.has_teardown:
     95                 self.has_teardown = True
     96                 self.addTearDownHook(self.remove_log)
     97 
     98     def register_commands(self):
     99         """Test commands related to registers, in particular vector registers."""
    100         self.common_setup()
    101 
    102         # verify that logging does not assert
    103         self.log_enable("registers")
    104 
    105         self.expect("register read -a", MISSING_EXPECTED_REGISTERS,
    106             substrs = ['registers were unavailable'], matching = False)
    107         self.runCmd("register read xmm0")
    108         self.runCmd("register read ymm15") # may be available
    109 
    110         self.expect("register read -s 3",
    111             substrs = ['invalid register set index: 3'], error = True)
    112 
    113     def write_and_restore(self, frame, register, must_exist = True):
    114         value = frame.FindValue(register, lldb.eValueTypeRegister)
    115         if must_exist:
    116             self.assertTrue(value.IsValid(), "finding a value for register " + register)
    117         elif not value.IsValid():
    118             return # If register doesn't exist, skip this test
    119 
    120         error = lldb.SBError()
    121         register_value = value.GetValueAsUnsigned(error, 0)
    122         self.assertTrue(error.Success(), "reading a value for " + register)
    123 
    124         self.runCmd("register write " + register + " 0xff0e")
    125         self.expect("register read " + register,
    126             substrs = [register + ' = 0x', 'ff0e'])
    127 
    128         self.runCmd("register write " + register + " " + str(register_value))
    129         self.expect("register read " + register,
    130             substrs = [register + ' = 0x'])
    131 
    132     def vector_write_and_read(self, frame, register, new_value, must_exist = True):
    133         value = frame.FindValue(register, lldb.eValueTypeRegister)
    134         if must_exist:
    135             self.assertTrue(value.IsValid(), "finding a value for register " + register)
    136         elif not value.IsValid():
    137             return # If register doesn't exist, skip this test
    138 
    139         self.runCmd("register write " + register + " \'" + new_value + "\'")
    140         self.expect("register read " + register,
    141             substrs = [register + ' = ', new_value])
    142 
    143     def fp_register_write(self):
    144         exe = os.path.join(os.getcwd(), "a.out")
    145 
    146         # Create a target by the debugger.
    147         target = self.dbg.CreateTarget(exe)
    148         self.assertTrue(target, VALID_TARGET)
    149 
    150         lldbutil.run_break_set_by_symbol (self, "main", num_expected_locations=-1)
    151 
    152         # Launch the process, and do not stop at the entry point.
    153         process = target.LaunchSimple(None, None, os.getcwd())
    154 
    155         process = target.GetProcess()
    156         self.assertTrue(process.GetState() == lldb.eStateStopped,
    157                         PROCESS_STOPPED)
    158 
    159         thread = process.GetThreadAtIndex(0)
    160         self.assertTrue(thread.IsValid(), "current thread is valid")
    161 
    162         currentFrame = thread.GetFrameAtIndex(0)
    163         self.assertTrue(currentFrame.IsValid(), "current frame is valid")
    164 
    165         self.write_and_restore(currentFrame, "fcw", False)
    166         self.write_and_restore(currentFrame, "fsw", False)
    167         self.write_and_restore(currentFrame, "ftw", False)
    168         self.write_and_restore(currentFrame, "ip", False)
    169         self.write_and_restore(currentFrame, "dp", False)
    170         self.write_and_restore(currentFrame, "mxcsr", False)
    171         self.write_and_restore(currentFrame, "mxcsrmask", False)
    172 
    173         new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
    174         self.vector_write_and_read(currentFrame, "stmm0", new_value)
    175         new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a}"
    176         self.vector_write_and_read(currentFrame, "stmm7", new_value)
    177 
    178         new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f}"
    179         self.vector_write_and_read(currentFrame, "xmm0", new_value)
    180         new_value = "{0x01 0x02 0x03 0x00 0x00 0x00 0x00 0x00 0x09 0x0a 0x2f 0x2f 0x2f 0x2f 0x0e 0x0f}"
    181         self.vector_write_and_read(currentFrame, "xmm15", new_value, False)
    182 
    183         has_avx = False 
    184         registerSets = currentFrame.GetRegisters() # Returns an SBValueList.
    185         for registerSet in registerSets:
    186             if 'advanced vector extensions' in registerSet.GetName().lower():
    187                 has_avx = True
    188                 break
    189 
    190         if has_avx:
    191             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}"
    192             self.vector_write_and_read(currentFrame, "ymm0", new_value)
    193             self.vector_write_and_read(currentFrame, "ymm15", new_value)
    194             self.expect("expr $ymm0", substrs = ['vector_type'])
    195         else:
    196             self.runCmd("register read ymm0")
    197 
    198     def register_expressions(self):
    199         """Test expression evaluation with commands related to registers."""
    200         self.common_setup()
    201 
    202         self.expect("expr/x $eax",
    203             substrs = ['unsigned int', ' = 0x'])
    204 
    205         if self.getArchitecture() in ['x86_64']:
    206             self.expect("expr -- ($rax & 0xffffffff) == $eax",
    207                 substrs = ['true'])
    208 
    209         self.expect("expr $xmm0",
    210             substrs = ['vector_type'])
    211 
    212         self.expect("expr (unsigned int)$xmm0[0]",
    213             substrs = ['unsigned int'])
    214 
    215     def convenience_registers(self):
    216         """Test convenience registers."""
    217         self.common_setup()
    218 
    219         # The command "register read -a" does output a derived register like eax...
    220         self.expect("register read -a", matching=True,
    221             substrs = ['eax'])
    222 
    223         # ...however, the vanilla "register read" command should not output derived registers like eax.
    224         self.expect("register read", matching=False,
    225             substrs = ['eax'])
    226         
    227         # Test reading of rax and eax.
    228         self.expect("register read rax eax",
    229             substrs = ['rax = 0x', 'eax = 0x'])
    230 
    231         # Now write rax with a unique bit pattern and test that eax indeed represents the lower half of rax.
    232         self.runCmd("register write rax 0x1234567887654321")
    233         self.expect("register read rax 0x1234567887654321",
    234             substrs = ['0x1234567887654321'])
    235 
    236     def convenience_registers_with_process_attach(self, test_16bit_regs):
    237         """Test convenience registers after a 'process attach'."""
    238         exe = os.path.join(os.getcwd(), "a.out")
    239 
    240         # Spawn a new process
    241         pid = 0
    242         if sys.platform.startswith('linux'):
    243             pid = self.forkSubprocess(exe, ['wait_for_attach'])
    244         else:
    245             proc = self.spawnSubprocess(exe, ['wait_for_attach'])
    246             pid = proc.pid
    247         self.addTearDownHook(self.cleanupSubprocesses)
    248 
    249         if self.TraceOn():
    250             print "pid of spawned process: %d" % pid
    251 
    252         self.runCmd("process attach -p %d" % pid)
    253 
    254         # Check that "register read eax" works.
    255         self.runCmd("register read eax")
    256 
    257         if self.getArchitecture() in ['x86_64']:
    258             self.expect("expr -- ($rax & 0xffffffff) == $eax",
    259                 substrs = ['true'])
    260 
    261         if test_16bit_regs:
    262             self.expect("expr -- $ax == (($ah << 8) | $al)",
    263                 substrs = ['true'])
    264 
    265 if __name__ == '__main__':
    266     import atexit
    267     lldb.SBDebugger.Initialize()
    268     atexit.register(lambda: lldb.SBDebugger.Terminate())
    269     unittest2.main()
    270