xref: /llvm-project/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py (revision 911a6f2fcc719c46b5b392823473ba0bb5b1f4e1)
1"""
2Test basics of linux core file debugging.
3"""
4
5import shutil
6import struct
7import os
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14
15class LinuxCoreTestCase(TestBase):
16    NO_DEBUG_INFO_TESTCASE = True
17
18    _aarch64_pid = 37688
19    _aarch64_pac_pid = 387
20    _i386_pid = 32306
21    _x86_64_pid = 32259
22    _s390x_pid = 1045
23    _ppc64le_pid = 28147
24    _riscv64_gpr_fpr_pid = 1089
25    _riscv64_gpr_only_pid = 97
26    _loongarch64_pid = 456735
27
28    _aarch64_regions = 4
29    _i386_regions = 4
30    _x86_64_regions = 5
31    _s390x_regions = 2
32    _ppc64le_regions = 2
33    _riscv64_regions = 4
34    _loongarch64_regions = 4
35
36    @skipIfLLVMTargetMissing("AArch64")
37    def test_aarch64(self):
38        """Test that lldb can read the process information from an aarch64 linux core file."""
39        self.do_test("linux-aarch64", self._aarch64_pid, self._aarch64_regions, "a.out")
40
41    @skipIfLLVMTargetMissing("X86")
42    def test_i386(self):
43        """Test that lldb can read the process information from an i386 linux core file."""
44        self.do_test("linux-i386", self._i386_pid, self._i386_regions, "a.out")
45
46    @skipIfLLVMTargetMissing("PowerPC")
47    def test_ppc64le(self):
48        """Test that lldb can read the process information from an ppc64le linux core file."""
49        self.do_test(
50            "linux-ppc64le",
51            self._ppc64le_pid,
52            self._ppc64le_regions,
53            "linux-ppc64le.ou",
54        )
55
56    @skipIfLLVMTargetMissing("X86")
57    def test_x86_64(self):
58        """Test that lldb can read the process information from an x86_64 linux core file."""
59        self.do_test("linux-x86_64", self._x86_64_pid, self._x86_64_regions, "a.out")
60
61    @skipIfLLVMTargetMissing("SystemZ")
62    def test_s390x(self):
63        """Test that lldb can read the process information from an s390x linux core file."""
64        self.do_test("linux-s390x", self._s390x_pid, self._s390x_regions, "a.out")
65
66    @skipIfLLVMTargetMissing("RISCV")
67    def test_riscv64_gpr_fpr(self):
68        """Test that lldb can read the process information from an riscv64 linux core file."""
69        self.do_test(
70            "linux-riscv64.gpr_fpr",
71            self._riscv64_gpr_fpr_pid,
72            self._riscv64_regions,
73            "a.out",
74        )
75
76    @skipIfLLVMTargetMissing("RISCV")
77    def test_riscv64_gpr_only(self):
78        """Test that lldb can read the process information from an riscv64 linux core file
79        made for a RV64IMAC target, having no FP-registers."""
80        self.do_test(
81            "linux-riscv64.gpr_only",
82            self._riscv64_gpr_only_pid,
83            self._riscv64_regions,
84            "a.out",
85        )
86
87    @skipIfLLVMTargetMissing("LoongArch")
88    def test_loongarch64(self):
89        """Test that lldb can read the process information from an loongarch64 linux core file."""
90        self.do_test(
91            "linux-loongarch64",
92            self._loongarch64_pid,
93            self._loongarch64_regions,
94            "a.out",
95        )
96
97    @skipIfLLVMTargetMissing("X86")
98    def test_same_pid_running(self):
99        """Test that we read the information from the core correctly even if we have a running
100        process with the same PID around"""
101        exe_file = self.getBuildArtifact("linux-x86_64-pid.out")
102        core_file = self.getBuildArtifact("linux-x86_64-pid.core")
103        shutil.copyfile("linux-x86_64.out", exe_file)
104        shutil.copyfile("linux-x86_64.core", core_file)
105        with open(core_file, "r+b") as f:
106            # These are offsets into the NT_PRSTATUS and NT_PRPSINFO structures in the note
107            # segment of the core file. If you update the file, these offsets may need updating
108            # as well. (Notes can be viewed with readelf --notes.)
109            for pid_offset in [0x1C4, 0x320]:
110                f.seek(pid_offset)
111                self.assertEqual(struct.unpack("<I", f.read(4))[0], self._x86_64_pid)
112
113                # We insert our own pid, and make sure the test still
114                # works.
115                f.seek(pid_offset)
116                f.write(struct.pack("<I", os.getpid()))
117        self.do_test(
118            self.getBuildArtifact("linux-x86_64-pid"),
119            os.getpid(),
120            self._x86_64_regions,
121            "a.out",
122        )
123
124    @skipIfLLVMTargetMissing("X86")
125    def test_two_cores_same_pid(self):
126        """Test that we handle the situation if we have two core files with the same PID
127        around"""
128        alttarget = self.dbg.CreateTarget("altmain.out")
129        altprocess = alttarget.LoadCore("altmain.core")
130        self.assertTrue(altprocess, PROCESS_IS_VALID)
131        self.assertEqual(altprocess.GetNumThreads(), 1)
132        self.assertEqual(altprocess.GetProcessID(), self._x86_64_pid)
133
134        altframe = altprocess.GetSelectedThread().GetFrameAtIndex(0)
135        self.assertEqual(altframe.GetFunctionName(), "_start")
136        self.assertEqual(
137            altframe.GetLineEntry().GetLine(), line_number("altmain.c", "Frame _start")
138        )
139
140        error = lldb.SBError()
141        F = altprocess.ReadCStringFromMemory(
142            altframe.FindVariable("F").GetValueAsUnsigned(), 256, error
143        )
144        self.assertSuccess(error)
145        self.assertEqual(F, "_start")
146
147        # without destroying this process, run the test which opens another core file with the
148        # same pid
149        self.do_test("linux-x86_64", self._x86_64_pid, self._x86_64_regions, "a.out")
150
151    @skipIfLLVMTargetMissing("X86")
152    @skipIfWindows
153    def test_read_memory(self):
154        """Test that we are able to read as many bytes as available"""
155        target = self.dbg.CreateTarget("linux-x86_64.out")
156        process = target.LoadCore("linux-x86_64.core")
157        self.assertTrue(process, PROCESS_IS_VALID)
158
159        error = lldb.SBError()
160        bytesread = process.ReadMemory(0x400FF0, 20, error)
161
162        # read only 16 bytes without zero bytes filling
163        self.assertEqual(len(bytesread), 16)
164        self.dbg.DeleteTarget(target)
165
166    @skipIfLLVMTargetMissing("X86")
167    def test_write_register(self):
168        """Test that writing to register results in an error and that error
169        message is set."""
170        target = self.dbg.CreateTarget("linux-x86_64.out")
171        process = target.LoadCore("linux-x86_64.core")
172        self.assertTrue(process, PROCESS_IS_VALID)
173
174        thread = process.GetSelectedThread()
175        self.assertTrue(thread)
176
177        frame = thread.GetSelectedFrame()
178        self.assertTrue(frame)
179
180        reg_value = frame.FindRegister("eax")
181        self.assertTrue(reg_value)
182
183        error = lldb.SBError()
184        success = reg_value.SetValueFromCString("10", error)
185        self.assertFalse(success)
186        self.assertTrue(error.Fail())
187        self.assertIsNotNone(error.GetCString())
188
189    @skipIfLLVMTargetMissing("X86")
190    def test_FPR_SSE(self):
191        # check x86_64 core file
192        target = self.dbg.CreateTarget(None)
193        self.assertTrue(target, VALID_TARGET)
194        process = target.LoadCore("linux-fpr_sse_x86_64.core")
195
196        values = {}
197        values["fctrl"] = "0x037f"
198        values["fstat"] = "0x0000"
199        values["ftag"] = "0x00ff"
200        values["fop"] = "0x0000"
201        values["fiseg"] = "0x00000000"
202        values["fioff"] = "0x0040011e"
203        values["foseg"] = "0x00000000"
204        values["fooff"] = "0x00000000"
205        values["mxcsr"] = "0x00001f80"
206        values["mxcsrmask"] = "0x0000ffff"
207        values["st0"] = "{0x99 0xf7 0xcf 0xfb 0x84 0x9a 0x20 0x9a 0xfd 0x3f}"
208        values["st1"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x3f}"
209        values["st2"] = "{0xfe 0x8a 0x1b 0xcd 0x4b 0x78 0x9a 0xd4 0x00 0x40}"
210        values["st3"] = "{0xac 0x79 0xcf 0xd1 0xf7 0x17 0x72 0xb1 0xfe 0x3f}"
211        values["st4"] = "{0xbc 0xf0 0x17 0x5c 0x29 0x3b 0xaa 0xb8 0xff 0x3f}"
212        values["st5"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x3f}"
213        values["st6"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
214        values["st7"] = "{0x35 0xc2 0x68 0x21 0xa2 0xda 0x0f 0xc9 0x00 0x40}"
215        values[
216            "xmm0"
217        ] = "{0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46}"
218        values[
219            "xmm1"
220        ] = "{0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64}"
221        values[
222            "xmm2"
223        ] = "{0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7}"
224        values[
225            "xmm3"
226        ] = "{0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25}"
227        values[
228            "xmm4"
229        ] = "{0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4}"
230        values[
231            "xmm5"
232        ] = "{0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b}"
233        values[
234            "xmm6"
235        ] = "{0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f}"
236        values[
237            "xmm7"
238        ] = "{0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd}"
239
240        for regname, value in values.items():
241            self.expect(
242                "register read {}".format(regname),
243                substrs=["{} = {}".format(regname, value)],
244            )
245
246        # now check i386 core file
247        target = self.dbg.CreateTarget(None)
248        self.assertTrue(target, VALID_TARGET)
249        process = target.LoadCore("linux-fpr_sse_i386.core")
250
251        values["fioff"] = "0x080480cc"
252
253        for regname, value in values.items():
254            self.expect(
255                "register read {}".format(regname),
256                substrs=["{} = {}".format(regname, value)],
257            )
258
259    @skipIfLLVMTargetMissing("X86")
260    def test_i386_sysroot(self):
261        """Test that lldb can find the exe for an i386 linux core file using the sysroot."""
262
263        # Copy linux-i386.out to tmp_sysroot/home/labath/test/a.out (since it was compiled as
264        # /home/labath/test/a.out)
265        tmp_sysroot = os.path.join(self.getBuildDir(), "lldb_i386_mock_sysroot")
266        executable = os.path.join(tmp_sysroot, "home", "labath", "test", "a.out")
267        lldbutil.mkdir_p(os.path.dirname(executable))
268        shutil.copyfile("linux-i386.out", executable)
269
270        # Set sysroot and load core
271        self.runCmd("platform select remote-linux --sysroot '%s'" % tmp_sysroot)
272        target = self.dbg.CreateTarget(None)
273        self.assertTrue(target, VALID_TARGET)
274        process = target.LoadCore("linux-i386.core")
275
276        # Check that we found a.out from the sysroot
277        self.check_all(process, self._i386_pid, self._i386_regions, "a.out")
278
279        self.dbg.DeleteTarget(target)
280
281    def test_object_map(self):
282        """Test that lldb can find the exe for an i386 linux core file using the object map."""
283
284        # Copy linux-i386.out to lldb_i386_object_map/a.out
285        tmp_object_map_root = os.path.join(self.getBuildDir(), "lldb_i386_object_map")
286        executable = os.path.join(tmp_object_map_root, "a.out")
287        lldbutil.mkdir_p(os.path.dirname(executable))
288        shutil.copyfile("linux-i386.out", executable)
289
290        # Replace the original module path at /home/labath/test and load the core
291        self.runCmd(
292            "settings set target.object-map /home/labath/test {}".format(
293                tmp_object_map_root
294            )
295        )
296
297        target = self.dbg.CreateTarget(None)
298        process = target.LoadCore("linux-i386.core")
299
300        # Check that we did load the mapped executable
301        exe_module_spec = process.GetTarget().GetModuleAtIndex(0).GetFileSpec()
302        self.assertTrue(exe_module_spec.fullpath.startswith(tmp_object_map_root))
303
304        self.check_all(process, self._i386_pid, self._i386_regions, "a.out")
305        self.dbg.DeleteTarget(target)
306
307    @skipIfLLVMTargetMissing("X86")
308    @skipIfWindows
309    def test_x86_64_sysroot(self):
310        """Test that sysroot has more priority then local filesystem."""
311
312        # Copy wrong executable to the location outside of sysroot
313        exe_outside = os.path.join(self.getBuildDir(), "bin", "a.out")
314        lldbutil.mkdir_p(os.path.dirname(exe_outside))
315        shutil.copyfile("altmain.out", exe_outside)
316
317        # Copy correct executable to the location inside sysroot
318        tmp_sysroot = os.path.join(self.getBuildDir(), "mock_sysroot")
319        exe_inside = os.path.join(tmp_sysroot, os.path.relpath(exe_outside, "/"))
320        lldbutil.mkdir_p(os.path.dirname(exe_inside))
321        shutil.copyfile("linux-x86_64.out", exe_inside)
322
323        # Prepare patched core file
324        core_file = os.path.join(self.getBuildDir(), "patched.core")
325        with open("linux-x86_64.core", "rb") as f:
326            core = f.read()
327        core = replace_path(core, "/test" * 817 + "/a.out", exe_outside)
328        with open(core_file, "wb") as f:
329            f.write(core)
330
331        # Set sysroot and load core
332        self.runCmd("platform select remote-linux --sysroot '%s'" % tmp_sysroot)
333        target = self.dbg.CreateTarget(None)
334        self.assertTrue(target, VALID_TARGET)
335        process = target.LoadCore(core_file)
336
337        # Check that we found executable from the sysroot
338        mod_path = str(target.GetModuleAtIndex(0).GetFileSpec())
339        self.assertEqual(mod_path, exe_inside)
340        self.check_all(process, self._x86_64_pid, self._x86_64_regions, "a.out")
341
342        self.dbg.DeleteTarget(target)
343
344    @skipIfLLVMTargetMissing("AArch64")
345    def test_aarch64_pac(self):
346        """Test that lldb can unwind stack for AArch64 elf core file with PAC enabled."""
347
348        target = self.dbg.CreateTarget("linux-aarch64-pac.out")
349        self.assertTrue(target, VALID_TARGET)
350        process = target.LoadCore("linux-aarch64-pac.core")
351
352        self.check_all(process, self._aarch64_pac_pid, self._aarch64_regions, "a.out")
353
354        self.dbg.DeleteTarget(target)
355
356    @skipIfLLVMTargetMissing("AArch64")
357    # This test fails on FreeBSD 12 and earlier, see llvm.org/pr49415 for details.
358    def test_aarch64_regs(self):
359        # check 64 bit ARM core files
360        target = self.dbg.CreateTarget(None)
361        self.assertTrue(target, VALID_TARGET)
362        process = target.LoadCore("linux-aarch64-neon.core")
363
364        values = {}
365        values["x1"] = "0x000000000000002f"
366        values["w1"] = "0x0000002f"
367        values["fp"] = "0x0000ffffdab7c770"
368        values["lr"] = "0x000000000040019c"
369        values["sp"] = "0x0000ffffdab7c750"
370        values["pc"] = "0x0000000000400168"
371        values[
372            "v0"
373        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xe0 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
374        values[
375            "v1"
376        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xf8 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
377        values[
378            "v2"
379        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x04 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
380        values[
381            "v3"
382        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
383        values[
384            "v4"
385        ] = "{0x00 0x00 0x90 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
386        values[
387            "v5"
388        ] = "{0x00 0x00 0xb0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
389        values[
390            "v6"
391        ] = "{0x00 0x00 0xd0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
392        values[
393            "v7"
394        ] = "{0x00 0x00 0xf0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
395        values[
396            "v8"
397        ] = "{0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11}"
398        values[
399            "v27"
400        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
401        values[
402            "v28"
403        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
404        values[
405            "v31"
406        ] = "{0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30}"
407        values["s2"] = "0"
408        values["s3"] = "0"
409        values["s4"] = "4.5"
410        values["s5"] = "5.5"
411        values["s6"] = "6.5"
412        values["s7"] = "7.5"
413        values["s8"] = "1.14437421E-28"
414        values["s30"] = "0"
415        values["s31"] = "6.40969056E-10"
416        values["d0"] = "0.5"
417        values["d1"] = "1.5"
418        values["d2"] = "2.5"
419        values["d3"] = "3.5"
420        values["d4"] = "5.3516153614920076E-315"
421        values["d5"] = "5.3619766690650802E-315"
422        values["d6"] = "5.3723379766381528E-315"
423        values["d7"] = "5.3826992842112254E-315"
424        values["d8"] = "1.8010757365944223E-226"
425        values["d30"] = "0"
426        values["d31"] = "1.3980432860952889E-76"
427        values["fpsr"] = "0x00000000"
428        values["fpcr"] = "0x00000000"
429        values["tpidr"] = "0x1122334455667788"
430
431        for regname, value in values.items():
432            self.expect(
433                "register read {}".format(regname),
434                substrs=["{} = {}".format(regname, value)],
435            )
436
437        self.expect("register read --all")
438
439    @skipIfLLVMTargetMissing("AArch64")
440    # This test fails on FreeBSD 12 and earlier, see llvm.org/pr49415 for details.
441    def test_aarch64_sve_regs_fpsimd(self):
442        # check 64 bit ARM core files
443        target = self.dbg.CreateTarget(None)
444        self.assertTrue(target, VALID_TARGET)
445        process = target.LoadCore("linux-aarch64-sve-fpsimd.core")
446
447        values = {}
448        values["x1"] = "0x000000000000002f"
449        values["w1"] = "0x0000002f"
450        values["fp"] = "0x0000ffffcbad8d50"
451        values["lr"] = "0x0000000000400180"
452        values["sp"] = "0x0000ffffcbad8d30"
453        values["pc"] = "0x000000000040014c"
454        values["cpsr"] = "0x00001000"
455        values[
456            "v0"
457        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xe0 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
458        values[
459            "v1"
460        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xf8 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
461        values[
462            "v2"
463        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x04 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
464        values[
465            "v3"
466        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
467        values[
468            "v4"
469        ] = "{0x00 0x00 0x90 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
470        values[
471            "v5"
472        ] = "{0x00 0x00 0xb0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
473        values[
474            "v6"
475        ] = "{0x00 0x00 0xd0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
476        values[
477            "v7"
478        ] = "{0x00 0x00 0xf0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
479        values[
480            "v8"
481        ] = "{0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11}"
482        values[
483            "v27"
484        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
485        values[
486            "v28"
487        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
488        values[
489            "v31"
490        ] = "{0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30}"
491        values["s2"] = "0"
492        values["s3"] = "0"
493        values["s4"] = "4.5"
494        values["s5"] = "5.5"
495        values["s6"] = "6.5"
496        values["s7"] = "7.5"
497        values["s8"] = "1.14437421E-28"
498        values["s30"] = "0"
499        values["s31"] = "6.40969056E-10"
500        values["d0"] = "0.5"
501        values["d1"] = "1.5"
502        values["d2"] = "2.5"
503        values["d3"] = "3.5"
504        values["d4"] = "5.3516153614920076E-315"
505        values["d5"] = "5.3619766690650802E-315"
506        values["d6"] = "5.3723379766381528E-315"
507        values["d7"] = "5.3826992842112254E-315"
508        values["d8"] = "1.8010757365944223E-226"
509        values["d30"] = "0"
510        values["d31"] = "1.3980432860952889E-76"
511        values["fpsr"] = "0x00000000"
512        values["fpcr"] = "0x00000000"
513        values["vg"] = "0x0000000000000004"
514        values[
515            "z0"
516        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xe0 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
517        values[
518            "z1"
519        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0xf8 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
520        values[
521            "z2"
522        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x04 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
523        values[
524            "z3"
525        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x0c 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
526        values[
527            "z4"
528        ] = "{0x00 0x00 0x90 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
529        values[
530            "z5"
531        ] = "{0x00 0x00 0xb0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
532        values[
533            "z6"
534        ] = "{0x00 0x00 0xd0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
535        values[
536            "z7"
537        ] = "{0x00 0x00 0xf0 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
538        values[
539            "z8"
540        ] = "{0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
541        values[
542            "z27"
543        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
544        values[
545            "z28"
546        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
547        values[
548            "z31"
549        ] = "{0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
550        values["p0"] = "{0x00 0x00 0x00 0x00}"
551        values["p1"] = "{0x00 0x00 0x00 0x00}"
552        values["p2"] = "{0x00 0x00 0x00 0x00}"
553        values["p4"] = "{0x00 0x00 0x00 0x00}"
554        values["p3"] = "{0x00 0x00 0x00 0x00}"
555        values["p6"] = "{0x00 0x00 0x00 0x00}"
556        values["p5"] = "{0x00 0x00 0x00 0x00}"
557        values["p7"] = "{0x00 0x00 0x00 0x00}"
558        values["p8"] = "{0x00 0x00 0x00 0x00}"
559        values["p9"] = "{0x00 0x00 0x00 0x00}"
560        values["p11"] = "{0x00 0x00 0x00 0x00}"
561        values["p10"] = "{0x00 0x00 0x00 0x00}"
562        values["p12"] = "{0x00 0x00 0x00 0x00}"
563        values["p13"] = "{0x00 0x00 0x00 0x00}"
564        values["p14"] = "{0x00 0x00 0x00 0x00}"
565        values["p15"] = "{0x00 0x00 0x00 0x00}"
566        values["ffr"] = "{0x00 0x00 0x00 0x00}"
567
568        for regname, value in values.items():
569            self.expect(
570                "register read {}".format(regname),
571                substrs=["{} = {}".format(regname, value)],
572            )
573
574        self.expect("register read --all")
575
576    @skipIfLLVMTargetMissing("AArch64")
577    def test_aarch64_sve_regs_full(self):
578        # check 64 bit ARM core files
579        target = self.dbg.CreateTarget(None)
580        self.assertTrue(target, VALID_TARGET)
581        process = target.LoadCore("linux-aarch64-sve-full.core")
582
583        values = {}
584        values["fp"] = "0x0000fffffc1ff4f0"
585        values["lr"] = "0x0000000000400170"
586        values["sp"] = "0x0000fffffc1ff4d0"
587        values["pc"] = "0x000000000040013c"
588        values[
589            "v0"
590        ] = "{0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40}"
591        values[
592            "v1"
593        ] = "{0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41}"
594        values[
595            "v2"
596        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
597        values[
598            "v3"
599        ] = "{0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41}"
600        values["s0"] = "7.5"
601        values["s1"] = "11.5"
602        values["s2"] = "0"
603        values["s3"] = "15.5"
604        values["d0"] = "65536.0158538818"
605        values["d1"] = "1572864.25476074"
606        values["d2"] = "0"
607        values["d3"] = "25165828.091796875"
608        values["vg"] = "0x0000000000000004"
609        values[
610            "z0"
611        ] = "{0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40 0x00 0x00 0xf0 0x40}"
612        values[
613            "z1"
614        ] = "{0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41 0x00 0x00 0x38 0x41}"
615        values[
616            "z2"
617        ] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
618        values[
619            "z3"
620        ] = "{0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41 0x00 0x00 0x78 0x41}"
621        values["p0"] = "{0x11 0x11 0x11 0x11}"
622        values["p1"] = "{0x11 0x11 0x11 0x11}"
623        values["p2"] = "{0x00 0x00 0x00 0x00}"
624        values["p3"] = "{0x11 0x11 0x11 0x11}"
625        values["p4"] = "{0x00 0x00 0x00 0x00}"
626
627        for regname, value in values.items():
628            self.expect(
629                "register read {}".format(regname),
630                substrs=["{} = {}".format(regname, value)],
631            )
632
633        self.expect("register read --all")
634
635        # Register field information should work with core files as it does a live process.
636        # The N/Z/C/V bits are always present so just check for those.
637        self.expect("register read cpsr", substrs=["= (N = 0, Z = 0, C = 0, V = 0"])
638        self.expect("register read fpsr", substrs=["= (QC = 0, IDC = 0, IXC = 0"])
639        # AHP/DN/FZ/RMode always present, others may vary.
640        self.expect(
641            "register read fpcr", substrs=["= (AHP = 0, DN = 0, FZ = 0, RMode = RN"]
642        )
643        # RMode should have enumerator descriptions.
644        self.expect(
645            "register info fpcr",
646            substrs=["RMode: 0 = RN, 1 = RP, 2 = RM, 3 = RZ"],
647        )
648
649    @skipIfLLVMTargetMissing("AArch64")
650    def test_aarch64_pac_regs(self):
651        # Test AArch64/Linux Pointer Authentication register read
652        target = self.dbg.CreateTarget(None)
653        self.assertTrue(target, VALID_TARGET)
654        process = target.LoadCore("linux-aarch64-pac.core")
655
656        values = {"data_mask": "0x007f00000000000", "code_mask": "0x007f00000000000"}
657
658        for regname, value in values.items():
659            self.expect(
660                "register read {}".format(regname),
661                substrs=["{} = {}".format(regname, value)],
662            )
663
664        self.expect("register read --all")
665
666    @skipIfLLVMTargetMissing("ARM")
667    def test_arm_core(self):
668        # check 32 bit ARM core file
669        target = self.dbg.CreateTarget(None)
670        self.assertTrue(target, VALID_TARGET)
671        process = target.LoadCore("linux-arm.core")
672
673        values = {}
674        values["r0"] = "0x00000000"
675        values["r1"] = "0x00000001"
676        values["r2"] = "0x00000002"
677        values["r3"] = "0x00000003"
678        values["r4"] = "0x00000004"
679        values["r5"] = "0x00000005"
680        values["r6"] = "0x00000006"
681        values["r7"] = "0x00000007"
682        values["r8"] = "0x00000008"
683        values["r9"] = "0x00000009"
684        values["r10"] = "0x0000000a"
685        values["r11"] = "0x0000000b"
686        values["r12"] = "0x0000000c"
687        values["sp"] = "0x0000000d"
688        values["lr"] = "0x0000000e"
689        values["pc"] = "0x0000000f"
690        values["cpsr"] = "0x00000010"
691        for regname, value in values.items():
692            self.expect(
693                "register read {}".format(regname),
694                substrs=["{} = {}".format(regname, value)],
695            )
696
697        self.expect("register read --all")
698
699    @skipIfLLVMTargetMissing("RISCV")
700    def test_riscv64_regs_gpr_fpr(self):
701        # check basic registers using 64 bit RISC-V core file
702        target = self.dbg.CreateTarget(None)
703        self.assertTrue(target, VALID_TARGET)
704        process = target.LoadCore("linux-riscv64.gpr_fpr.core")
705
706        values = {}
707        values["pc"] = "0x000000000001016e"
708        values["ra"] = "0x00000000000101a4"
709        values["sp"] = "0x0000003fffc1d2d0"
710        values["gp"] = "0x0000002ae6eccf50"
711        values["tp"] = "0x0000003ff3cb5400"
712        values["t0"] = "0x7f7f7f7fffffffff"
713        values["t1"] = "0x0000002ae6eb9b1c"
714        values["t2"] = "0xffffffffffffffff"
715        values["fp"] = "0x0000003fffc1d300"
716        values["s1"] = "0x0000002ae6eced98"
717        values["a0"] = "0x0"
718        values["a1"] = "0x0000000000010144"
719        values["a2"] = "0x0000002ae6ecedb0"
720        values["a3"] = "0xafdbdbff81cf7f81"
721        values["a4"] = "0x00000000000101e4"
722        values["a5"] = "0x0"
723        values["a6"] = "0x2f5b5a40014e0001"
724        values["a7"] = "0x00000000000000dd"
725        values["s2"] = "0x0000002ae6ec8860"
726        values["s3"] = "0x0000002ae6ecedb0"
727        values["s4"] = "0x0000003fff886c18"
728        values["s5"] = "0x0000002ae6eceb78"
729        values["s6"] = "0x0000002ae6ec8860"
730        values["s7"] = "0x0000002ae6ec8860"
731        values["s8"] = "0x0"
732        values["s9"] = "0x000000000000000f"
733        values["s10"] = "0x0000002ae6ecc8d0"
734        values["s11"] = "0x0000000000000008"
735        values["t3"] = "0x0000003ff3be3728"
736        values["t4"] = "0x0"
737        values["t5"] = "0x0000000000000002"
738        values["t6"] = "0x0000002ae6ed08b9"
739        values["zero"] = "0x0"
740        values["fa5"] = "0xffffffff423c0000"
741        values["fcsr"] = "0x00000000"
742
743        fpr_names = {
744            "ft0",
745            "ft1",
746            "ft2",
747            "ft3",
748            "ft4",
749            "ft5",
750            "ft6",
751            "ft7",
752            "ft8",
753            "ft9",
754            "ft10",
755            "ft11",
756            "fa0",
757            "fa1",
758            "fa2",
759            "fa3",
760            "fa4",
761            # fa5 is non-zero and checked in the list above.
762            "fa6",
763            "fa7",
764            "fs0",
765            "fs1",
766            "fs2",
767            "fs3",
768            "fs4",
769            "fs5",
770            "fs6",
771            "fs7",
772            "fs8",
773            "fs9",
774            "fs10",
775            "fs11",
776        }
777        fpr_value = "0x0000000000000000"
778
779        for regname, value in values.items():
780            self.expect(
781                "register read {}".format(regname),
782                substrs=["{} = {}".format(regname, value)],
783            )
784
785        for regname in fpr_names:
786            self.expect(
787                "register read {}".format(regname),
788                substrs=["{} = {}".format(regname, fpr_value)],
789            )
790
791        self.expect("register read --all")
792
793    @skipIfLLVMTargetMissing("RISCV")
794    def test_riscv64_regs_gpr_only(self):
795        # check registers using 64 bit RISC-V core file containing GP-registers only
796        target = self.dbg.CreateTarget(None)
797        self.assertTrue(target, VALID_TARGET)
798        process = target.LoadCore("linux-riscv64.gpr_only.core")
799
800        values = {}
801        values["pc"] = "0x0000000000010164"
802        values["ra"] = "0x0000000000010194"
803        values["sp"] = "0x00fffffff4d5fcc0"
804        values["gp"] = "0x0000000000157678"
805        values["tp"] = "0x00ffffff99c43400"
806        values["t0"] = "0x00ffffff99c6b260"
807        values["t1"] = "0x00ffffff99b7bd54"
808        values["t2"] = "0x0000000003f0b27f"
809        values["fp"] = "0x00fffffff4d5fcf0"
810        values["s1"] = "0x0000000000000003"
811        values["a0"] = "0x0"
812        values["a1"] = "0x0000000000010144"
813        values["a2"] = "0x0000000000176460"
814        values["a3"] = "0x000000000015ee38"
815        values["a4"] = "0x00000000423c0000"
816        values["a5"] = "0x0"
817        values["a6"] = "0x0"
818        values["a7"] = "0x00000000000000dd"
819        values["s2"] = "0x0"
820        values["s3"] = "0x000000000014ddf8"
821        values["s4"] = "0x000000000003651c"
822        values["s5"] = "0x00fffffffccd8d28"
823        values["s6"] = "0x000000000014ddf8"
824        values["s7"] = "0x00ffffff99c69d48"
825        values["s8"] = "0x00ffffff99c6a008"
826        values["s9"] = "0x0"
827        values["s10"] = "0x0"
828        values["s11"] = "0x0"
829        values["t3"] = "0x00ffffff99c42000"
830        values["t4"] = "0x00ffffff99af8e20"
831        values["t5"] = "0x0000000000000005"
832        values["t6"] = "0x44760bdd8d5f6381"
833        values["zero"] = "0x0"
834
835        for regname, value in values.items():
836            self.expect(
837                "register read {}".format(regname),
838                substrs=["{} = {}".format(regname, value)],
839            )
840
841        # Check that LLDB does not try to read other registers from core file
842        self.expect(
843            "register read --all",
844            matching=False,
845            substrs=["registers were unavailable"],
846        )
847
848    @skipIfLLVMTargetMissing("LoongArch")
849    def test_loongarch64_regs(self):
850        # check registers using 64 bit LoongArch core file containing GP and FP registers
851        target = self.dbg.CreateTarget(None)
852        self.assertTrue(target, VALID_TARGET)
853        process = target.LoadCore("linux-loongarch64.core")
854
855        values = {}
856        values["r0"] = "0x0000000000000000"
857        values["r1"] = "0x000000012000016c"
858        values["r2"] = "0x0000000000000000"
859        values["r3"] = "0x00007ffffb8249e0"
860        values["r4"] = "0x0000000000000000"
861        values["r5"] = "0x000000012000010c"
862        values["r6"] = "0x0000000000000000"
863        values["r7"] = "0x0000000000000000"
864        values["r8"] = "0x0000000000000000"
865        values["r9"] = "0x0000000000000000"
866        values["r10"] = "0x0000000000000000"
867        values["r11"] = "0x00000000000000dd"
868        values["r12"] = "0x0000000000000000"
869        values["r13"] = "0x000000000000002f"
870        values["r14"] = "0x0000000000000000"
871        values["r15"] = "0x0000000000000000"
872        values["r16"] = "0x0000000000000000"
873        values["r17"] = "0x0000000000000000"
874        values["r18"] = "0x0000000000000000"
875        values["r19"] = "0x0000000000000000"
876        values["r20"] = "0x0000000000000000"
877        values["r21"] = "0x0000000000000000"
878        values["r22"] = "0x00007ffffb824a10"
879        values["r23"] = "0x0000000000000000"
880        values["r24"] = "0x0000000000000000"
881        values["r25"] = "0x0000000000000000"
882        values["r26"] = "0x0000000000000000"
883        values["r27"] = "0x0000000000000000"
884        values["r28"] = "0x0000000000000000"
885        values["r29"] = "0x0000000000000000"
886        values["r30"] = "0x0000000000000000"
887        values["r31"] = "0x0000000000000000"
888        values["orig_a0"] = "0x0000555556b62d50"
889        values["pc"] = "0x000000012000012c"
890
891        fpr_values = {}
892        fpr_values["f0"] = "0x00000000ffffff05"
893        fpr_values["f1"] = "0x2525252525252525"
894        fpr_values["f2"] = "0x2525252525560005"
895        fpr_values["f3"] = "0x000000000000ffff"
896        fpr_values["f4"] = "0x0000000000000000"
897        fpr_values["f5"] = "0x0000000000000008"
898        fpr_values["f6"] = "0x0f0e0d0c0b0a0908"
899        fpr_values["f7"] = "0xffffffffffffffff"
900        fpr_values["f8"] = "0x6261747563657845"
901        fpr_values["f9"] = "0x766173206562206c"
902        fpr_values["f10"] = "0xffffffffffffffff"
903        fpr_values["f11"] = "0xffffffffffffffff"
904        fpr_values["f12"] = "0xffffffffffffffff"
905        fpr_values["f13"] = "0xffffffffffffffff"
906        fpr_values["f14"] = "0xffffffffffffffff"
907        fpr_values["f15"] = "0xffffffffffffffff"
908        fpr_values["f16"] = "0xffffffffffffffff"
909        fpr_values["f17"] = "0xffffffffffffffff"
910        fpr_values["f18"] = "0xffffffffffffffff"
911        fpr_values["f19"] = "0xffffffffffffffff"
912        fpr_values["f20"] = "0xffffffffffffffff"
913        fpr_values["f21"] = "0xffffffffffffffff"
914        fpr_values["f22"] = "0xffffffffffffffff"
915        fpr_values["f23"] = "0xffffffffffffffff"
916        fpr_values["f24"] = "0xffffffffffffffff"
917        fpr_values["f25"] = "0xffffffffffffffff"
918        fpr_values["f26"] = "0xffffffffffffffff"
919        fpr_values["f27"] = "0xffffffffffffffff"
920        fpr_values["f28"] = "0xffffffffffffffff"
921        fpr_values["f29"] = "0xffffffffffffffff"
922        fpr_values["f30"] = "0xffffffffffffffff"
923        fpr_values["f31"] = "0xffffffffffffffff"
924        fpr_values["fcc0"] = "0x01"
925        fpr_values["fcc1"] = "0x00"
926        fpr_values["fcc2"] = "0x01"
927        fpr_values["fcc3"] = "0x01"
928        fpr_values["fcc4"] = "0x01"
929        fpr_values["fcc5"] = "0x01"
930        fpr_values["fcc6"] = "0x00"
931        fpr_values["fcc7"] = "0x01"
932        fpr_values["fcsr"] = "0x00000000"
933
934        for regname, value in values.items():
935            self.expect(
936                "register read {}".format(regname),
937                substrs=["{} = {}".format(regname, value)],
938            )
939
940        for regname, value in fpr_values.items():
941            self.expect(
942                "register read {}".format(regname),
943                substrs=["{} = {}".format(regname, value)],
944            )
945
946        self.expect("register read --all")
947
948    def test_get_core_file_api(self):
949        """
950        Test SBProcess::GetCoreFile() API can successfully get the core file.
951        """
952        core_file_name = "linux-x86_64.core"
953        target = self.dbg.CreateTarget("linux-x86_64.out")
954        process = target.LoadCore(core_file_name)
955        self.assertTrue(process, PROCESS_IS_VALID)
956        self.assertEqual(process.GetCoreFile().GetFilename(), core_file_name)
957        self.dbg.DeleteTarget(target)
958
959    def check_memory_regions(self, process, region_count):
960        region_list = process.GetMemoryRegions()
961        self.assertEqual(region_list.GetSize(), region_count)
962
963        region = lldb.SBMemoryRegionInfo()
964
965        # Check we have the right number of regions.
966        self.assertEqual(region_list.GetSize(), region_count)
967
968        # Check that getting a region beyond the last in the list fails.
969        self.assertFalse(region_list.GetMemoryRegionAtIndex(region_count, region))
970
971        # Check each region is valid.
972        for i in range(region_list.GetSize()):
973            # Check we can actually get this region.
974            self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region))
975
976            # Every region in the list should be mapped.
977            self.assertTrue(region.IsMapped())
978
979            # Test the address at the start of a region returns it's enclosing
980            # region.
981            begin_address = region.GetRegionBase()
982            region_at_begin = lldb.SBMemoryRegionInfo()
983            error = process.GetMemoryRegionInfo(begin_address, region_at_begin)
984            self.assertEqual(region, region_at_begin)
985
986            # Test an address in the middle of a region returns it's enclosing
987            # region.
988            middle_address = (region.GetRegionBase() + region.GetRegionEnd()) // 2
989            region_at_middle = lldb.SBMemoryRegionInfo()
990            error = process.GetMemoryRegionInfo(middle_address, region_at_middle)
991            self.assertEqual(region, region_at_middle)
992
993            # Test the address at the end of a region returns it's enclosing
994            # region.
995            end_address = region.GetRegionEnd() - 1
996            region_at_end = lldb.SBMemoryRegionInfo()
997            error = process.GetMemoryRegionInfo(end_address, region_at_end)
998            self.assertEqual(region, region_at_end)
999
1000            # Check that quering the end address does not return this region but
1001            # the next one.
1002            next_region = lldb.SBMemoryRegionInfo()
1003            error = process.GetMemoryRegionInfo(region.GetRegionEnd(), next_region)
1004            self.assertNotEqual(region, next_region)
1005            self.assertEqual(region.GetRegionEnd(), next_region.GetRegionBase())
1006
1007        # Check that query beyond the last region returns an unmapped region
1008        # that ends at LLDB_INVALID_ADDRESS
1009        last_region = lldb.SBMemoryRegionInfo()
1010        region_list.GetMemoryRegionAtIndex(region_count - 1, last_region)
1011        end_region = lldb.SBMemoryRegionInfo()
1012        error = process.GetMemoryRegionInfo(last_region.GetRegionEnd(), end_region)
1013        self.assertFalse(end_region.IsMapped())
1014        self.assertEqual(last_region.GetRegionEnd(), end_region.GetRegionBase())
1015        self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
1016
1017    def check_state(self, process):
1018        with open(os.devnull) as devnul:
1019            # sanitize test output
1020            self.dbg.SetOutputFileHandle(devnul, False)
1021            self.dbg.SetErrorFileHandle(devnul, False)
1022
1023            self.assertTrue(process.is_stopped)
1024
1025            # Process.Continue
1026            error = process.Continue()
1027            self.assertFalse(error.Success())
1028            self.assertTrue(process.is_stopped)
1029
1030            # Thread.StepOut
1031            thread = process.GetSelectedThread()
1032            thread.StepOut()
1033            self.assertTrue(process.is_stopped)
1034
1035            # command line
1036            self.dbg.HandleCommand("s")
1037            self.assertTrue(process.is_stopped)
1038            self.dbg.HandleCommand("c")
1039            self.assertTrue(process.is_stopped)
1040
1041            # restore file handles
1042            self.dbg.SetOutputFileHandle(None, False)
1043            self.dbg.SetErrorFileHandle(None, False)
1044
1045    def check_stack(self, process, pid, thread_name):
1046        thread = process.GetSelectedThread()
1047        self.assertTrue(thread)
1048        self.assertEqual(thread.GetThreadID(), pid)
1049        self.assertEqual(thread.GetName(), thread_name)
1050        backtrace = ["bar", "foo", "_start"]
1051        self.assertEqual(thread.GetNumFrames(), len(backtrace))
1052        for i in range(len(backtrace)):
1053            frame = thread.GetFrameAtIndex(i)
1054            self.assertTrue(frame)
1055            self.assertEqual(frame.GetFunctionName(), backtrace[i])
1056            self.assertEqual(
1057                frame.GetLineEntry().GetLine(),
1058                line_number("main.c", "Frame " + backtrace[i]),
1059            )
1060            self.assertEqual(
1061                frame.FindVariable("F").GetValueAsUnsigned(), ord(backtrace[i][0])
1062            )
1063
1064    def check_all(self, process, pid, region_count, thread_name):
1065        self.assertTrue(process, PROCESS_IS_VALID)
1066        self.assertEqual(process.GetNumThreads(), 1)
1067        self.assertEqual(process.GetProcessID(), pid)
1068
1069        self.check_state(process)
1070
1071        self.check_stack(process, pid, thread_name)
1072
1073        self.check_memory_regions(process, region_count)
1074
1075    def do_test(self, filename, pid, region_count, thread_name):
1076        target = self.dbg.CreateTarget(filename + ".out")
1077        process = target.LoadCore(filename + ".core")
1078
1079        self.check_all(process, pid, region_count, thread_name)
1080
1081        self.dbg.DeleteTarget(target)
1082
1083
1084def replace_path(binary, replace_from, replace_to):
1085    src = replace_from.encode()
1086    dst = replace_to.encode()
1087    dst += b"\0" * (len(src) - len(dst))
1088    return binary.replace(src, dst)
1089