1"""
2Check that lldb falls back to default register layouts when the remote provides
3no target XML or does not include registers in the target XML.
4
5GPRS are passed to the responder to create register data to send back to lldb.
6Registers in SUPPL are virtual registers based on those general ones. The tests
7pass __file__ to FileCheck so any prefixes in this Python file will be checked.
8"""
9
10import lldb
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test.decorators import *
13from lldbsuite.test.gdbclientutils import *
14from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
15
16import binascii
17from textwrap import dedent
18
19
20class MyResponder(MockGDBServerResponder):
21    @staticmethod
22    def filecheck_to_blob(fc):
23        for l in fc.strip().splitlines():
24            val = l.split("0x")[1]
25            yield binascii.b2a_hex(bytes(reversed(binascii.a2b_hex(val)))).decode()
26
27    def __init__(self, architecture, has_target_xml, reg_data, halt_reason):
28        super().__init__()
29        self.architecture = architecture
30        self.has_target_xml = has_target_xml
31        self.reg_data = "".join(self.filecheck_to_blob(reg_data))
32        self.halt_reason = halt_reason
33
34    def readRegister(self, regnum):
35        return ""
36
37    def readRegisters(self):
38        return self.reg_data
39
40    def haltReason(self):
41        return self.halt_reason
42
43    def qXferRead(self, obj, annex, offset, length):
44        if self.has_target_xml and annex == "target.xml":
45            return (
46                dedent(
47                    f"""\
48                    <?xml version="1.0"?>
49                    <target version="1.0">
50                      <architecture>{self.architecture}</architecture>
51                    </target>"""
52                ),
53                False,
54            )
55
56        return None, False
57
58
59class TestGDBServerTargetXML(GDBRemoteTestBase):
60    def check_x86_64_regs(self, has_target_xml):
61        GPRS = """
62CHECK-AMD64-DAG: rax = 0x0807060504030201
63CHECK-AMD64-DAG: rbx = 0x1817161514131211
64CHECK-AMD64-DAG: rcx = 0x2827262524232221
65CHECK-AMD64-DAG: rdx = 0x3837363534333231
66CHECK-AMD64-DAG: rsi = 0x4847464544434241
67CHECK-AMD64-DAG: rdi = 0x5857565554535251
68CHECK-AMD64-DAG: rbp = 0x6867666564636261
69CHECK-AMD64-DAG: rsp = 0x7877767574737271
70CHECK-AMD64-DAG: r8 = 0x8887868584838281
71CHECK-AMD64-DAG: r9 = 0x9897969594939291
72CHECK-AMD64-DAG: r10 = 0xa8a7a6a5a4a3a2a1
73CHECK-AMD64-DAG: r11 = 0xb8b7b6b5b4b3b2b1
74CHECK-AMD64-DAG: r12 = 0xc8c7c6c5c4c3c2c1
75CHECK-AMD64-DAG: r13 = 0xd8d7d6d5d4d3d2d1
76CHECK-AMD64-DAG: r14 = 0xe8e7e6e5e4e3e2e1
77CHECK-AMD64-DAG: r15 = 0xf8f7f6f5f4f3f2f1
78CHECK-AMD64-DAG: rip = 0x100f0e0d0c0b0a09
79CHECK-AMD64-DAG: eflags = 0x1c1b1a19
80CHECK-AMD64-DAG: cs = 0x2c2b2a29
81CHECK-AMD64-DAG: ss = 0x3c3b3a39
82"""
83
84        SUPPL = """
85CHECK-AMD64-DAG: eax = 0x04030201
86CHECK-AMD64-DAG: ebx = 0x14131211
87CHECK-AMD64-DAG: ecx = 0x24232221
88CHECK-AMD64-DAG: edx = 0x34333231
89CHECK-AMD64-DAG: esi = 0x44434241
90CHECK-AMD64-DAG: edi = 0x54535251
91CHECK-AMD64-DAG: ebp = 0x64636261
92CHECK-AMD64-DAG: esp = 0x74737271
93CHECK-AMD64-DAG: r8d = 0x84838281
94CHECK-AMD64-DAG: r9d = 0x94939291
95CHECK-AMD64-DAG: r10d = 0xa4a3a2a1
96CHECK-AMD64-DAG: r11d = 0xb4b3b2b1
97CHECK-AMD64-DAG: r12d = 0xc4c3c2c1
98CHECK-AMD64-DAG: r13d = 0xd4d3d2d1
99CHECK-AMD64-DAG: r14d = 0xe4e3e2e1
100CHECK-AMD64-DAG: r15d = 0xf4f3f2f1
101
102CHECK-AMD64-DAG: ax = 0x0201
103CHECK-AMD64-DAG: bx = 0x1211
104CHECK-AMD64-DAG: cx = 0x2221
105CHECK-AMD64-DAG: dx = 0x3231
106CHECK-AMD64-DAG: si = 0x4241
107CHECK-AMD64-DAG: di = 0x5251
108CHECK-AMD64-DAG: bp = 0x6261
109CHECK-AMD64-DAG: sp = 0x7271
110CHECK-AMD64-DAG: r8w = 0x8281
111CHECK-AMD64-DAG: r9w = 0x9291
112CHECK-AMD64-DAG: r10w = 0xa2a1
113CHECK-AMD64-DAG: r11w = 0xb2b1
114CHECK-AMD64-DAG: r12w = 0xc2c1
115CHECK-AMD64-DAG: r13w = 0xd2d1
116CHECK-AMD64-DAG: r14w = 0xe2e1
117CHECK-AMD64-DAG: r15w = 0xf2f1
118
119CHECK-AMD64-DAG: ah = 0x02
120CHECK-AMD64-DAG: bh = 0x12
121CHECK-AMD64-DAG: ch = 0x22
122CHECK-AMD64-DAG: dh = 0x32
123
124CHECK-AMD64-DAG: al = 0x01
125CHECK-AMD64-DAG: bl = 0x11
126CHECK-AMD64-DAG: cl = 0x21
127CHECK-AMD64-DAG: dl = 0x31
128CHECK-AMD64-DAG: sil = 0x41
129CHECK-AMD64-DAG: dil = 0x51
130CHECK-AMD64-DAG: bpl = 0x61
131CHECK-AMD64-DAG: spl = 0x71
132CHECK-AMD64-DAG: r8l = 0x81
133CHECK-AMD64-DAG: r9l = 0x91
134CHECK-AMD64-DAG: r10l = 0xa1
135CHECK-AMD64-DAG: r11l = 0xb1
136CHECK-AMD64-DAG: r12l = 0xc1
137CHECK-AMD64-DAG: r13l = 0xd1
138CHECK-AMD64-DAG: r14l = 0xe1
139CHECK-AMD64-DAG: r15l = 0xf1
140"""
141
142        self.server.responder = MyResponder(
143            "x86-64",
144            has_target_xml,
145            GPRS,
146            "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;07:0102030405060708;10:1112131415161718;",
147        )
148
149        target = self.createTarget("basic_eh_frame.yaml")
150        process = self.connect(target)
151        lldbutil.expect_state_changes(
152            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
153        )
154
155        # test all registers
156        self.filecheck(
157            "register read --all",
158            __file__,
159            filecheck_options="--check-prefix=CHECK-AMD64",
160        )
161
162        # test generic aliases
163        self.match("register read arg4", ["rcx = 0x2827262524232221"])
164        self.match("register read arg3", ["rdx = 0x3837363534333231"])
165        self.match("register read arg2", ["rsi = 0x4847464544434241"])
166        self.match("register read arg1", ["rdi = 0x5857565554535251"])
167        self.match("register read fp", ["rbp = 0x6867666564636261"])
168        self.match("register read sp", ["rsp = 0x7877767574737271"])
169        self.match("register read arg5", ["r8 = 0x8887868584838281"])
170        self.match("register read arg6", ["r9 = 0x9897969594939291"])
171        self.match("register read pc", ["rip = 0x100f0e0d0c0b0a09"])
172        self.match("register read flags", ["eflags = 0x1c1b1a19"])
173
174    @skipIfRemote
175    @skipIfLLVMTargetMissing("X86")
176    def test_x86_64_regs_no_target_xml(self):
177        """Test grabbing various x86_64 registers from gdbserver when there
178        is no target XML."""
179        self.check_x86_64_regs(False)
180
181    @skipIfXmlSupportMissing
182    @skipIfRemote
183    @skipIfLLVMTargetMissing("X86")
184    def test_x86_64_regs_no_register_info(self):
185        """Test grabbing various x86_64 registers from gdbserver when there
186        is target XML but it does not include register info."""
187        self.check_x86_64_regs(True)
188
189    def check_aarch64_regs(self, has_target_xml):
190        GPRS = """
191CHECK-AARCH64-DAG: x0 = 0x0001020304050607
192CHECK-AARCH64-DAG: x1 = 0x0102030405060708
193CHECK-AARCH64-DAG: x2 = 0x0203040506070809
194CHECK-AARCH64-DAG: x3 = 0x030405060708090a
195CHECK-AARCH64-DAG: x4 = 0x0405060708090a0b
196CHECK-AARCH64-DAG: x5 = 0x05060708090a0b0c
197CHECK-AARCH64-DAG: x6 = 0x060708090a0b0c0d
198CHECK-AARCH64-DAG: x7 = 0x0708090a0b0c0d0e
199CHECK-AARCH64-DAG: x8 = 0x08090a0b0c0d0e0f
200CHECK-AARCH64-DAG: x9 = 0x090a0b0c0d0e0f10
201CHECK-AARCH64-DAG: x10 = 0x0a0b0c0d0e0f1011
202CHECK-AARCH64-DAG: x11 = 0x0b0c0d0e0f101112
203CHECK-AARCH64-DAG: x12 = 0x0c0d0e0f10111213
204CHECK-AARCH64-DAG: x13 = 0x0d0e0f1011121314
205CHECK-AARCH64-DAG: x14 = 0x0e0f101112131415
206CHECK-AARCH64-DAG: x15 = 0x0f10111213141516
207CHECK-AARCH64-DAG: x16 = 0x1011121314151617
208CHECK-AARCH64-DAG: x17 = 0x1112131415161718
209CHECK-AARCH64-DAG: x18 = 0x1213141516171819
210CHECK-AARCH64-DAG: x19 = 0x131415161718191a
211CHECK-AARCH64-DAG: x20 = 0x1415161718191a1b
212CHECK-AARCH64-DAG: x21 = 0x15161718191a1b1c
213CHECK-AARCH64-DAG: x22 = 0x161718191a1b1c1d
214CHECK-AARCH64-DAG: x23 = 0x1718191a1b1c1d1e
215CHECK-AARCH64-DAG: x24 = 0x18191a1b1c1d1e1f
216CHECK-AARCH64-DAG: x25 = 0x191a1b1c1d1e1f20
217CHECK-AARCH64-DAG: x26 = 0x1a1b1c1d1e1f2021
218CHECK-AARCH64-DAG: x27 = 0x1b1c1d1e1f202122
219CHECK-AARCH64-DAG: x28 = 0x1c1d1e1f20212223
220CHECK-AARCH64-DAG: x29 = 0x1d1e1f2021222324
221CHECK-AARCH64-DAG: x30 = 0x1e1f202122232425
222CHECK-AARCH64-DAG: sp = 0x1f20212223242526
223CHECK-AARCH64-DAG: pc = 0x2021222324252627
224CHECK-AARCH64-DAG: cpsr = 0x21222324
225"""
226
227        SUPPL = """
228CHECK-AARCH64-DAG: w0 = 0x04050607
229CHECK-AARCH64-DAG: w1 = 0x05060708
230CHECK-AARCH64-DAG: w2 = 0x06070809
231CHECK-AARCH64-DAG: w3 = 0x0708090a
232CHECK-AARCH64-DAG: w4 = 0x08090a0b
233CHECK-AARCH64-DAG: w5 = 0x090a0b0c
234CHECK-AARCH64-DAG: w6 = 0x0a0b0c0d
235CHECK-AARCH64-DAG: w7 = 0x0b0c0d0e
236CHECK-AARCH64-DAG: w8 = 0x0c0d0e0f
237CHECK-AARCH64-DAG: w9 = 0x0d0e0f10
238CHECK-AARCH64-DAG: w10 = 0x0e0f1011
239CHECK-AARCH64-DAG: w11 = 0x0f101112
240CHECK-AARCH64-DAG: w12 = 0x10111213
241CHECK-AARCH64-DAG: w13 = 0x11121314
242CHECK-AARCH64-DAG: w14 = 0x12131415
243CHECK-AARCH64-DAG: w15 = 0x13141516
244CHECK-AARCH64-DAG: w16 = 0x14151617
245CHECK-AARCH64-DAG: w17 = 0x15161718
246CHECK-AARCH64-DAG: w18 = 0x16171819
247CHECK-AARCH64-DAG: w19 = 0x1718191a
248CHECK-AARCH64-DAG: w20 = 0x18191a1b
249CHECK-AARCH64-DAG: w21 = 0x191a1b1c
250CHECK-AARCH64-DAG: w22 = 0x1a1b1c1d
251CHECK-AARCH64-DAG: w23 = 0x1b1c1d1e
252CHECK-AARCH64-DAG: w24 = 0x1c1d1e1f
253CHECK-AARCH64-DAG: w25 = 0x1d1e1f20
254CHECK-AARCH64-DAG: w26 = 0x1e1f2021
255CHECK-AARCH64-DAG: w27 = 0x1f202122
256CHECK-AARCH64-DAG: w28 = 0x20212223
257CHECK-AARCH64-DAG: w29 = 0x21222324
258CHECK-AARCH64-DAG: w30 = 0x22232425
259CHECK-AARCH64-DAG: w31 = 0x23242526
260"""
261
262        self.server.responder = MyResponder(
263            "aarch64",
264            has_target_xml,
265            GPRS,
266            "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;07:0102030405060708;10:1112131415161718;",
267        )
268
269        target = self.createTarget("basic_eh_frame-aarch64.yaml")
270        process = self.connect(target)
271        lldbutil.expect_state_changes(
272            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
273        )
274
275        # test all registers
276        self.filecheck(
277            "register read --all",
278            __file__,
279            filecheck_options="--check-prefix=CHECK-AARCH64",
280        )
281
282        # test generic aliases
283        self.match("register read arg1", ["x0 = 0x0001020304050607"])
284        self.match("register read arg2", ["x1 = 0x0102030405060708"])
285        self.match("register read fp", ["x29 = 0x1d1e1f2021222324"])
286        self.match("register read lr", ["x30 = 0x1e1f202122232425"])
287        self.match("register read ra", ["x30 = 0x1e1f202122232425"])
288        self.match("register read flags", ["cpsr = 0x21222324"])
289
290    @skipIfRemote
291    @skipIfLLVMTargetMissing("AArch64")
292    def test_aarch64_regs_no_target_xml(self):
293        """Test grabbing various aarch64 registers from gdbserver when there
294        is no target XML."""
295        self.check_aarch64_regs(False)
296
297    @skipIfXmlSupportMissing
298    @skipIfRemote
299    @skipIfLLVMTargetMissing("AArch64")
300    def test_aarch64_regs_no_register_info(self):
301        """Test grabbing various aarch64 registers from gdbserver when there
302        is target XML but it does not include register info."""
303        self.check_aarch64_regs(True)
304
305    def check_i386_regs(self, has_target_xml):
306        GPRS = """
307CHECK-I386-DAG: eax = 0x04030201
308CHECK-I386-DAG: ecx = 0x14131211
309CHECK-I386-DAG: edx = 0x24232221
310CHECK-I386-DAG: ebx = 0x34333231
311CHECK-I386-DAG: esp = 0x44434241
312CHECK-I386-DAG: ebp = 0x54535251
313CHECK-I386-DAG: esi = 0x64636261
314CHECK-I386-DAG: edi = 0x74737271
315CHECK-I386-DAG: eip = 0x84838281
316CHECK-I386-DAG: eflags = 0x94939291
317CHECK-I386-DAG: cs = 0xa4a3a2a1
318CHECK-I386-DAG: ss = 0xb4b3b2b1
319CHECK-I386-DAG: ds = 0xc4c3c2c1
320CHECK-I386-DAG: es = 0xd4d3d2d1
321CHECK-I386-DAG: fs = 0xe4e3e2e1
322CHECK-I386-DAG: gs = 0xf4f3f2f1
323"""
324
325        SUPPL = """
326CHECK-I386-DAG: ax = 0x0201
327CHECK-I386-DAG: cx = 0x1211
328CHECK-I386-DAG: dx = 0x2221
329CHECK-I386-DAG: bx = 0x3231
330CHECK-I386-DAG: sp = 0x4241
331CHECK-I386-DAG: bp = 0x5251
332CHECK-I386-DAG: si = 0x6261
333CHECK-I386-DAG: di = 0x7271
334
335CHECK-I386-DAG: ah = 0x02
336CHECK-I386-DAG: ch = 0x12
337CHECK-I386-DAG: dh = 0x22
338CHECK-I386-DAG: bh = 0x32
339
340CHECK-I386-DAG: al = 0x01
341CHECK-I386-DAG: cl = 0x11
342CHECK-I386-DAG: dl = 0x21
343CHECK-I386-DAG: bl = 0x31
344CHECK-I386-DAG: spl = 0x41
345CHECK-I386-DAG: bpl = 0x51
346CHECK-I386-DAG: sil = 0x61
347CHECK-I386-DAG: dil = 0x71
348"""
349
350        self.server.responder = MyResponder(
351            "i386",
352            has_target_xml,
353            GPRS,
354            "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;07:0102030405060708;10:1112131415161718;",
355        )
356
357        target = self.createTarget("basic_eh_frame-i386.yaml")
358        process = self.connect(target)
359        lldbutil.expect_state_changes(
360            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
361        )
362
363        # test all registers
364        self.filecheck(
365            "register read --all",
366            __file__,
367            filecheck_options="--check-prefix=CHECK-I386",
368        )
369
370        # test generic aliases
371        self.match("register read fp", ["ebp = 0x54535251"])
372        self.match("register read sp", ["esp = 0x44434241"])
373        self.match("register read pc", ["eip = 0x84838281"])
374        self.match("register read flags", ["eflags = 0x94939291"])
375
376    @skipIfRemote
377    @skipIfLLVMTargetMissing("X86")
378    def test_i386_regs_no_target_xml(self):
379        """Test grabbing various i386 registers from gdbserver when there is
380        no target XML."""
381        self.check_i386_regs(False)
382
383    @skipIfXmlSupportMissing
384    @skipIfRemote
385    @skipIfLLVMTargetMissing("X86")
386    def test_i386_regs_no_register_info(self):
387        """Test grabbing various i386 registers from gdbserver when there is
388        target XML but it does not include register info."""
389        self.check_i386_regs(True)