1"""
2Test NetBSD core file debugging.
3"""
4
5from __future__ import division, print_function
6
7import signal
8import os
9
10import lldb
11from lldbsuite.test.decorators import *
12from lldbsuite.test.lldbtest import *
13from lldbsuite.test import lldbutil
14
15
16class NetBSDCoreCommonTestCase(TestBase):
17    NO_DEBUG_INFO_TESTCASE = True
18
19    mydir = TestBase.compute_mydir(__file__)
20
21    def check_memory_regions(self, process, region_count):
22        region_list = process.GetMemoryRegions()
23        self.assertEqual(region_list.GetSize(), region_count)
24
25        region = lldb.SBMemoryRegionInfo()
26
27        # Check we have the right number of regions.
28        self.assertEqual(region_list.GetSize(), region_count)
29
30        # Check that getting a region beyond the last in the list fails.
31        self.assertFalse(
32            region_list.GetMemoryRegionAtIndex(
33                region_count, region))
34
35        # Check each region is valid.
36        for i in range(region_list.GetSize()):
37            # Check we can actually get this region.
38            self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region))
39
40            # Every region in the list should be mapped.
41            self.assertTrue(region.IsMapped())
42
43            # Test the address at the start of a region returns it's enclosing
44            # region.
45            begin_address = region.GetRegionBase()
46            region_at_begin = lldb.SBMemoryRegionInfo()
47            error = process.GetMemoryRegionInfo(begin_address, region_at_begin)
48            self.assertEqual(region, region_at_begin)
49
50            # Test an address in the middle of a region returns it's enclosing
51            # region.
52            middle_address = (region.GetRegionBase() +
53                              region.GetRegionEnd()) // 2
54            region_at_middle = lldb.SBMemoryRegionInfo()
55            error = process.GetMemoryRegionInfo(
56                middle_address, region_at_middle)
57            self.assertEqual(region, region_at_middle)
58
59            # Test the address at the end of a region returns it's enclosing
60            # region.
61            end_address = region.GetRegionEnd() - 1
62            region_at_end = lldb.SBMemoryRegionInfo()
63            error = process.GetMemoryRegionInfo(end_address, region_at_end)
64            self.assertEqual(region, region_at_end)
65
66            # Check that quering the end address does not return this region but
67            # the next one.
68            next_region = lldb.SBMemoryRegionInfo()
69            error = process.GetMemoryRegionInfo(
70                region.GetRegionEnd(), next_region)
71            self.assertNotEqual(region, next_region)
72            self.assertEqual(
73                region.GetRegionEnd(),
74                next_region.GetRegionBase())
75
76        # Check that query beyond the last region returns an unmapped region
77        # that ends at LLDB_INVALID_ADDRESS
78        last_region = lldb.SBMemoryRegionInfo()
79        region_list.GetMemoryRegionAtIndex(region_count - 1, last_region)
80        end_region = lldb.SBMemoryRegionInfo()
81        error = process.GetMemoryRegionInfo(
82            last_region.GetRegionEnd(), end_region)
83        self.assertFalse(end_region.IsMapped())
84        self.assertEqual(
85            last_region.GetRegionEnd(),
86            end_region.GetRegionBase())
87        self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
88
89    def check_state(self, process):
90        with open(os.devnull) as devnul:
91            # sanitize test output
92            self.dbg.SetOutputFileHandle(devnul, False)
93            self.dbg.SetErrorFileHandle(devnul, False)
94
95            self.assertTrue(process.is_stopped)
96
97            # Process.Continue
98            error = process.Continue()
99            self.assertFalse(error.Success())
100            self.assertTrue(process.is_stopped)
101
102            # Thread.StepOut
103            thread = process.GetSelectedThread()
104            thread.StepOut()
105            self.assertTrue(process.is_stopped)
106
107            # command line
108            self.dbg.HandleCommand('s')
109            self.assertTrue(process.is_stopped)
110            self.dbg.HandleCommand('c')
111            self.assertTrue(process.is_stopped)
112
113            # restore file handles
114            self.dbg.SetOutputFileHandle(None, False)
115            self.dbg.SetErrorFileHandle(None, False)
116
117    def check_backtrace(self, thread, filename, backtrace):
118        self.assertGreaterEqual(thread.GetNumFrames(), len(backtrace))
119        src = filename.rpartition('.')[0] + '.c'
120        for i in range(len(backtrace)):
121            frame = thread.GetFrameAtIndex(i)
122            self.assertTrue(frame)
123            if not backtrace[i].startswith('_'):
124                self.assertEqual(frame.GetFunctionName(), backtrace[i])
125                self.assertEqual(frame.GetLineEntry().GetLine(),
126                                 line_number(src, "Frame " + backtrace[i]))
127                self.assertEqual(
128                    frame.FindVariable("F").GetValueAsUnsigned(), ord(
129                        backtrace[i][0]))
130
131    def do_test(self, filename, pid, region_count):
132        target = self.dbg.CreateTarget(filename)
133        process = target.LoadCore(filename + ".core")
134
135        self.assertTrue(process, PROCESS_IS_VALID)
136        self.assertEqual(process.GetNumThreads(), self.THREAD_COUNT)
137        self.assertEqual(process.GetProcessID(), pid)
138
139        self.check_state(process)
140
141        self.check_stack(process, pid, filename)
142
143        self.check_memory_regions(process, region_count)
144
145        self.dbg.DeleteTarget(target)
146
147
148class NetBSD1LWPCoreTestCase(NetBSDCoreCommonTestCase):
149    THREAD_COUNT = 1
150
151    def check_stack(self, process, pid, filename):
152        thread = process.GetSelectedThread()
153        self.assertTrue(thread)
154        self.assertEqual(thread.GetThreadID(), 1)
155        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
156        self.assertEqual(thread.GetStopReasonDataCount(), 1)
157        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
158        backtrace = ["bar", "foo", "main"]
159        self.check_backtrace(thread, filename, backtrace)
160
161    @skipIfLLVMTargetMissing("AArch64")
162    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
163    def test_aarch64(self):
164        """Test single-threaded aarch64 core dump."""
165        self.do_test("1lwp_SIGSEGV.aarch64", pid=8339, region_count=32)
166
167    @skipIfLLVMTargetMissing("X86")
168    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
169    def test_amd64(self):
170        """Test single-threaded amd64 core dump."""
171        self.do_test("1lwp_SIGSEGV.amd64", pid=693, region_count=21)
172
173
174class NetBSD2LWPT2CoreTestCase(NetBSDCoreCommonTestCase):
175    THREAD_COUNT = 2
176
177    def check_stack(self, process, pid, filename):
178        thread = process.GetSelectedThread()
179        self.assertTrue(thread)
180        self.assertEqual(thread.GetThreadID(), 2)
181        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
182        self.assertEqual(thread.GetStopReasonDataCount(), 1)
183        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
184        backtrace = ["bar", "foo", "lwp_main"]
185        self.check_backtrace(thread, filename, backtrace)
186
187        # thread 1 should have no signal
188        thread = process.GetThreadByID(1)
189        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
190        self.assertEqual(thread.GetStopReasonDataCount(), 1)
191        self.assertEqual(thread.GetStopReasonDataAtIndex(0), 0)
192
193    @skipIfLLVMTargetMissing("AArch64")
194    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
195    def test_aarch64(self):
196        """Test double-threaded aarch64 core dump where thread 2 is signalled."""
197        self.do_test("2lwp_t2_SIGSEGV.aarch64", pid=14142, region_count=31)
198
199    @skipIfLLVMTargetMissing("X86")
200    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
201    def test_amd64(self):
202        """Test double-threaded amd64 core dump where thread 2 is signalled."""
203        self.do_test("2lwp_t2_SIGSEGV.amd64", pid=622, region_count=24)
204
205
206class NetBSD2LWPProcessSigCoreTestCase(NetBSDCoreCommonTestCase):
207    THREAD_COUNT = 2
208
209    def check_stack(self, process, pid, filename):
210        thread = process.GetSelectedThread()
211        self.assertTrue(thread)
212        self.assertEqual(thread.GetThreadID(), 2)
213        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
214        self.assertEqual(thread.GetStopReasonDataCount(), 1)
215        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
216        backtrace = ["bar", "foo", "lwp_main"]
217        self.check_backtrace(thread, filename, backtrace)
218
219        # thread 1 should have the same signal
220        thread = process.GetThreadByID(1)
221        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
222        self.assertEqual(thread.GetStopReasonDataCount(), 1)
223        self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV)
224
225    @skipIfLLVMTargetMissing("AArch64")
226    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
227    def test_aarch64(self):
228        """Test double-threaded aarch64 core dump where process is signalled."""
229        self.do_test("2lwp_process_SIGSEGV.aarch64", pid=1403, region_count=30)
230
231    @skipIfLLVMTargetMissing("X86")
232    @skipIfReproducer # lldb::FileSP used in typemap cannot be instrumented.
233    def test_amd64(self):
234        """Test double-threaded amd64 core dump where process is signalled."""
235        self.do_test("2lwp_process_SIGSEGV.amd64", pid=665, region_count=24)
236