1"""
2Test saving a mini dump.
3"""
4
5import os
6import lldb
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11
12class ProcessSaveCoreMinidumpTestCase(TestBase):
13    def verify_core_file(
14        self,
15        core_path,
16        expected_pid,
17        expected_modules,
18        expected_threads,
19        stacks_to_sps_map,
20        stacks_to_registers_map,
21    ):
22        # To verify, we'll launch with the mini dump
23        target = self.dbg.CreateTarget(None)
24        process = target.LoadCore(core_path)
25
26        # check if the core is in desired state
27        self.assertTrue(process, PROCESS_IS_VALID)
28        self.assertTrue(process.GetProcessInfo().IsValid())
29        self.assertEqual(process.GetProcessInfo().GetProcessID(), expected_pid)
30        self.assertNotEqual(target.GetTriple().find("linux"), -1)
31        self.assertTrue(target.GetNumModules(), len(expected_modules))
32        self.assertEqual(process.GetNumThreads(), len(expected_threads))
33
34        for module, expected in zip(target.modules, expected_modules):
35            self.assertTrue(module.IsValid())
36            module_file_name = module.GetFileSpec().GetFilename()
37            expected_file_name = expected.GetFileSpec().GetFilename()
38            # skip kernel virtual dynamic shared objects
39            if "vdso" in expected_file_name:
40                continue
41            self.assertEqual(module_file_name, expected_file_name)
42            self.assertEqual(module.GetUUIDString(), expected.GetUUIDString())
43
44        red_zone = process.GetTarget().GetStackRedZoneSize()
45        for thread_idx in range(process.GetNumThreads()):
46            thread = process.GetThreadAtIndex(thread_idx)
47            self.assertTrue(thread.IsValid())
48            thread_id = thread.GetThreadID()
49            self.assertIn(thread_id, expected_threads)
50            frame = thread.GetFrameAtIndex(0)
51            sp_region = lldb.SBMemoryRegionInfo()
52            sp = frame.GetSP()
53            err = process.GetMemoryRegionInfo(sp, sp_region)
54            self.assertTrue(err.Success(), err.GetCString())
55            error = lldb.SBError()
56            # Ensure thread_id is in the saved map
57            self.assertIn(thread_id, stacks_to_sps_map)
58            # Ensure the SP is correct
59            self.assertEqual(stacks_to_sps_map[thread_id], sp)
60            # Try to read at the end of the stack red zone and succeed
61            process.ReadMemory(sp - red_zone, 1, error)
62            self.assertTrue(error.Success(), error.GetCString())
63            # Try to read just past the red zone and fail
64            process.ReadMemory(sp - red_zone - 1, 1, error)
65            self.assertTrue(error.Fail(), "No failure when reading past the red zone")
66            # Verify the registers are the same
67            self.assertIn(thread_id, stacks_to_registers_map)
68            register_val_list = stacks_to_registers_map[thread_id]
69            frame_register_list = frame.GetRegisters()
70            # explicitly verify we collected fs and gs base for x86_64
71            explicit_registers = ["fs_base", "gs_base"]
72            for reg in explicit_registers:
73                register = frame_register_list.GetFirstValueByName(reg)
74                self.assertNotEqual(None, register)
75                self.assertEqual(
76                    register.GetValueAsUnsigned(),
77                    stacks_to_registers_map[thread_id]
78                    .GetFirstValueByName("fs_base")
79                    .GetValueAsUnsigned(),
80                )
81
82            for x in register_val_list:
83                self.assertEqual(
84                    x.GetValueAsUnsigned(),
85                    frame_register_list.GetFirstValueByName(
86                        x.GetName()
87                    ).GetValueAsUnsigned(),
88                )
89
90        self.dbg.DeleteTarget(target)
91
92    @skipUnlessArch("x86_64")
93    @skipUnlessPlatform(["linux"])
94    def test_save_linux_mini_dump(self):
95        """Test that we can save a Linux mini dump."""
96
97        self.build()
98        exe = self.getBuildArtifact("a.out")
99        core_stack = self.getBuildArtifact("core.stack.dmp")
100        core_dirty = self.getBuildArtifact("core.dirty.dmp")
101        core_full = self.getBuildArtifact("core.full.dmp")
102        core_sb_stack = self.getBuildArtifact("core_sb.stack.dmp")
103        core_sb_dirty = self.getBuildArtifact("core_sb.dirty.dmp")
104        core_sb_full = self.getBuildArtifact("core_sb.full.dmp")
105        try:
106            target = self.dbg.CreateTarget(exe)
107            process = target.LaunchSimple(
108                None, None, self.get_process_working_directory()
109            )
110            self.assertState(process.GetState(), lldb.eStateStopped)
111
112            # get neccessary data for the verification phase
113            process_info = process.GetProcessInfo()
114            expected_pid = process_info.GetProcessID() if process_info.IsValid() else -1
115            expected_number_of_modules = target.GetNumModules()
116            expected_modules = target.modules
117            expected_number_of_threads = process.GetNumThreads()
118            expected_threads = []
119            stacks_to_sp_map = {}
120            stacks_to_registers_map = {}
121
122            for thread_idx in range(process.GetNumThreads()):
123                thread = process.GetThreadAtIndex(thread_idx)
124                thread_id = thread.GetThreadID()
125                expected_threads.append(thread_id)
126                stacks_to_sp_map[thread_id] = thread.GetFrameAtIndex(0).GetSP()
127                stacks_to_registers_map[thread_id] = thread.GetFrameAtIndex(
128                    0
129                ).GetRegisters()
130
131            # save core and, kill process and verify corefile existence
132            base_command = "process save-core --plugin-name=minidump "
133            self.runCmd(base_command + " --style=stack '%s'" % (core_stack))
134            self.assertTrue(os.path.isfile(core_stack))
135            self.verify_core_file(
136                core_stack,
137                expected_pid,
138                expected_modules,
139                expected_threads,
140                stacks_to_sp_map,
141                stacks_to_registers_map,
142            )
143
144            self.runCmd(base_command + " --style=modified-memory '%s'" % (core_dirty))
145            self.assertTrue(os.path.isfile(core_dirty))
146            self.verify_core_file(
147                core_dirty,
148                expected_pid,
149                expected_modules,
150                expected_threads,
151                stacks_to_sp_map,
152                stacks_to_registers_map,
153            )
154
155            self.runCmd(base_command + " --style=full '%s'" % (core_full))
156            self.assertTrue(os.path.isfile(core_full))
157            self.verify_core_file(
158                core_full,
159                expected_pid,
160                expected_modules,
161                expected_threads,
162                stacks_to_sp_map,
163                stacks_to_registers_map,
164            )
165
166            options = lldb.SBSaveCoreOptions()
167            core_sb_stack_spec = lldb.SBFileSpec(core_sb_stack)
168            options.SetOutputFile(core_sb_stack_spec)
169            options.SetPluginName("minidump")
170            options.SetStyle(lldb.eSaveCoreStackOnly)
171            # validate saving via SBProcess
172            error = process.SaveCore(options)
173            self.assertTrue(error.Success())
174            self.assertTrue(os.path.isfile(core_sb_stack))
175            self.verify_core_file(
176                core_sb_stack,
177                expected_pid,
178                expected_modules,
179                expected_threads,
180                stacks_to_sp_map,
181                stacks_to_registers_map,
182            )
183
184            options = lldb.SBSaveCoreOptions()
185            core_sb_dirty_spec = lldb.SBFileSpec(core_sb_dirty)
186            options.SetOutputFile(core_sb_dirty_spec)
187            options.SetPluginName("minidump")
188            options.SetStyle(lldb.eSaveCoreDirtyOnly)
189            error = process.SaveCore(options)
190            self.assertTrue(error.Success())
191            self.assertTrue(os.path.isfile(core_sb_dirty))
192            self.verify_core_file(
193                core_sb_dirty,
194                expected_pid,
195                expected_modules,
196                expected_threads,
197                stacks_to_sp_map,
198                stacks_to_registers_map,
199            )
200
201            # Minidump can now save full core files, but they will be huge and
202            # they might cause this test to timeout.
203            options = lldb.SBSaveCoreOptions()
204            core_sb_full_spec = lldb.SBFileSpec(core_sb_full)
205            options.SetOutputFile(core_sb_full_spec)
206            options.SetPluginName("minidump")
207            options.SetStyle(lldb.eSaveCoreFull)
208            error = process.SaveCore(options)
209            self.assertTrue(error.Success())
210            self.assertTrue(os.path.isfile(core_sb_full))
211            self.verify_core_file(
212                core_sb_full,
213                expected_pid,
214                expected_modules,
215                expected_threads,
216                stacks_to_sp_map,
217                stacks_to_registers_map,
218            )
219
220            self.assertSuccess(process.Kill())
221        finally:
222            # Clean up the mini dump file.
223            self.assertTrue(self.dbg.DeleteTarget(target))
224            if os.path.isfile(core_stack):
225                os.unlink(core_stack)
226            if os.path.isfile(core_dirty):
227                os.unlink(core_dirty)
228            if os.path.isfile(core_full):
229                os.unlink(core_full)
230            if os.path.isfile(core_sb_stack):
231                os.unlink(core_sb_stack)
232            if os.path.isfile(core_sb_dirty):
233                os.unlink(core_sb_dirty)
234            if os.path.isfile(core_sb_full):
235                os.unlink(core_sb_full)
236
237    @skipUnlessArch("x86_64")
238    @skipUnlessPlatform(["linux"])
239    def test_save_linux_mini_dump_thread_options(self):
240        """Test that we can save a Linux mini dump
241        with a subset of threads"""
242
243        self.build()
244        exe = self.getBuildArtifact("a.out")
245        thread_subset_dmp = self.getBuildArtifact("core.thread.subset.dmp")
246        try:
247            target = self.dbg.CreateTarget(exe)
248            process = target.LaunchSimple(
249                None, None, self.get_process_working_directory()
250            )
251            self.assertState(process.GetState(), lldb.eStateStopped)
252
253            thread_to_include = process.GetThreadAtIndex(0)
254            options = lldb.SBSaveCoreOptions()
255            thread_subset_spec = lldb.SBFileSpec(thread_subset_dmp)
256            options.AddThread(thread_to_include)
257            options.SetOutputFile(thread_subset_spec)
258            options.SetPluginName("minidump")
259            options.SetStyle(lldb.eSaveCoreStackOnly)
260            error = process.SaveCore(options)
261            self.assertTrue(error.Success())
262
263            core_target = self.dbg.CreateTarget(None)
264            core_process = core_target.LoadCore(thread_subset_dmp)
265
266            self.assertTrue(core_process, PROCESS_IS_VALID)
267            self.assertEqual(core_process.GetNumThreads(), 1)
268            saved_thread = core_process.GetThreadAtIndex(0)
269            expected_thread = process.GetThreadAtIndex(0)
270            self.assertEqual(expected_thread.GetThreadID(), saved_thread.GetThreadID())
271            expected_sp = expected_thread.GetFrameAtIndex(0).GetSP()
272            saved_sp = saved_thread.GetFrameAtIndex(0).GetSP()
273            self.assertEqual(expected_sp, saved_sp)
274            expected_region = lldb.SBMemoryRegionInfo()
275            saved_region = lldb.SBMemoryRegionInfo()
276            error = core_process.GetMemoryRegionInfo(saved_sp, saved_region)
277            self.assertTrue(error.Success(), error.GetCString())
278            error = process.GetMemoryRegionInfo(expected_sp, expected_region)
279            self.assertTrue(error.Success(), error.GetCString())
280            self.assertEqual(
281                expected_region.GetRegionBase(), saved_region.GetRegionBase()
282            )
283            self.assertEqual(
284                expected_region.GetRegionEnd(), saved_region.GetRegionEnd()
285            )
286
287        finally:
288            self.assertTrue(self.dbg.DeleteTarget(target))
289            if os.path.isfile(thread_subset_dmp):
290                os.unlink(thread_subset_dmp)
291
292    @skipUnlessArch("x86_64")
293    @skipUnlessPlatform(["linux"])
294    def test_save_linux_mini_dump_default_options(self):
295        """Test that we can save a Linux mini dump with default SBSaveCoreOptions"""
296
297        self.build()
298        exe = self.getBuildArtifact("a.out")
299        default_value_file = self.getBuildArtifact("core.defaults.dmp")
300        try:
301            target = self.dbg.CreateTarget(exe)
302            process = target.LaunchSimple(
303                None, None, self.get_process_working_directory()
304            )
305            self.assertState(process.GetState(), lldb.eStateStopped)
306
307            process_info = process.GetProcessInfo()
308            expected_pid = process_info.GetProcessID() if process_info.IsValid() else -1
309            expected_modules = target.modules
310            expected_threads = []
311            stacks_to_sp_map = {}
312            expected_pid = process.GetProcessInfo().GetProcessID()
313            stacks_to_registers_map = {}
314
315            for thread_idx in range(process.GetNumThreads()):
316                thread = process.GetThreadAtIndex(thread_idx)
317                thread_id = thread.GetThreadID()
318                expected_threads.append(thread_id)
319                stacks_to_sp_map[thread_id] = thread.GetFrameAtIndex(0).GetSP()
320                stacks_to_registers_map[thread_id] = thread.GetFrameAtIndex(
321                    0
322                ).GetRegisters()
323
324            # This is almost identical to the single thread test case because
325            # minidump defaults to stacks only, so we want to see if the
326            # default options work as expected.
327            options = lldb.SBSaveCoreOptions()
328            default_value_spec = lldb.SBFileSpec(default_value_file)
329            options.SetOutputFile(default_value_spec)
330            options.SetPluginName("minidump")
331            error = process.SaveCore(options)
332            self.assertTrue(error.Success())
333
334            self.verify_core_file(
335                default_value_file,
336                expected_pid,
337                expected_modules,
338                expected_threads,
339                stacks_to_sp_map,
340                stacks_to_registers_map,
341            )
342
343        finally:
344            self.assertTrue(self.dbg.DeleteTarget(target))
345            if os.path.isfile(default_value_file):
346                os.unlink(default_value_file)
347
348    @skipUnlessArch("x86_64")
349    @skipUnlessPlatform(["linux"])
350    def test_save_linux_minidump_one_region(self):
351        """Test that we can save a Linux mini dump with one region in sbsavecore regions"""
352
353        self.build()
354        exe = self.getBuildArtifact("a.out")
355        one_region_file = self.getBuildArtifact("core.one_region.dmp")
356        try:
357            target = self.dbg.CreateTarget(exe)
358            process = target.LaunchSimple(
359                None, None, self.get_process_working_directory()
360            )
361            self.assertState(process.GetState(), lldb.eStateStopped)
362
363            memory_region = lldb.SBMemoryRegionInfo()
364            memory_list = process.GetMemoryRegions()
365            memory_list.GetMemoryRegionAtIndex(0, memory_region)
366
367            # This is almost identical to the single thread test case because
368            # minidump defaults to stacks only, so we want to see if the
369            # default options work as expected.
370            options = lldb.SBSaveCoreOptions()
371            file_spec = lldb.SBFileSpec(one_region_file)
372            options.SetOutputFile(file_spec)
373            options.SetPluginName("minidump")
374            options.AddMemoryRegionToSave(memory_region)
375            options.SetStyle(lldb.eSaveCoreCustomOnly)
376            error = process.SaveCore(options)
377            print(f"Error: {error.GetCString()}")
378            self.assertTrue(error.Success(), error.GetCString())
379
380            core_target = self.dbg.CreateTarget(None)
381            core_proc = core_target.LoadCore(one_region_file)
382            core_memory_list = core_proc.GetMemoryRegions()
383            # Note because the /proc/pid maps are included on linux, we can't
384            # depend on size for validation, so we'll ensure the first region
385            # is present and then assert we fail on the second.
386            core_memory_region = lldb.SBMemoryRegionInfo()
387            core_memory_list.GetMemoryRegionAtIndex(0, core_memory_region)
388            self.assertEqual(
389                core_memory_region.GetRegionBase(), memory_region.GetRegionBase()
390            )
391            self.assertEqual(
392                core_memory_region.GetRegionEnd(), memory_region.GetRegionEnd()
393            )
394
395            region_two = lldb.SBMemoryRegionInfo()
396            core_memory_list.GetMemoryRegionAtIndex(1, region_two)
397            err = lldb.SBError()
398            content = core_proc.ReadMemory(region_two.GetRegionBase(), 1, err)
399            self.assertTrue(err.Fail(), "Should fail to read memory")
400
401        finally:
402            self.assertTrue(self.dbg.DeleteTarget(target))
403            if os.path.isfile(one_region_file):
404                os.unlink(one_region_file)
405
406    @skipUnlessArch("x86_64")
407    @skipUnlessPlatform(["linux"])
408    def test_save_minidump_custom_save_style(self):
409        """Test that verifies a custom and unspecified save style fails for
410        containing no data to save"""
411
412        self.build()
413        exe = self.getBuildArtifact("a.out")
414        custom_file = self.getBuildArtifact("core.custom.dmp")
415        try:
416            target = self.dbg.CreateTarget(exe)
417            process = target.LaunchSimple(
418                None, None, self.get_process_working_directory()
419            )
420            self.assertState(process.GetState(), lldb.eStateStopped)
421
422            options = lldb.SBSaveCoreOptions()
423            options.SetOutputFile(lldb.SBFileSpec(custom_file))
424            options.SetPluginName("minidump")
425            options.SetStyle(lldb.eSaveCoreCustomOnly)
426
427            error = process.SaveCore(options)
428            self.assertTrue(error.Fail())
429            self.assertEqual(
430                error.GetCString(), "no valid address ranges found for core style"
431            )
432
433        finally:
434            self.assertTrue(self.dbg.DeleteTarget(target))
435            if os.path.isfile(custom_file):
436                os.unlink(custom_file)
437
438    def save_core_with_region(self, process, region_index):
439        try:
440            custom_file = self.getBuildArtifact("core.custom.dmp")
441            memory_region = lldb.SBMemoryRegionInfo()
442            memory_list = process.GetMemoryRegions()
443            memory_list.GetMemoryRegionAtIndex(0, memory_region)
444            options = lldb.SBSaveCoreOptions()
445            options.SetOutputFile(lldb.SBFileSpec(custom_file))
446            options.SetPluginName("minidump")
447            options.SetStyle(lldb.eSaveCoreFull)
448
449            error = process.SaveCore(options)
450            self.assertTrue(error.Success())
451            core_target = self.dbg.CreateTarget(None)
452            core_proc = core_target.LoadCore(custom_file)
453            core_memory_list = core_proc.GetMemoryRegions()
454            # proc/pid/ maps are included on linux, so we can't depend on size
455            # for validation, we make a set of all the ranges,
456            # and ensure no duplicates!
457            range_set = set()
458            for x in range(core_memory_list.GetSize()):
459                core_memory_region = lldb.SBMemoryRegionInfo()
460                core_memory_list.GetMemoryRegionAtIndex(x, core_memory_region)
461                mem_tuple = (
462                    core_memory_region.GetRegionBase(),
463                    core_memory_region.GetRegionEnd(),
464                )
465                self.assertTrue(
466                    mem_tuple not in range_set, "Duplicate memory region found"
467                )
468                range_set.add(mem_tuple)
469        finally:
470            if os.path.isfile(custom_file):
471                os.unlink(custom_file)
472
473    @skipUnlessArch("x86_64")
474    @skipUnlessPlatform(["linux"])
475    def test_save_minidump_custom_save_style_duplicated_regions(self):
476        """Test that verifies a custom and unspecified save style fails for
477        containing no data to save"""
478
479        self.build()
480        exe = self.getBuildArtifact("a.out")
481        try:
482            target = self.dbg.CreateTarget(exe)
483            process = target.LaunchSimple(
484                None, None, self.get_process_working_directory()
485            )
486            self.assertState(process.GetState(), lldb.eStateStopped)
487
488            memory_list = process.GetMemoryRegions()
489            # Test that we don't duplicate regions, by duplicating regions
490            # at various indices.
491            self.save_core_with_region(process, 0)
492            self.save_core_with_region(process, len(memory_list) - 1)
493
494        finally:
495            self.assertTrue(self.dbg.DeleteTarget(target))
496
497    @skipUnlessPlatform(["linux"])
498    def minidump_deleted_on_save_failure(self):
499        """Test that verifies the minidump file is deleted after an error"""
500
501        self.build()
502        exe = self.getBuildArtifact("a.out")
503        try:
504            target = self.dbg.CreateTarget(exe)
505            process = target.LaunchSimple(
506                None, None, self.get_process_working_directory()
507            )
508            self.assertState(process.GetState(), lldb.eStateStopped)
509
510            custom_file = self.getBuildArtifact("core.should.be.deleted.custom.dmp")
511            options = lldb.SBSaveCoreOptions()
512            options.SetOutputFile(lldb.SBFileSpec(custom_file))
513            options.SetPluginName("minidump")
514            options.SetStyle(lldb.eSaveCoreCustomOnly)
515            # We set custom only and have no thread list and have no memory.
516            error = process.SaveCore(options)
517            self.assertTrue(error.Fail())
518            self.assertIn(
519                "no valid address ranges found for core style", error.GetCString()
520            )
521            self.assertTrue(not os.path.isfile(custom_file))
522
523        finally:
524            self.assertTrue(self.dbg.DeleteTarget(target))
525
526    @skipUnlessPlatform(["linux"])
527    @skipUnlessArch("x86_64")
528    def minidump_saves_fs_base_region(self):
529        """Test that verifies the minidump file saves region for fs_base"""
530
531        self.build()
532        exe = self.getBuildArtifact("a.out")
533        try:
534            target = self.dbg.CreateTarget(exe)
535            process = target.LaunchSimple(
536                None, None, self.get_process_working_directory()
537            )
538            self.assertState(process.GetState(), lldb.eStateStopped)
539            thread = process.GetThreadAtIndex(0)
540            custom_file = self.getBuildArtifact("core.reg_region.dmp")
541            options = lldb.SBSaveCoreOptions()
542            options.SetOutputFile(lldb.SBFileSpec(custom_file))
543            options.SetPluginName("minidump")
544            options.SetStyle(lldb.eSaveCoreCustomOnly)
545            options.AddThread(thread)
546            error = process.SaveCore(options)
547            self.assertTrue(error.Success())
548
549            registers = thread.GetFrameAtIndex(0).GetRegisters()
550            fs_base = registers.GetFirstValueByName("fs_base").GetValueAsUnsigned()
551            self.assertTrue(fs_base != 0)
552            core_target = self.dbg.CreateTarget(None)
553            core_proc = core_target.LoadCore(one_region_file)
554            core_region_list = core_proc.GetMemoryRegions()
555            live_region_list = process.GetMemoryRegions()
556            live_region = lldb.SBMemoryRegionInfo()
557            live_region_list.GetMemoryRegionForAddress(fs_base, live_region)
558            core_region = lldb.SBMemoryRegionInfo()
559            error = core_region_list.GetMemoryRegionForAddress(fs_base, core_region)
560            self.assertTrue(error.Success())
561            self.assertEqual(live_region, core_region)
562
563        finally:
564            self.assertTrue(self.dbg.DeleteTarget(target))
565            self.assertTrue(self.dbg.DeleteTarget(core_target))
566            if os.path.isfile(custom_file):
567                os.unlink(custom_file)
568
569    def minidump_deterministic_difference(self):
570        """Test that verifies that two minidumps produced are identical."""
571        self.build()
572        exe = self.getBuildArtifact("a.out")
573        try:
574            target = self.dbg.CreateTarget(exe)
575            process = target.LaunchSimple(
576                None, None, self.get_process_working_directory()
577            )
578
579            core_styles = [
580                lldb.eSaveCoreStackOnly,
581                lldb.eSaveCoreDirtyOnly,
582                lldb.eSaveCoreFull,
583            ]
584            for style in core_styles:
585                spec_one = lldb.SBFileSpec(self.getBuildArtifact("core.one.dmp"))
586                spec_two = lldb.SBFileSpec(self.getBuildArtifact("core.two.dmp"))
587                options = lldb.SBSaveCoreOptions()
588                options.SetOutputFile(spec_one)
589                options.SetPluginName("minidump")
590                options.SetStyle(style)
591                error = process.SaveCore(options)
592                self.assertTrue(error.Success())
593                options.SetOutputFile(spec_two)
594                error = process.SaveCore(options)
595                self.assertTrue(error.Success())
596
597                file_one = None
598                file_two = None
599                with open(spec_one.GetFileName(), mode="rb") as file:
600                    file_one = file.read()
601                with open(spec_two.GetFileName(), mode="rb") as file:
602                    file_two = file.read()
603                self.assertEqual(file_one, file_two)
604                self.assertTrue(os.unlink(spec_one.GetFileName()))
605                self.assertTrue(os.unlink(spec_two.GetFileName()))
606        finally:
607            self.assertTrue(self.dbg.DeleteTarget(target))
608
609    @skipUnlessPlatform(["linux"])
610    @skipUnlessArch("x86_64")
611    def minidump_saves_fs_base_region(self):
612        self.build()
613        exe = self.getBuildArtifact("a.out")
614        try:
615            target = self.dbg.CreateTarget(exe)
616            process = target.LaunchSimple(
617                None, None, self.get_process_working_directory()
618            )
619            self.assertState(process.GetState(), lldb.eStateStopped)
620            thread = process.GetThreadAtIndex(0)
621            tls_file = self.getBuildArtifact("core.tls.dmp")
622            options = lldb.SBSaveCoreOptions()
623            options.SetOutputFile(lldb.SBFileSpec(tls_file))
624            options.SetPluginName("minidump")
625            options.SetStyle(lldb.eSaveCoreCustomOnly)
626            options.AddThread(thread)
627            error = process.SaveCore(options)
628            self.assertTrue(error.Success())
629            core_target = self.dbg.CreateTarget(None)
630            core_proc = core_target.LoadCore(tls_file)
631            frame = core_proc.GetThreadAtIndex(0).GetFrameAtIndex(0)
632            tls_val = frame.FindValue("lf")
633            self.assertEqual(tls_val.GetValueAsUnsigned(), 42)
634
635        except:
636            self.assertTrue(self.dbg.DeleteTarget(target))
637            if os.path.isfile(tls_file):
638                os.unlink(tls_file)
639