diff options
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/postmortem')
39 files changed, 943 insertions, 196 deletions
diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/TestLinuxCore.py b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/TestLinuxCore.py new file mode 100644 index 000000000000..ed46ef1c847e --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/TestLinuxCore.py @@ -0,0 +1,249 @@ +""" +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(oslist=['windows']) + @skipIf(triple='^mips') + def test_i386(self): + """Test that lldb can read the process information from an i386 linux core file.""" + self.do_test("linux-i386", self._i386_pid, self._i386_regions) + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_x86_64(self): + """Test that lldb can read the process information from an x86_64 linux core file.""" + self.do_test("linux-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'])) + @skipIf(triple='^mips') + def test_s390x(self): + """Test that lldb can read the process information from an s390x linux core file.""" + self.do_test("linux-s390x", self._s390x_pid, self._s390x_regions) + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + 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("linux-x86_64.out", "linux-x86_64-pid.out") + shutil.copyfile("linux-x86_64.core", "linux-x86_64-pid.core") + with open("linux-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("linux-x86_64-pid", os.getpid(), self._x86_64_regions) + finally: + self.RemoveTempFile("linux-x86_64-pid.out") + self.RemoveTempFile("linux-x86_64-pid.core") + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + 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("linux-x86_64", self._x86_64_pid, self._x86_64_regions) + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_FPR_SSE(self): + # check x86_64 core file + target = self.dbg.CreateTarget(None) + self.assertTrue(target, VALID_TARGET) + process = target.LoadCore("linux-fpr_sse_x86_64.core") + + values = {} + values["fctrl"] = "0x037f" + values["fstat"] = "0x0000" + values["ftag"] = "0xff" + values["fop"] = "0x0000" + values["fiseg"] = "0x00000000" + values["fioff"] = "0x0040011e" + values["foseg"] = "0x00000000" + values["fooff"] = "0x00000000" + values["mxcsr"] = "0x00001f80" + values["mxcsrmask"] = "0x0000ffff" + values["st0"] = "{0x99 0xf7 0xcf 0xfb 0x84 0x9a 0x20 0x9a 0xfd 0x3f}" + values["st1"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x3f}" + values["st2"] = "{0xfe 0x8a 0x1b 0xcd 0x4b 0x78 0x9a 0xd4 0x00 0x40}" + values["st3"] = "{0xac 0x79 0xcf 0xd1 0xf7 0x17 0x72 0xb1 0xfe 0x3f}" + values["st4"] = "{0xbc 0xf0 0x17 0x5c 0x29 0x3b 0xaa 0xb8 0xff 0x3f}" + values["st5"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x3f}" + values["st6"] = "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}" + values["st7"] = "{0x35 0xc2 0x68 0x21 0xa2 0xda 0x0f 0xc9 0x00 0x40}" + values["xmm0"] = "{0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46 0x29 0x31 0x64 0x46}" + values["xmm1"] = "{0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64 0x9c 0xed 0x86 0x64}" + values["xmm2"] = "{0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7 0x07 0xc2 0x1f 0xd7}" + values["xmm3"] = "{0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25 0xa2 0x20 0x48 0x25}" + values["xmm4"] = "{0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4 0xeb 0x5a 0xa8 0xc4}" + values["xmm5"] = "{0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b 0x49 0x41 0x20 0x0b}" + values["xmm6"] = "{0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f 0xf8 0xf1 0x8b 0x4f}" + values["xmm7"] = "{0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd 0x13 0xf1 0x30 0xcd}" + + for regname, value in values.iteritems(): + self.expect("register read {}".format(regname), substrs=["{} = {}".format(regname, value)]) + + + # now check i386 core file + target = self.dbg.CreateTarget(None) + self.assertTrue(target, VALID_TARGET) + process = target.LoadCore("linux-fpr_sse_i386.core") + + values["fioff"] = "0x080480cc" + + for regname, value in values.iteritems(): + self.expect("register read {}".format(regname), substrs=["{} = {}".format(regname, value)]) + + 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 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/elf-core/altmain.c index da49a00996e1..da49a00996e1 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.c +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.c diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.core Binary files differindex 423413070c7a..423413070c7a 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.core +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.out b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.out Binary files differindex 2fddf3e8f803..2fddf3e8f803 100755 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/altmain.out +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/fpr_sse.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/fpr_sse.cpp new file mode 100644 index 000000000000..e6826fc7a097 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/fpr_sse.cpp @@ -0,0 +1,38 @@ +// fpr_sse_x86_64.core was generated with: +// ./make-core.sh fpr_sse.cpp +// +// fpr_sse_i386.core was generated with: +// export CFLAGS=-m32 +// ./make-core.sh fpr_sse.cpp + +void _start(void) { + __asm__("fldpi;" + "fldz;" + "fld1;" + "fldl2e;" + "fldln2;" + "fldl2t;" + "fld1;" + "fldlg2;"); + + unsigned int values[8] = { + 0x46643129, 0x6486ed9c, 0xd71fc207, 0x254820a2, + 0xc4a85aeb, 0x0b204149, 0x4f8bf1f8, 0xcd30f113, + }; + + __asm__("vbroadcastss %0, %%xmm0;" + "vbroadcastss %1, %%xmm1;" + "vbroadcastss %2, %%xmm2;" + "vbroadcastss %3, %%xmm3;" + "vbroadcastss %4, %%xmm4;" + "vbroadcastss %5, %%xmm5;" + "vbroadcastss %6, %%xmm6;" + "vbroadcastss %7, %%xmm7;" + + ::"m"(values[0]), + "m"(values[1]), "m"(values[2]), "m"(values[3]), "m"(values[4]), + "m"(values[5]), "m"(values[6]), "m"(values[7])); + + volatile int *a = 0; + *a = 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py new file mode 100644 index 000000000000..5a11a52e93a6 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py @@ -0,0 +1,52 @@ +""" +Test signal reporting when debugging with linux core files. +""" + +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 GCoreTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + _initial_platform = lldb.DBG.GetSelectedPlatform() + + _i386_pid = 5586 + _x86_64_pid = 5669 + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_i386(self): + """Test that lldb can read the process information from an i386 linux core file.""" + self.do_test("linux-i386", self._i386_pid) + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_x86_64(self): + """Test that lldb can read the process information from an x86_64 linux core file.""" + self.do_test("linux-x86_64", self._x86_64_pid) + + def do_test(self, filename, pid): + target = self.dbg.CreateTarget("") + process = target.LoadCore(filename + ".core") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 3) + self.assertEqual(process.GetProcessID(), pid) + + for thread in process: + reason = thread.GetStopReason() + self.assertEqual(reason, lldb.eStopReasonSignal) + signal = thread.GetStopReasonDataAtIndex(1) + # Check we got signal 19 (SIGSTOP) + self.assertEqual(signal, 19) + + self.dbg.DeleteTarget(target) + lldb.DBG.SetSelectedPlatform(self._initial_platform) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-i386.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-i386.core Binary files differnew file mode 100644 index 000000000000..8f9ac87c19f2 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-i386.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-x86_64.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-x86_64.core Binary files differnew file mode 100644 index 000000000000..ef673e45b219 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-x86_64.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp new file mode 100644 index 000000000000..9908faffb6eb --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp @@ -0,0 +1,63 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This test verifies the correct handling of child thread exits. + +#include <atomic> +#include <thread> +#include <csignal> + +pseudo_barrier_t g_barrier1; +pseudo_barrier_t g_barrier2; + +void * +thread1 () +{ + // Synchronize with the main thread. + pseudo_barrier_wait(g_barrier1); + + // Synchronize with the main thread and thread2. + pseudo_barrier_wait(g_barrier2); + + // Return + return NULL; +} + +void * +thread2 () +{ + + // Synchronize with thread1 and the main thread. + pseudo_barrier_wait(g_barrier2); // Should not reach here. + + // Return + return NULL; +} + +int main () +{ + + pseudo_barrier_init(g_barrier1, 2); + pseudo_barrier_init(g_barrier2, 3); + + // Create a thread. + std::thread thread_1(thread1); + + // Wait for thread1 to start. + pseudo_barrier_wait(g_barrier1); + + // Wait for thread1 to start. + std::thread thread_2(thread2); + + // Thread 2 is waiting for another thread to reach the barrier. + // This should have for ever. (So we can run gcore against this process.) + thread_2.join(); + + return 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk new file mode 100755 index 000000000000..ff874a21f760 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk @@ -0,0 +1,5 @@ +LEVEL = ../../../../make + +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh new file mode 100755 index 000000000000..b6979c7790de --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh @@ -0,0 +1,56 @@ +#! /bin/sh + +linux_check_ptrace_scope() +{ + if grep -q '1' </proc/sys/kernel/yama/ptrace_scope; then + cat <<EOF +Your system prevents the use of PTRACE to attach to non-child processes. The core file +cannot be generated. Please reset /proc/sys/kernel/yama/ptrace_scope to 0 (requires root +privileges) to enable core generation via gcore. +EOF + exit 1 + fi +} + +set -e -x + +OS=$(uname -s) +if [ "$OS" = Linux ]; then + linux_check_ptrace_scope +fi + +rm -f a.out +make -f main.mk + +cat <<EOF +Executable file is in a.out. +Core file will be saved as core.<pid>. +EOF + +stack_size=`ulimit -s` + +# Decrease stack size to 16k => smaller core files. +# gcore won't run with the smaller stack +ulimit -Ss 16 + +core_dump_filter=`cat /proc/self/coredump_filter` +echo 0 > /proc/self/coredump_filter + +./a.out & + +pid=$! + +echo $core_dump_filter > /proc/self/coredump_filter + +# Reset stack size as so there's enough space to run gcore. +ulimit -s $stack_size + +echo "Sleeping for 5 seconds to wait for $pid" + +sleep 5 +echo "Taking core from process $pid" + +gcore -o core $pid + +echo "Killing process $pid" +kill -9 $pid diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_i386.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_i386.core Binary files differnew file mode 100644 index 000000000000..b0fdaf67ca4f --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_i386.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_x86_64.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_x86_64.core Binary files differnew file mode 100644 index 000000000000..5fb39ee115b2 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_x86_64.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.core Binary files differindex f8deff474d1f..f8deff474d1f 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.core +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.out b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.out Binary files differindex 3cdd4eeca103..3cdd4eeca103 100755 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/i386.out +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.core Binary files differindex b97fc43e967d..b97fc43e967d 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.core +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.out b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.out Binary files differindex 640fbdc257d9..640fbdc257d9 100755 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/s390x.out +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.core Binary files differindex e2fa69e4558e..e2fa69e4558e 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.core +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.out b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.out Binary files differindex 842402fd519d..842402fd519d 100755 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/x86_64.out +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.out diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/main.c b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/main.c index f5bde4171ca5..f5bde4171ca5 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/main.c +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/main.c diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/make-core.sh b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/make-core.sh index efe1b801df34..9dd83f19c76e 100755 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/make-core.sh +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/make-core.sh @@ -1,4 +1,30 @@ -#! /bin/bash +#! /bin/sh + +linux_check_core_pattern() +{ + 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 +} + +OS=$(uname -s) +case "$OS" in +FreeBSD) + core_pattern=$(sysctl -n kern.corefile) + ;; +Linux) + core_pattern=$(cat /proc/sys/kernel/core_pattern) + ;; +*) + echo "OS $OS not supported" >&2 + exit 1 + ;; +esac set -e -x @@ -10,13 +36,8 @@ 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 +if [ "$OS" = Linux ]; then + linux_check_core_pattern fi ulimit -c 1000 @@ -33,7 +54,7 @@ ${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). +Core file will be saved according to pattern $core_pattern. EOF ulimit -s 8 # Decrease stack size to 8k => smaller core files. diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py new file mode 100644 index 000000000000..7cc3c0775ced --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py @@ -0,0 +1,61 @@ +""" +Test signal reporting when debugging with linux core files. +""" + +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 LinuxCoreThreadsTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + mydir = TestBase.compute_mydir(__file__) + _initial_platform = lldb.DBG.GetSelectedPlatform() + + _i386_pid = 5193 + _x86_64_pid = 5222 + + # Thread id for the failing thread. + _i386_tid = 5195 + _x86_64_tid = 5250 + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_i386(self): + """Test that lldb can read the process information from an i386 linux core file.""" + self.do_test("linux-i386", self._i386_pid, self._i386_tid) + + @skipIf(oslist=['windows']) + @skipIf(triple='^mips') + def test_x86_64(self): + """Test that lldb can read the process information from an x86_64 linux core file.""" + self.do_test("linux-x86_64", self._x86_64_pid, self._x86_64_tid) + + def do_test(self, filename, pid, tid): + target = self.dbg.CreateTarget("") + process = target.LoadCore(filename + ".core") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetNumThreads(), 3) + self.assertEqual(process.GetProcessID(), pid) + + for thread in process: + reason = thread.GetStopReason() + if( thread.GetThreadID() == tid ): + self.assertEqual(reason, lldb.eStopReasonSignal) + signal = thread.GetStopReasonDataAtIndex(1) + # Check we got signal 4 (SIGILL) + self.assertEqual(signal, 4) + else: + signal = thread.GetStopReasonDataAtIndex(1) + # Check we got no signal on the other threads + self.assertEqual(signal, 0) + + self.dbg.DeleteTarget(target) + lldb.DBG.SetSelectedPlatform(self._initial_platform) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-i386.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-i386.core Binary files differnew file mode 100644 index 000000000000..86c6fb8c5ac3 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-i386.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-x86_64.core b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-x86_64.core Binary files differnew file mode 100644 index 000000000000..fc27e5810ee5 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-x86_64.core diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp new file mode 100644 index 000000000000..826d9d3fa972 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp @@ -0,0 +1,63 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This test verifies the correct handling of child thread exits. + +#include <atomic> +#include <thread> +#include <csignal> + +pseudo_barrier_t g_barrier1; +pseudo_barrier_t g_barrier2; + +void * +thread1 () +{ + // Synchronize with the main thread. + pseudo_barrier_wait(g_barrier1); + + // Synchronize with the main thread and thread2. + pseudo_barrier_wait(g_barrier2); + + // Return + return NULL; // Should not reach here. (thread2 should raise SIGILL) +} + +void * +thread2 () +{ + raise(SIGILL); // Raise SIGILL + + // Synchronize with thread1 and the main thread. + pseudo_barrier_wait(g_barrier2); // Should not reach here. + + // Return + return NULL; +} + +int main () +{ + pseudo_barrier_init(g_barrier1, 2); + pseudo_barrier_init(g_barrier2, 3); + + // Create a thread. + std::thread thread_1(thread1); + + // Wait for thread1 to start. + pseudo_barrier_wait(g_barrier1); + + // Create another thread. + std::thread thread_2(thread2); + + // Wait for thread2 to start. + // Second thread should crash but first thread and main thread may reach here. + pseudo_barrier_wait(g_barrier2); + + return 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk new file mode 100755 index 000000000000..ff874a21f760 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk @@ -0,0 +1,5 @@ +LEVEL = ../../../../make + +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh new file mode 100755 index 000000000000..ea263c86ea46 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh @@ -0,0 +1,64 @@ +#! /bin/sh + +linux_check_core_pattern() +{ + 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 +} + +OS=$(uname -s) +case "$OS" in +FreeBSD) + core_pattern=$(sysctl -n kern.corefile) + ;; +Linux) + core_pattern=$(cat /proc/sys/kernel/core_pattern) + ;; +*) + echo "OS $OS not supported" >&2 + exit 1 + ;; +esac + +set -e -x + +if [ "$OS" = Linux ]; then + linux_check_core_pattern +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 + +rm -f a.out +make -f main.mk + +cat <<EOF +Executable file is in a.out. +Core file will be saved according to pattern $core_pattern. +EOF + +# Save stack size and core_dump_filter +stack_size=`ulimit -s` +ulimit -Ss 32 # Decrease stack size to 32k => smaller core files. + +core_dump_filter=`cat /proc/self/coredump_filter` +echo 0 > /proc/self/coredump_filter + +exec ./a.out + +# Reset stack size and core_dump_filter +echo core_dump_filter > /proc/self/coredump_filter +ulimit -s $stack_size diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py b/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py deleted file mode 100644 index fd5bb00d0565..000000000000 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -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/minidump-new/TestMiniDumpNew.py b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py new file mode 100644 index 000000000000..44a42fdfe9d1 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py @@ -0,0 +1,161 @@ +""" +Test basics of Minidump debugging. +""" + +from __future__ import print_function +from six import iteritems + +import shutil + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class MiniDumpNewTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + _linux_x86_64_pid = 29917 + _linux_x86_64_not_crashed_pid = 29939 + _linux_x86_64_not_crashed_pid_offset = 0xD967 + + def test_process_info_in_minidump(self): + """Test that lldb can read the process information from the Minidump.""" + # target create -c linux-x86_64.dmp + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("linux-x86_64.dmp") + self.assertTrue(self.process, PROCESS_IS_VALID) + self.assertEqual(self.process.GetNumThreads(), 1) + self.assertEqual(self.process.GetProcessID(), self._linux_x86_64_pid) + + def test_thread_info_in_minidump(self): + """Test that lldb can read the thread information from the Minidump.""" + # target create -c linux-x86_64.dmp + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("linux-x86_64.dmp") + # This process crashed due to a segmentation fault in its + # one and only thread. + self.assertEqual(self.process.GetNumThreads(), 1) + thread = self.process.GetThreadAtIndex(0) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + stop_description = thread.GetStopDescription(256) + self.assertTrue("SIGSEGV" in stop_description) + + def test_stack_info_in_minidump(self): + """Test that we can see a trivial stack in a breakpad-generated Minidump.""" + # target create linux-x86_64 -c linux-x86_64.dmp + self.dbg.CreateTarget("linux-x86_64") + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("linux-x86_64.dmp") + self.assertEqual(self.process.GetNumThreads(), 1) + self.assertEqual(self.process.GetProcessID(), self._linux_x86_64_pid) + thread = self.process.GetThreadAtIndex(0) + # frame #0: linux-x86_64`crash() + # frame #1: linux-x86_64`_start + self.assertEqual(thread.GetNumFrames(), 2) + frame = thread.GetFrameAtIndex(0) + self.assertTrue(frame.IsValid()) + pc = frame.GetPC() + eip = frame.FindRegister("pc") + self.assertTrue(eip.IsValid()) + self.assertEqual(pc, eip.GetValueAsUnsigned()) + + def test_snapshot_minidump(self): + """Test that if we load a snapshot minidump file (meaning the process + did not crash) there is no stop reason.""" + # target create -c linux-x86_64_not_crashed.dmp + self.dbg.CreateTarget(None) + self.target = self.dbg.GetSelectedTarget() + self.process = self.target.LoadCore("linux-x86_64_not_crashed.dmp") + self.assertEqual(self.process.GetNumThreads(), 1) + thread = self.process.GetThreadAtIndex(0) + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone) + stop_description = thread.GetStopDescription(256) + self.assertEqual(stop_description, None) + + def do_test_deeper_stack(self, binary, core, pid): + target = self.dbg.CreateTarget(binary) + process = target.LoadCore(core) + thread = process.GetThreadAtIndex(0) + + self.assertEqual(process.GetProcessID(), pid) + + expected_stack = {1: 'bar', 2: 'foo', 3: '_start'} + self.assertGreaterEqual(thread.GetNumFrames(), len(expected_stack)) + for index, name in iteritems(expected_stack): + frame = thread.GetFrameAtIndex(index) + self.assertTrue(frame.IsValid()) + function_name = frame.GetFunctionName() + self.assertTrue(name in function_name) + + def test_deeper_stack_in_minidump(self): + """Test that we can examine a more interesting stack in a Minidump.""" + # Launch with the Minidump, and inspect the stack. + # target create linux-x86_64_not_crashed -c linux-x86_64_not_crashed.dmp + self.do_test_deeper_stack("linux-x86_64_not_crashed", + "linux-x86_64_not_crashed.dmp", + self._linux_x86_64_not_crashed_pid) + + def do_change_pid_in_minidump(self, core, newcore, offset, oldpid, newpid): + """ This assumes that the minidump is breakpad generated on Linux - + meaning that the PID in the file will be an ascii string part of + /proc/PID/status which is written in the file + """ + shutil.copyfile(core, newcore) + with open(newcore, "rb+") as f: + f.seek(offset) + currentpid = f.read(5).decode('utf-8') + self.assertEqual(currentpid, oldpid) + + f.seek(offset) + if len(newpid) < len(oldpid): + newpid += " " * (len(oldpid) - len(newpid)) + newpid += "\n" + f.write(newpid.encode('utf-8')) + + def test_deeper_stack_in_minidump_with_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""" + try: + self.do_change_pid_in_minidump("linux-x86_64_not_crashed.dmp", + "linux-x86_64_not_crashed-pid.dmp", + self._linux_x86_64_not_crashed_pid_offset, + str(self._linux_x86_64_not_crashed_pid), + str(os.getpid())) + self.do_test_deeper_stack("linux-x86_64_not_crashed", + "linux-x86_64_not_crashed-pid.dmp", + os.getpid()) + finally: + self.RemoveTempFile("linux-x86_64_not_crashed-pid.dmp") + + def test_two_cores_same_pid(self): + """Test that we handle the situation if we have two core files with the same PID """ + try: + self.do_change_pid_in_minidump("linux-x86_64_not_crashed.dmp", + "linux-x86_64_not_crashed-pid.dmp", + self._linux_x86_64_not_crashed_pid_offset, + str(self._linux_x86_64_not_crashed_pid), + str(self._linux_x86_64_pid)) + self.do_test_deeper_stack("linux-x86_64_not_crashed", + "linux-x86_64_not_crashed-pid.dmp", + self._linux_x86_64_pid) + self.test_stack_info_in_minidump() + finally: + self.RemoveTempFile("linux-x86_64_not_crashed-pid.dmp") + + def test_local_variables_in_minidump(self): + """Test that we can examine local variables in a Minidump.""" + # Launch with the Minidump, and inspect a local variable. + # target create linux-x86_64_not_crashed -c linux-x86_64_not_crashed.dmp + target = self.dbg.CreateTarget("linux-x86_64_not_crashed") + process = target.LoadCore("linux-x86_64_not_crashed.dmp") + thread = process.GetThreadAtIndex(0) + frame = thread.GetFrameAtIndex(1) + value = frame.EvaluateExpression('x') + self.assertEqual(value.GetValueAsSigned(), 3) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/install_breakpad.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/install_breakpad.cpp new file mode 100644 index 000000000000..c34ac17128fa --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/install_breakpad.cpp @@ -0,0 +1,16 @@ +#include "client/linux/handler/exception_handler.h" + +static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor, + void *context, bool succeeded) { + return succeeded; +} + +google_breakpad::ExceptionHandler *eh; + +void InstallBreakpad() { + google_breakpad::MinidumpDescriptor descriptor("/tmp"); + eh = new google_breakpad::ExceptionHandler(descriptor, NULL, dumpCallback, + NULL, true, -1); +} + +void WriteMinidump() { eh->WriteMinidump(); } diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64 b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64 Binary files differnew file mode 100755 index 000000000000..078d9c8fa90a --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64 diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.cpp new file mode 100644 index 000000000000..61d31492940d --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.cpp @@ -0,0 +1,12 @@ +void crash() { + volatile int *a = (int *)(nullptr); + *a = 1; +} + +extern "C" void _start(); +void InstallBreakpad(); + +void _start() { + InstallBreakpad(); + crash(); +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.dmp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.dmp Binary files differnew file mode 100644 index 000000000000..e2ae724abe99 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.dmp diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed Binary files differnew file mode 100755 index 000000000000..8b38cdb48bdd --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.cpp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.cpp new file mode 100644 index 000000000000..070c565e72bd --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.cpp @@ -0,0 +1,22 @@ +void InstallBreakpad(); +void WriteMinidump(); + +int global = 42; + +int bar(int x) { + WriteMinidump(); + int y = 4 * x + global; + return y; +} + +int foo(int x) { + int y = 2 * bar(3 * x); + return y; +} + +extern "C" void _start(); + +void _start() { + InstallBreakpad(); + foo(1); +} diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.dmp b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.dmp Binary files differnew file mode 100644 index 000000000000..ad4b61a7bbb4 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.dmp diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/makefile.txt b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/makefile.txt new file mode 100644 index 000000000000..79a95d61d85e --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/makefile.txt @@ -0,0 +1,29 @@ +# This makefile aims to make the binaries as small as possible, for us not to +# upload huge binary blobs in the repo. +# The binary should have debug symbols because stack unwinding doesn't work +# correctly using the information in the Minidump only. Also we want to evaluate +# local variables, etc. +# Breakpad compiles as a static library, so statically linking againts it +# makes the binary huge. +# Dynamically linking to it does improve things, but we are still #include-ing +# breakpad headers (which is a lot of source code for which we generate debug +# symbols) +# So, install_breakpad.cpp does the #include-ing and defines a global function +# "InstallBreakpad" that does all the exception handler registration. +# We compile install_breakpad to object file and then link it, alongside the +# static libbreakpad, into a shared library. +# Then the binaries dynamically link to that lib. +# The other optimisation is not using the standard library (hence the _start +# instead of main). We only link dynamically to some standard libraries. +# This way we have a tiny binary (~8K) that has debug symbols and uses breakpad +# to generate a Minidump when the binary crashes/requests such. +# +CC=g++ +FLAGS=-g --std=c++11 +INCLUDE=-I$HOME/breakpad/src/src/ +LINK=-L. -lbreakpad -lpthread -nostdlib -lc -lstdc++ -lgcc_s -fno-exceptions +all: + $(CC) $(FLAGS) -fPIC -c install_breakpad.cpp $(INCLUDE) -o install_breakpad.o + ld -shared install_breakpad.o libbreakpad_client.a -o libbreakpad.so + $(CC) $(FLAGS) -o linux-x86_64 linux-x86_64.cpp $(LINK) + $(CC) $(FLAGS) -o linux-x86_64_not_crashed linux-x86_64_not_crashed.cpp $(LINK) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py index 89d1974b6703..b89a305d0e88 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py @@ -11,12 +11,12 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class MiniDumpTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True - @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts - @no_debug_info_test def test_process_info_in_mini_dump(self): """Test that lldb can read the process information from the minidump.""" # target create -c fizzbuzz_no_heap.dmp @@ -27,23 +27,20 @@ class MiniDumpTestCase(TestBase): self.assertEqual(self.process.GetNumThreads(), 1) self.assertEqual(self.process.GetProcessID(), 4440) - @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts - @no_debug_info_test def test_thread_info_in_mini_dump(self): """Test that lldb can read the thread information from the minidump.""" # target create -c fizzbuzz_no_heap.dmp self.dbg.CreateTarget("") self.target = self.dbg.GetSelectedTarget() self.process = self.target.LoadCore("fizzbuzz_no_heap.dmp") - # This process crashed due to an access violation (0xc0000005) in its one and only thread. + # This process crashed due to an access violation (0xc0000005) in its + # one and only thread. self.assertEqual(self.process.GetNumThreads(), 1) thread = self.process.GetThreadAtIndex(0) self.assertEqual(thread.GetStopReason(), lldb.eStopReasonException) - stop_description = thread.GetStopDescription(256); - self.assertTrue("0xc0000005" in stop_description); + stop_description = thread.GetStopDescription(256) + self.assertTrue("0xc0000005" in stop_description) - @skipUnlessWindows # for now mini-dump debugging is limited to Windows hosts - @no_debug_info_test def test_stack_info_in_mini_dump(self): """Test that we can see a trivial stack in a VS-generate mini dump.""" # target create -c fizzbuzz_no_heap.dmp @@ -61,8 +58,7 @@ class MiniDumpTestCase(TestBase): self.assertTrue(eip.IsValid()) self.assertEqual(pc, eip.GetValueAsUnsigned()) - @skipUnlessWindows - @not_remote_testsuite_ready + @skipUnlessWindows # Minidump saving works only on windows def test_deeper_stack_in_mini_dump(self): """Test that we can examine a more interesting stack in a mini dump.""" self.build() @@ -72,7 +68,8 @@ class MiniDumpTestCase(TestBase): # Set a breakpoint and capture a mini dump. target = self.dbg.CreateTarget(exe) breakpoint = target.BreakpointCreateByName("bar") - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertEqual(process.GetState(), lldb.eStateStopped) self.assertTrue(process.SaveCore(core)) self.assertTrue(os.path.isfile(core)) @@ -83,7 +80,7 @@ class MiniDumpTestCase(TestBase): process = target.LoadCore(core) thread = process.GetThreadAtIndex(0) - expected_stack = { 0: 'bar', 1: 'foo', 2: 'main' } + expected_stack = {0: 'bar', 1: 'foo', 2: 'main'} self.assertGreaterEqual(thread.GetNumFrames(), len(expected_stack)) for index, name in iteritems(expected_stack): frame = thread.GetFrameAtIndex(index) @@ -97,8 +94,7 @@ class MiniDumpTestCase(TestBase): if (os.path.isfile(core)): os.unlink(core) - @skipUnlessWindows - @not_remote_testsuite_ready + @skipUnlessWindows # Minidump saving works only on windows def test_local_variables_in_mini_dump(self): """Test that we can examine local variables in a mini dump.""" self.build() @@ -108,7 +104,8 @@ class MiniDumpTestCase(TestBase): # Set a breakpoint and capture a mini dump. target = self.dbg.CreateTarget(exe) breakpoint = target.BreakpointCreateByName("bar") - process = target.LaunchSimple(None, None, self.get_process_working_directory()) + process = target.LaunchSimple( + None, None, self.get_process_working_directory()) self.assertEqual(process.GetState(), lldb.eStateStopped) self.assertTrue(process.SaveCore(core)) self.assertTrue(os.path.isfile(core)) diff --git a/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py index 08debab538f5..73ad3940aca2 100644 --- a/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py +++ b/packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py @@ -16,12 +16,12 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil + class Wow64MiniDumpTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True - @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 @@ -31,8 +31,6 @@ class Wow64MiniDumpTestCase(TestBase): 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 @@ -49,8 +47,6 @@ class Wow64MiniDumpTestCase(TestBase): 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 @@ -66,7 +62,8 @@ class Wow64MiniDumpTestCase(TestBase): # 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. + # 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()) |