From c12f159788dcc791e4a415352031fb761f31c3ec Mon Sep 17 00:00:00 2001 From: Michal Gorny Date: Fri, 8 Mar 2019 21:10:43 +0000 Subject: [lldb] [Process] Add proper support for NetBSD core files with threads Improve the support for processing NetBSD cores. Fix reading process identifier, thread information and associating the terminating signal with the correct thread. Includes test cases for single-threaded program receiving SIGSEGV, and two dual-threaded programs: one where thread receives the signal, and the other one when the whole process is signalled. Differential Revision: https://reviews.llvm.org/D32149 llvm-svn: 355736 --- .../postmortem/netbsd-core/1lwp_SIGSEGV.amd64 | Bin 0 -> 13616 bytes .../postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core | Bin 0 -> 101872 bytes .../postmortem/netbsd-core/1lwp_SIGSEGV.c | 14 ++ .../netbsd-core/2lwp_process_SIGSEGV.amd64 | Bin 0 -> 15816 bytes .../netbsd-core/2lwp_process_SIGSEGV.amd64.core | Bin 0 -> 121208 bytes .../postmortem/netbsd-core/2lwp_process_SIGSEGV.c | 32 +++ .../postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 | Bin 0 -> 15456 bytes .../netbsd-core/2lwp_t2_SIGSEGV.amd64.core | Bin 0 -> 121192 bytes .../postmortem/netbsd-core/2lwp_t2_SIGSEGV.c | 30 +++ .../postmortem/netbsd-core/GNUmakefile | 15 ++ .../postmortem/netbsd-core/TestNetBSDCore.py | 225 +++++++++++++++++++++ 11 files changed, 316 insertions(+) create mode 100755 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64 create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c create mode 100755 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64 create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c create mode 100755 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py (limited to 'lldb/packages/Python/lldbsuite/test/functionalities') diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64 b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64 new file mode 100755 index 00000000000..56fa077bd6a Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64 differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core new file mode 100644 index 00000000000..d2d40500455 Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c new file mode 100644 index 00000000000..972e9678af5 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.c @@ -0,0 +1,14 @@ +static void bar(char *boom) { + char F = 'b'; + *boom = 47; // Frame bar +} + +static void foo(char *boom, void (*boomer)(char *)) { + char F = 'f'; + boomer(boom); // Frame foo +} + +void main(void) { + char F = 'm'; + foo(0, bar); // Frame main +} diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64 b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64 new file mode 100755 index 00000000000..00f61dfce84 Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64 differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core new file mode 100644 index 00000000000..f9c2b562fba Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c new file mode 100644 index 00000000000..ce583aaada9 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +static void bar() { + char F = 'b'; + kill(getpid(), SIGSEGV); // Frame bar +} + +static void foo(void (*boomer)()) { + char F = 'f'; + boomer(); // Frame foo +} + +static void lwp_main(void *unused) { + char F = 'l'; + foo(bar); // Frame lwp_main +} + +int main(int argc, char **argv) { + ucontext_t uc; + lwpid_t lid; + static const size_t ssize = 16 * 1024; + void *stack; + + stack = malloc(ssize); + _lwp_makecontext(&uc, lwp_main, NULL, NULL, stack, ssize); + _lwp_create(&uc, 0, &lid); + _lwp_wait(lid, NULL); +} diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 new file mode 100755 index 00000000000..d304de160f0 Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core new file mode 100644 index 00000000000..5f68687c56e Binary files /dev/null and b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core differ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c new file mode 100644 index 00000000000..1cd86631edd --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.c @@ -0,0 +1,30 @@ +#include +#include +#include + +static void bar(char *boom) { + char F = 'b'; + *boom = 47; // Frame bar +} + +static void foo(char *boom, void (*boomer)(char *)) { + char F = 'f'; + boomer(boom); // Frame foo +} + +void lwp_main(void *unused) { + char F = 'l'; + foo(0, bar); // Frame lwp_main +} + +int main(int argc, char **argv) { + ucontext_t uc; + lwpid_t lid; + static const size_t ssize = 16 * 1024; + void *stack; + + stack = malloc(ssize); + _lwp_makecontext(&uc, lwp_main, NULL, NULL, stack, ssize); + _lwp_create(&uc, 0, &lid); + _lwp_wait(lid, NULL); +} diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile new file mode 100644 index 00000000000..62c719d3d2f --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/GNUmakefile @@ -0,0 +1,15 @@ +ARCH = $(shell uname -m) +PROGRAMS = 1lwp_SIGSEGV 2lwp_t2_SIGSEGV 2lwp_process_SIGSEGV +EXECS = $(patsubst %,%.$(ARCH),$(PROGRAMS)) +CORES = $(patsubst %,%.core,$(EXECS)) + +all: $(CORES) $(EXECS) +clean: + rm -f $(CORES) $(EXECS) + +%.core: % + sysctl -w proc.$$$$.corename=$@; ulimit -s 16; ! ./$< +%.$(ARCH): %.c + $(CC) -o $@ -g $< + +.PHONY: all clean diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py new file mode 100644 index 00000000000..ca234ecc1f6 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/TestNetBSDCore.py @@ -0,0 +1,225 @@ +""" +Test NetBSD core file debugging. +""" + +from __future__ import division, print_function + +import shutil +import signal +import struct +import os + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class NetBSDCoreCommonTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + super(NetBSDCoreCommonTestCase, self).setUp() + self._initial_platform = lldb.DBG.GetSelectedPlatform() + + def tearDown(self): + lldb.DBG.SetSelectedPlatform(self._initial_platform) + super(NetBSDCoreCommonTestCase, self).tearDown() + + def check_memory_regions(self, process, region_count): + region_list = process.GetMemoryRegions() + self.assertEqual(region_list.GetSize(), region_count) + + region = lldb.SBMemoryRegionInfo() + + # Check we have the right number of regions. + self.assertEqual(region_list.GetSize(), region_count) + + # Check that getting a region beyond the last in the list fails. + self.assertFalse( + region_list.GetMemoryRegionAtIndex( + region_count, region)) + + # Check each region is valid. + for i in range(region_list.GetSize()): + # Check we can actually get this region. + self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region)) + + # Every region in the list should be mapped. + self.assertTrue(region.IsMapped()) + + # Test the address at the start of a region returns it's enclosing + # region. + begin_address = region.GetRegionBase() + region_at_begin = lldb.SBMemoryRegionInfo() + error = process.GetMemoryRegionInfo(begin_address, region_at_begin) + self.assertEqual(region, region_at_begin) + + # Test an address in the middle of a region returns it's enclosing + # region. + middle_address = (region.GetRegionBase() + + region.GetRegionEnd()) // 2 + region_at_middle = lldb.SBMemoryRegionInfo() + error = process.GetMemoryRegionInfo( + middle_address, region_at_middle) + self.assertEqual(region, region_at_middle) + + # Test the address at the end of a region returns it's enclosing + # region. + end_address = region.GetRegionEnd() - 1 + region_at_end = lldb.SBMemoryRegionInfo() + error = process.GetMemoryRegionInfo(end_address, region_at_end) + self.assertEqual(region, region_at_end) + + # Check that quering the end address does not return this region but + # the next one. + next_region = lldb.SBMemoryRegionInfo() + error = process.GetMemoryRegionInfo( + region.GetRegionEnd(), next_region) + self.assertNotEqual(region, next_region) + self.assertEqual( + region.GetRegionEnd(), + next_region.GetRegionBase()) + + # Check that query beyond the last region returns an unmapped region + # that ends at LLDB_INVALID_ADDRESS + last_region = lldb.SBMemoryRegionInfo() + region_list.GetMemoryRegionAtIndex(region_count - 1, last_region) + end_region = lldb.SBMemoryRegionInfo() + error = process.GetMemoryRegionInfo( + last_region.GetRegionEnd(), end_region) + self.assertFalse(end_region.IsMapped()) + self.assertEqual( + last_region.GetRegionEnd(), + end_region.GetRegionBase()) + self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS) + + def check_state(self, process): + with open(os.devnull) as devnul: + # sanitize test output + self.dbg.SetOutputFileHandle(devnul, False) + self.dbg.SetErrorFileHandle(devnul, False) + + self.assertTrue(process.is_stopped) + + # Process.Continue + error = process.Continue() + self.assertFalse(error.Success()) + self.assertTrue(process.is_stopped) + + # Thread.StepOut + thread = process.GetSelectedThread() + thread.StepOut() + self.assertTrue(process.is_stopped) + + # command line + self.dbg.HandleCommand('s') + self.assertTrue(process.is_stopped) + self.dbg.HandleCommand('c') + self.assertTrue(process.is_stopped) + + # restore file handles + self.dbg.SetOutputFileHandle(None, False) + self.dbg.SetErrorFileHandle(None, False) + + def check_backtrace(self, thread, filename, backtrace): + self.assertGreaterEqual(thread.GetNumFrames(), len(backtrace)) + src = filename.rpartition('.')[0] + '.c' + for i in range(len(backtrace)): + frame = thread.GetFrameAtIndex(i) + self.assertTrue(frame) + self.assertEqual(frame.GetFunctionName(), backtrace[i]) + if not backtrace[i].startswith('_'): + self.assertEqual(frame.GetLineEntry().GetLine(), + line_number(src, "Frame " + backtrace[i])) + self.assertEqual( + frame.FindVariable("F").GetValueAsUnsigned(), ord( + backtrace[i][0])) + + def do_test(self, filename, pid, region_count): + target = self.dbg.CreateTarget(filename) + process = target.LoadCore(filename + ".core") + + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), self.THREAD_COUNT) + self.assertEqual(process.GetProcessID(), pid) + + self.check_state(process) + + self.check_stack(process, pid, filename) + + self.check_memory_regions(process, region_count) + + self.dbg.DeleteTarget(target) + + +class NetBSD1LWPCoreTestCase(NetBSDCoreCommonTestCase): + THREAD_COUNT = 1 + + def check_stack(self, process, pid, filename): + thread = process.GetSelectedThread() + self.assertTrue(thread) + self.assertEqual(thread.GetThreadID(), 1) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertEqual(thread.GetStopReasonDataCount(), 1) + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV) + backtrace = ["bar", "foo", "main"] + self.check_backtrace(thread, filename, backtrace) + + @skipIfLLVMTargetMissing("X86") + def test_amd64(self): + """Test single-threaded amd64 core dump.""" + self.do_test("1lwp_SIGSEGV.amd64", pid=693, region_count=21) + + +class NetBSD2LWPT2CoreTestCase(NetBSDCoreCommonTestCase): + THREAD_COUNT = 2 + + def check_stack(self, process, pid, filename): + thread = process.GetSelectedThread() + self.assertTrue(thread) + self.assertEqual(thread.GetThreadID(), 2) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertEqual(thread.GetStopReasonDataCount(), 1) + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV) + backtrace = ["bar", "foo", "lwp_main"] + self.check_backtrace(thread, filename, backtrace) + + # thread 1 should have no signal + thread = process.GetThreadByID(1) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertEqual(thread.GetStopReasonDataCount(), 1) + self.assertEqual(thread.GetStopReasonDataAtIndex(0), 0) + + @skipIfLLVMTargetMissing("X86") + def test_amd64(self): + """Test double-threaded amd64 core dump where thread 2 is signalled.""" + self.do_test("2lwp_t2_SIGSEGV.amd64", pid=622, region_count=24) + + +class NetBSD2LWPProcessSigCoreTestCase(NetBSDCoreCommonTestCase): + THREAD_COUNT = 2 + + def check_stack(self, process, pid, filename): + thread = process.GetSelectedThread() + self.assertTrue(thread) + self.assertEqual(thread.GetThreadID(), 2) + self.assertEqual(thread.GetThreadID(), 2) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertEqual(thread.GetStopReasonDataCount(), 1) + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV) + backtrace = ["_kill", "bar", "foo", "lwp_main"] + self.check_backtrace(thread, filename, backtrace) + + # thread 1 should have the same signal + thread = process.GetThreadByID(1) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertEqual(thread.GetStopReasonDataCount(), 1) + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signal.SIGSEGV) + + @skipIfLLVMTargetMissing("X86") + def test_amd64(self): + """Test double-threaded amd64 core dump where process is signalled.""" + self.do_test("2lwp_process_SIGSEGV.amd64", pid=141, region_count=24) -- cgit v1.2.3