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