1from __future__ import print_function
2import lldb
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test.decorators import *
5from lldbsuite.test.gdbclientutils import *
6from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
7
8
9# This test case checks for register number mismatch between lldb and gdb stub.
10# LLDB client assigns register numbers to target xml registers in increasing
11# order starting with regnum = 0, while gdb-remote may specify different regnum
12# which is stored as eRegisterKindProcessPlugin. Remote side will use its
13# register number in expedited register list, value_regs and invalidate_regnums.
14#
15# This test creates a ficticious target xml with non-sequential regnums to test
16# that correct registers are accessed in all of above mentioned cases.
17
18class TestRemoteRegNums(GDBRemoteTestBase):
19
20    @skipIfXmlSupportMissing
21    def test(self):
22        class MyResponder(MockGDBServerResponder):
23            def haltReason(self):
24                return "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;00:00bc010001000000;09:c04825ebfe7f0000;"
25
26            def threadStopInfo(self, threadnum):
27                return "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;00:00bc010001000000;09:c04825ebfe7f0000;"
28
29            def writeRegisters(self):
30                return "E02"
31
32            def readRegisters(self):
33                return "E01"
34
35            rax_regnum2_val = "7882773ce0ffffff"
36            rbx_regnum4_val = "1122334455667788"
37
38            def readRegister(self, regnum):
39                # lldb will try sending "p0" to see if the p packet is supported,
40                # give a bogus value; in theory lldb could use this value in the
41                # register context and that would be valid behavior.
42
43                # notably, don't give values for registers 1 & 3 -- lldb should
44                # get those from the ? stop packet ("T11") and it is a pref regression
45                # if lldb is asking for these register values.
46                if regnum == 0:
47                    return "5555555555555555"
48                if regnum == 2:
49                    return self.rax_regnum2_val
50                if regnum == 4:
51                    return self.rbx_regnum4_val
52
53                return "E03"
54
55            def writeRegister(self, regnum, value_hex):
56                if regnum == 2:
57                    self.rax_regnum2_val = value_hex
58                if regnum == 4:
59                    self.rbx_regnum4_val = value_hex
60
61                return "OK"
62
63            def qXferRead(self, obj, annex, offset, length):
64                if annex == "target.xml":
65                    return """<?xml version="1.0"?>
66                        <target version="1.0">
67                          <architecture>i386:x86-64</architecture>
68                          <feature name="org.gnu.gdb.i386.core">
69                            <reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general" altname="pc" generic="pc"/>
70                            <reg name="rax" bitsize="64" regnum="2" type="code_ptr" group="general"/>
71                            <reg name="rbx" bitsize="64" regnum="4" type="code_ptr" group="general"/>
72                            <reg name="eax" bitsize="32" regnum="5" value_regnums="2" invalidate_regnums="2" type="code_ptr" group="general"/>
73                            <reg name="ebx" bitsize="32" regnum="7" value_regnums="4" invalidate_regnums="4" type="code_ptr" group="general"/>
74                            <reg name="rsi" bitsize="64" regnum="9" type="code_ptr" group="general"/>
75                          </feature>
76                        </target>""", False
77                else:
78                    return None, False
79
80        self.server.responder = MyResponder()
81        target = self.dbg.CreateTarget('')
82        if self.TraceOn():
83            self.runCmd("log enable gdb-remote packets")
84            self.addTearDownHook(
85                lambda: self.runCmd("log disable gdb-remote packets"))
86        process = self.connect(target)
87
88        thread = process.GetThreadAtIndex(0)
89        frame = thread.GetFrameAtIndex(0)
90        rax = frame.FindRegister("rax").GetValueAsUnsigned()
91        eax = frame.FindRegister("eax").GetValueAsUnsigned()
92        rbx = frame.FindRegister("rbx").GetValueAsUnsigned()
93        ebx = frame.FindRegister("ebx").GetValueAsUnsigned()
94        rsi = frame.FindRegister("rsi").GetValueAsUnsigned()
95        pc = frame.GetPC()
96        rip = frame.FindRegister("rip").GetValueAsUnsigned()
97
98        if self.TraceOn():
99            print("Register values: rax == 0x%x, rbx == 0x%x, rsi == 0x%x, pc == 0x%x, rip == 0x%x" % (
100                rax, rbx, rsi, pc, rip))
101
102        self.assertEqual(rax, 0xffffffe03c778278)
103        self.assertEqual(rbx, 0x8877665544332211)
104        self.assertEqual(eax, 0x3c778278)
105        self.assertEqual(ebx, 0x44332211)
106        self.assertEqual(rsi, 0x00007ffeeb2548c0)
107        self.assertEqual(pc, 0x10001bc00)
108        self.assertEqual(rip, 0x10001bc00)
109
110        frame.FindRegister("eax").SetValueFromCString("1")
111        frame.FindRegister("ebx").SetValueFromCString("0")
112        eax = frame.FindRegister("eax").GetValueAsUnsigned()
113        ebx = frame.FindRegister("ebx").GetValueAsUnsigned()
114        rax = frame.FindRegister("rax").GetValueAsUnsigned()
115        rbx = frame.FindRegister("rbx").GetValueAsUnsigned()
116
117        if self.TraceOn():
118            print("Register values: rax == 0x%x, rbx == 0x%x, rsi == 0x%x, pc == 0x%x, rip == 0x%x" % (
119                rax, rbx, rsi, pc, rip))
120
121        self.assertEqual(rax, 0xffffffe000000001)
122        self.assertEqual(rbx, 0x8877665500000000)
123        self.assertEqual(eax, 0x00000001)
124        self.assertEqual(ebx, 0x00000000)
125        self.assertEqual(rsi, 0x00007ffeeb2548c0)
126        self.assertEqual(pc, 0x10001bc00)
127        self.assertEqual(rip, 0x10001bc00)
128