diff options
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/postmortem')
16 files changed, 336 insertions, 1 deletions
diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py new file mode 100644 index 000000000000..fd5bb00d0565 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py @@ -0,0 +1,164 @@ +""" +Test basics of linux core file debugging. +""" + +from __future__ import print_function + +import shutil +import struct + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class LinuxCoreTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + + _i386_pid = 32306 + _x86_64_pid = 32259 + _s390x_pid = 1045 + + _i386_regions = 4 + _x86_64_regions = 5 + _s390x_regions = 2 + + @skipIf(bugnumber="llvm.org/pr26947") + def test_i386(self): + """Test that lldb can read the process information from an i386 linux core file.""" + self.do_test("i386", self._i386_pid, self._i386_regions) + + def test_x86_64(self): + """Test that lldb can read the process information from an x86_64 linux core file.""" + self.do_test("x86_64", self._x86_64_pid, self._x86_64_regions) + + # This seems to hang on non-s390x platforms for some reason. Disabling for now. + @skipIf(archs=no_match(['s390x'])) + def test_s390x(self): + """Test that lldb can read the process information from an s390x linux core file.""" + self.do_test("s390x", self._s390x_pid, self._s390x_regions) + + def test_same_pid_running(self): + """Test that we read the information from the core correctly even if we have a running + process with the same PID around""" + try: + shutil.copyfile("x86_64.out", "x86_64-pid.out") + shutil.copyfile("x86_64.core", "x86_64-pid.core") + with open("x86_64-pid.core", "r+b") as f: + # These are offsets into the NT_PRSTATUS and NT_PRPSINFO structures in the note + # segment of the core file. If you update the file, these offsets may need updating + # as well. (Notes can be viewed with readelf --notes.) + for pid_offset in [0x1c4, 0x320]: + f.seek(pid_offset) + self.assertEqual(struct.unpack("<I", f.read(4))[0], self._x86_64_pid) + + # We insert our own pid, and make sure the test still works. + f.seek(pid_offset) + f.write(struct.pack("<I", os.getpid())) + self.do_test("x86_64-pid", os.getpid(), self._x86_64_regions) + finally: + self.RemoveTempFile("x86_64-pid.out") + self.RemoveTempFile("x86_64-pid.core") + + def test_two_cores_same_pid(self): + """Test that we handle the situation if we have two core files with the same PID + around""" + alttarget = self.dbg.CreateTarget("altmain.out") + altprocess = alttarget.LoadCore("altmain.core") + self.assertTrue(altprocess, PROCESS_IS_VALID) + self.assertEqual(altprocess.GetNumThreads(), 1) + self.assertEqual(altprocess.GetProcessID(), self._x86_64_pid) + + altframe = altprocess.GetSelectedThread().GetFrameAtIndex(0) + self.assertEqual(altframe.GetFunctionName(), "_start") + self.assertEqual(altframe.GetLineEntry().GetLine(), line_number("altmain.c", "Frame _start")) + + error = lldb.SBError() + F = altprocess.ReadCStringFromMemory(altframe.FindVariable("F").GetValueAsUnsigned(), 256, error) + self.assertTrue(error.Success()) + self.assertEqual(F, "_start") + + # without destroying this process, run the test which opens another core file with the + # same pid + self.do_test("x86_64", self._x86_64_pid, self._x86_64_regions) + + 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()) / 2l + 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() - 1l + 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 do_test(self, filename, pid, region_count): + target = self.dbg.CreateTarget(filename + ".out") + process = target.LoadCore(filename + ".core") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 1) + self.assertEqual(process.GetProcessID(), pid) + + thread = process.GetSelectedThread() + self.assertTrue(thread) + self.assertEqual(thread.GetThreadID(), pid) + backtrace = ["bar", "foo", "_start"] + self.assertEqual(thread.GetNumFrames(), len(backtrace)) + for i in range(len(backtrace)): + frame = thread.GetFrameAtIndex(i) + self.assertTrue(frame) + self.assertEqual(frame.GetFunctionName(), backtrace[i]) + self.assertEqual(frame.GetLineEntry().GetLine(), + line_number("main.c", "Frame " + backtrace[i])) + self.assertEqual(frame.FindVariable("F").GetValueAsUnsigned(), ord(backtrace[i][0])) + + self.check_memory_regions(process, region_count) + + self.dbg.DeleteTarget(target) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.c b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.c new file mode 100644 index 000000000000..da49a00996e1 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.c @@ -0,0 +1,6 @@ +void _start(void) +{ + const char *F = "_start"; + char *boom = (char *)0; + *boom = 47; // Frame _start +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.core b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.core Binary files differnew file mode 100644 index 000000000000..423413070c7a --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.out b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.out Binary files differnew file mode 100755 index 000000000000..2fddf3e8f803 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.core b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.core Binary files differnew file mode 100644 index 000000000000..f8deff474d1f --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.out b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.out Binary files differnew file mode 100755 index 000000000000..3cdd4eeca103 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/main.c b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/main.c new file mode 100644 index 000000000000..f5bde4171ca5 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/main.c @@ -0,0 +1,17 @@ +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 _start(void) +{ + char F = '_'; + foo(0, bar); // Frame _start +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/make-core.sh b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/make-core.sh new file mode 100755 index 000000000000..efe1b801df34 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/make-core.sh @@ -0,0 +1,40 @@ +#! /bin/bash + +set -e -x + +file=$1 +if [ -z "$file" ]; then + cat <<EOF +Please supply the main source file as the first argument. +EOF + exit 1 +fi + +if grep -q '^|' </proc/sys/kernel/core_pattern; then + cat <<EOF +Your system uses a crash report tool ($(cat /proc/sys/kernel/core_pattern)). Core files +will not be generated. Please reset /proc/sys/kernel/core_pattern (requires root +privileges) to enable core generation. +EOF + exit 1 +fi + +ulimit -c 1000 +real_limit=$(ulimit -c) +if [ $real_limit -lt 100 ]; then + cat <<EOF +Unable to increase the core file limit. Core file may be truncated! +To fix this, increase HARD core file limit (ulimit -H -c 1000). This may require root +privileges. +EOF +fi + +${CC:-cc} -nostdlib -static -g $CFLAGS "$file" -o a.out + +cat <<EOF +Executable file is in a.out. +Core file will be saved according to pattern $(cat /proc/sys/kernel/core_pattern). +EOF + +ulimit -s 8 # Decrease stack size to 8k => smaller core files. +exec ./a.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.core b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.core Binary files differnew file mode 100644 index 000000000000..b97fc43e967d --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.out b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.out Binary files differnew file mode 100755 index 000000000000..640fbdc257d9 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.core b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.core Binary files differnew file mode 100644 index 000000000000..e2fa69e4558e --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.out b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.out Binary files differnew file mode 100755 index 000000000000..842402fd519d --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py index 1dda59ac374b..89d1974b6703 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py @@ -7,8 +7,9 @@ from six import iteritems import lldb +from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * -import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test import lldbutil class MiniDumpTestCase(TestBase): diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py new file mode 100644 index 000000000000..08debab538f5 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py @@ -0,0 +1,76 @@ +""" +Test basics of a mini dump taken of a 32-bit process running in WoW64 + +WoW64 is the subsystem that lets 32-bit processes run in 64-bit Windows. If you +capture a mini dump of a process running under WoW64 with a 64-bit debugger, you +end up with a dump of the WoW64 layer. In that case, LLDB must do extra work to +get the 32-bit register contexts. +""" + +from __future__ import print_function +from six import iteritems + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class Wow64MiniDumpTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts + @no_debug_info_test + def test_wow64_mini_dump(self): + """Test that lldb can read the process information from the minidump.""" + # target create -c fizzbuzz_wow64.dmp + target = self.dbg.CreateTarget("") + process = target.LoadCore("fizzbuzz_wow64.dmp") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 1) + self.assertEqual(process.GetProcessID(), 0x1E9C) + + @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts + @no_debug_info_test + def test_thread_info_in_wow64_mini_dump(self): + """Test that lldb can read the thread information from the minidump.""" + # target create -c fizzbuzz_wow64.dmp + target = self.dbg.CreateTarget("") + process = target.LoadCore("fizzbuzz_wow64.dmp") + # This process crashed due to an access violation (0xc0000005), but the + # minidump doesn't have an exception record--perhaps the crash handler + # ate it. + # TODO: See if we can recover the exception information from the TEB, + # which, according to Windbg, has a pointer to an exception list. + + # In the dump, none of the threads are stopped, so we cannot use + # lldbutil.get_stopped_thread. + thread = process.GetThreadAtIndex(0) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone) + + @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts + @no_debug_info_test + def test_stack_info_in_wow64_mini_dump(self): + """Test that we can see a trivial stack in a VS-generate mini dump.""" + # target create -c fizzbuzz_no_heap.dmp + target = self.dbg.CreateTarget("") + process = target.LoadCore("fizzbuzz_wow64.dmp") + self.assertGreaterEqual(process.GetNumThreads(), 1) + # This process crashed due to an access violation (0xc0000005), but the + # minidump doesn't have an exception record--perhaps the crash handler + # ate it. + # TODO: See if we can recover the exception information from the TEB, + # which, according to Windbg, has a pointer to an exception list. + + # In the dump, none of the threads are stopped, so we cannot use + # lldbutil.get_stopped_thread. + thread = process.GetThreadAtIndex(0) + # The crash is in main, so there should be at least one frame on the stack. + self.assertGreaterEqual(thread.GetNumFrames(), 1) + frame = thread.GetFrameAtIndex(0) + self.assertTrue(frame.IsValid()) + pc = frame.GetPC() + eip = frame.FindRegister("pc") + self.assertTrue(eip.IsValid()) + self.assertEqual(pc, eip.GetValueAsUnsigned()) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz.cpp new file mode 100644 index 000000000000..295d4a1f24db --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz.cpp @@ -0,0 +1,31 @@ +// A sample program for getting minidumps on Windows. + +#include <iostream> + +bool +fizz(int x) +{ + return x % 3 == 0; +} + +bool +buzz(int x) +{ + return x % 5 == 0; +} + +int +main() +{ + int *buggy = 0; + + for (int i = 1; i <= 100; ++i) + { + if (fizz(i)) std::cout << "fizz"; + if (buzz(i)) std::cout << "buzz"; + if (!fizz(i) && !buzz(i)) std::cout << i; + std::cout << '\n'; + } + + return *buggy; +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz_wow64.dmp b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz_wow64.dmp Binary files differnew file mode 100644 index 000000000000..3d97186f2cd2 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz_wow64.dmp |