diff options
author | Michal Gorny <mgorny@gentoo.org> | 2019-03-08 21:10:43 +0000 |
---|---|---|
committer | Michal Gorny <mgorny@gentoo.org> | 2019-03-08 21:10:43 +0000 |
commit | c12f159788dcc791e4a415352031fb761f31c3ec (patch) | |
tree | 6bbcdf3a3a43fd093a4d92c6b9a01205acf01946 /lldb/packages/Python/lldbsuite | |
parent | 7a462ab7ae7d4fe45eace5942519bf305391e11f (diff) | |
download | bcm5719-llvm-c12f159788dcc791e4a415352031fb761f31c3ec.tar.gz bcm5719-llvm-c12f159788dcc791e4a415352031fb761f31c3ec.zip |
[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
Diffstat (limited to 'lldb/packages/Python/lldbsuite')
11 files changed, 316 insertions, 0 deletions
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 Binary files differnew file mode 100755 index 00000000000..56fa077bd6a --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64 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 Binary files differnew file mode 100644 index 00000000000..d2d40500455 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/1lwp_SIGSEGV.amd64.core 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 Binary files differnew file mode 100755 index 00000000000..00f61dfce84 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64 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 Binary files differnew file mode 100644 index 00000000000..f9c2b562fba --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_process_SIGSEGV.amd64.core 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 <lwp.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +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 Binary files differnew file mode 100755 index 00000000000..d304de160f0 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64 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 Binary files differnew file mode 100644 index 00000000000..5f68687c56e --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/postmortem/netbsd-core/2lwp_t2_SIGSEGV.amd64.core 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 <lwp.h> +#include <stddef.h> +#include <stdlib.h> + +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) |