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