diff options
author | dim <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 |
commit | 78b9749c0a4ea980a8b934645da6ae98fcc665e8 (patch) | |
tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /packages/Python/lldbsuite/test/functionalities/signal | |
parent | 60cb593f9d55fa5ca7a5372b731f2330345b4b9a (diff) | |
download | FreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.zip FreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.tar.gz |
Vendor import of lldb trunk r256945:
https://llvm.org/svn/llvm-project/lldb/trunk@256945
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/signal')
9 files changed, 511 insertions, 0 deletions
diff --git a/packages/Python/lldbsuite/test/functionalities/signal/Makefile b/packages/Python/lldbsuite/test/functionalities/signal/Makefile new file mode 100644 index 0000000..0d70f25 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/signal/TestSendSignal.py b/packages/Python/lldbsuite/test/functionalities/signal/TestSendSignal.py new file mode 100644 index 0000000..971b82a --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/TestSendSignal.py @@ -0,0 +1,105 @@ +"""Test that lldb command 'process signal SIGUSR1' to send a signal to the inferior works.""" + +from __future__ import print_function + + + +import os, time, signal +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class SendSignalTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break inside main(). + self.line = line_number('main.c', 'Put breakpoint here') + + @expectedFailureFreeBSD("llvm.org/pr23318: does not report running state") + @skipIfWindows # Windows does not support signals + def test_with_run_command(self): + """Test that lldb command 'process signal SIGUSR1' sends a signal to the inferior process.""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Now create a breakpoint on main.c by name 'c'. + breakpoint = target.BreakpointCreateByLocation('main.c', self.line) + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + + # Get the breakpoint location from breakpoint after we verified that, + # indeed, it has one location. + location = breakpoint.GetLocationAtIndex(0) + self.assertTrue(location and + location.IsEnabled(), + VALID_BREAKPOINT_LOCATION) + + # Now launch the process, no arguments & do not stop at entry point. + launch_info = lldb.SBLaunchInfo([exe]) + launch_info.SetWorkingDirectory(self.get_process_working_directory()) + + process_listener = lldb.SBListener("signal_test_listener") + launch_info.SetListener(process_listener) + error = lldb.SBError() + process = target.Launch(launch_info, error) + self.assertTrue(process, PROCESS_IS_VALID) + + self.runCmd("process handle -n False -p True -s True SIGUSR1") + + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid(), "We hit the first breakpoint.") + + # After resuming the process, send it a SIGUSR1 signal. + + self.setAsync(True) + + self.assertTrue(process_listener.IsValid(), "Got a good process listener") + + # Disable our breakpoint, we don't want to hit it anymore... + breakpoint.SetEnabled(False) + + # Now continue: + process.Continue() + + # If running remote test, there should be a connected event + if lldb.remote_platform: + self.match_state(process_listener, lldb.eStateConnected) + + self.match_state(process_listener, lldb.eStateRunning) + + # Now signal the process, and make sure it stops: + process.Signal(lldbutil.get_signal_number('SIGUSR1')) + + self.match_state(process_listener, lldb.eStateStopped) + + # Now make sure the thread was stopped with a SIGUSR1: + threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonSignal) + self.assertTrue(len(threads) == 1, "One thread stopped for a signal.") + thread = threads[0] + + self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") + self.assertTrue(thread.GetStopReasonDataAtIndex(0) == lldbutil.get_signal_number('SIGUSR1'), + "The stop signal was SIGUSR1") + + def match_state(self, process_listener, expected_state): + num_seconds = 5 + broadcaster = self.process().GetBroadcaster() + event_type_mask = lldb.SBProcess.eBroadcastBitStateChanged + event = lldb.SBEvent() + got_event = process_listener.WaitForEventForBroadcasterWithType( + num_seconds, broadcaster, event_type_mask, event) + self.assertTrue(got_event, "Got an event") + state = lldb.SBProcess.GetStateFromEvent(event) + self.assertTrue(state == expected_state, + "It was the %s state." % + lldb.SBDebugger_StateAsCString(expected_state)) diff --git a/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/Makefile b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/Makefile new file mode 100644 index 0000000..b09a579 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/TestHandleSegv.py b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/TestHandleSegv.py new file mode 100644 index 0000000..feed5bf --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/TestHandleSegv.py @@ -0,0 +1,43 @@ +"""Test that we can debug inferiors that handle SIGSEGV by themselves""" + +from __future__ import print_function + + + +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil +import re + + +class HandleSegvTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIfWindows # signals do not exist on Windows + @skipIfDarwin + @expectedFailureFreeBSD("llvm.org/pr23699 SIGSEGV is reported as exception, not signal") + def test_inferior_handle_sigsegv(self): + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # launch + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetState(), lldb.eStateStopped) + signo = process.GetUnixSignals().GetSignalNumberFromName("SIGSEGV") + + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) + self.assertTrue(thread and thread.IsValid(), "Thread should be stopped due to a signal") + self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo, "The stop signal was SIGSEGV") + + # Continue until we exit. + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), 0) diff --git a/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/main.c b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/main.c new file mode 100644 index 0000000..27d9b8e --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/handle-segv/main.c @@ -0,0 +1,58 @@ +#include <sys/mman.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +enum { + kMmapSize = 0x1000, + kMagicValue = 47, +}; + +void *address; +volatile sig_atomic_t signaled = 0; + +void handler(int sig) +{ + signaled = 1; + if (munmap(address, kMmapSize) != 0) + { + perror("munmap"); + _exit(5); + } + + void* newaddr = mmap(address, kMmapSize, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_FIXED | MAP_PRIVATE, -1, 0); + if (newaddr != address) + { + fprintf(stderr, "Newly mmaped address (%p) does not equal old address (%p).\n", + newaddr, address); + _exit(6); + } + *(int*)newaddr = kMagicValue; +} + +int main() +{ + if (signal(SIGSEGV, handler) == SIG_ERR) + { + perror("signal"); + return 1; + } + + address = mmap(NULL, kMmapSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (address == MAP_FAILED) + { + perror("mmap"); + return 2; + } + + // This should first trigger a segfault. Our handler will make the memory readable and write + // the magic value into memory. + if (*(int*)address != kMagicValue) + return 3; + + if (! signaled) + return 4; + + return 0; +} diff --git a/packages/Python/lldbsuite/test/functionalities/signal/main.c b/packages/Python/lldbsuite/test/functionalities/signal/main.c new file mode 100644 index 0000000..77e7605 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/main.c @@ -0,0 +1,27 @@ +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +void handler_usr1 (int i) +{ + puts ("got signal usr1"); +} + +void handler_alrm (int i) +{ + puts ("got signal ALRM"); +} + +int main () +{ + int i = 0; + + signal (SIGUSR1, handler_usr1); + signal (SIGALRM, handler_alrm); + + puts ("Put breakpoint here"); + + while (i++ < 20) + sleep (1); +} + diff --git a/packages/Python/lldbsuite/test/functionalities/signal/raise/Makefile b/packages/Python/lldbsuite/test/functionalities/signal/raise/Makefile new file mode 100644 index 0000000..b09a579 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/raise/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py b/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py new file mode 100644 index 0000000..39e7753 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py @@ -0,0 +1,221 @@ +"""Test that we handle inferiors that send signals to themselves""" + +from __future__ import print_function + + + +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil +import re + + +@skipIfWindows # signals do not exist on Windows +class RaiseTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_sigstop(self): + self.build() + self.signal_test('SIGSTOP', False) + # passing of SIGSTOP is not correctly handled, so not testing that scenario: https://llvm.org/bugs/show_bug.cgi?id=23574 + + @skipIfDarwin # darwin does not support real time signals + @skipIfTargetAndroid() + def test_sigsigrtmin(self): + self.build() + self.signal_test('SIGRTMIN', True) + + def launch(self, target, signal): + # launch the process, do not stop at entry point. + process = target.LaunchSimple([signal], None, self.get_process_working_directory()) + self.assertTrue(process, PROCESS_IS_VALID) + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid(), "Thread should be stopped due to a breakpoint") + return process + + def set_handle(self, signal, pass_signal, stop_at_signal, notify_signal): + return_obj = lldb.SBCommandReturnObject() + self.dbg.GetCommandInterpreter().HandleCommand( + "process handle %s -p %s -s %s -n %s" % (signal, pass_signal, stop_at_signal, notify_signal), + return_obj) + self.assertTrue (return_obj.Succeeded() == True, "Setting signal handling failed") + + + def signal_test(self, signal, test_passing): + """Test that we handle inferior raising signals""" + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + lldbutil.run_break_set_by_symbol(self, "main") + + # launch + process = self.launch(target, signal) + signo = process.GetUnixSignals().GetSignalNumberFromName(signal) + + # retrieve default signal disposition + return_obj = lldb.SBCommandReturnObject() + self.dbg.GetCommandInterpreter().HandleCommand("process handle %s " % signal, return_obj) + match = re.match('NAME *PASS *STOP *NOTIFY.*(false|true) *(false|true) *(false|true)', + return_obj.GetOutput(), re.IGNORECASE | re.DOTALL) + if not match: + self.fail('Unable to retrieve default signal disposition.') + default_pass = match.group(1) + default_stop = match.group(2) + default_notify = match.group(3) + + # Make sure we stop at the signal + self.set_handle(signal, "false", "true", "true") + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) + self.assertTrue(thread.IsValid(), "Thread should be stopped due to a signal") + self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo, + "The stop signal was %s" % signal) + + # Continue until we exit. + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), 0) + + # launch again + process = self.launch(target, signal) + + # Make sure we do not stop at the signal. We should still get the notification. + self.set_handle(signal, "false", "false", "true") + self.expect("process continue", substrs=["stopped and restarted", signal]) + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), 0) + + # launch again + process = self.launch(target, signal) + + # Make sure we do not stop at the signal, and we do not get the notification. + self.set_handle(signal, "false", "false", "false") + self.expect("process continue", substrs=["stopped and restarted"], matching=False) + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), 0) + + if not test_passing: + # reset signal handling to default + self.set_handle(signal, default_pass, default_stop, default_notify) + return + + # launch again + process = self.launch(target, signal) + + # Make sure we stop at the signal + self.set_handle(signal, "true", "true", "true") + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) + self.assertTrue(thread.IsValid(), "Thread should be stopped due to a signal") + self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") + self.assertEqual(thread.GetStopReasonDataAtIndex(0), + process.GetUnixSignals().GetSignalNumberFromName(signal), + "The stop signal was %s" % signal) + + # Continue until we exit. The process should receive the signal. + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), signo) + + # launch again + process = self.launch(target, signal) + + # Make sure we do not stop at the signal. We should still get the notification. Process + # should receive the signal. + self.set_handle(signal, "true", "false", "true") + self.expect("process continue", substrs=["stopped and restarted", signal]) + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), signo) + + # launch again + process = self.launch(target, signal) + + # Make sure we do not stop at the signal, and we do not get the notification. Process + # should receive the signal. + self.set_handle(signal, "true", "false", "false") + self.expect("process continue", substrs=["stopped and restarted"], matching=False) + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), signo) + + # reset signal handling to default + self.set_handle(signal, default_pass, default_stop, default_notify) + + @expectedFailureLinux("llvm.org/pr24530") # the signal the inferior generates gets lost + @expectedFailureDarwin("llvm.org/pr24530") # the signal the inferior generates gets lost + def test_restart_bug(self): + """Test that we catch a signal in the edge case where the process receives it while we are + about to interrupt it""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + bkpt = target.BreakpointCreateByName("main") + self.assertTrue(bkpt.IsValid(), VALID_BREAKPOINT) + + # launch the inferior and don't wait for it to stop + self.dbg.SetAsync(True) + error = lldb.SBError() + listener = lldb.SBListener("my listener") + process = target.Launch (listener, + ["SIGSTOP"], # argv + None, # envp + None, # stdin_path + None, # stdout_path + None, # stderr_path + None, # working directory + 0, # launch flags + False, # Stop at entry + error) # error + + self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID) + + event = lldb.SBEvent() + + # Give the child enough time to reach the breakpoint, + # while clearing out all the pending events. + # The last WaitForEvent call will time out after 2 seconds. + while listener.WaitForEvent(2, event): + if self.TraceOn(): + print("Process changing state to:", self.dbg.StateAsCString(process.GetStateFromEvent(event))) + + # now the process should be stopped + self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + self.assertEqual(len(lldbutil.get_threads_stopped_at_breakpoint(process, bkpt)), 1, + "A thread should be stopped at breakpoint") + + # Remove all breakpoints. This makes sure we don't have to single-step over them when we + # resume the process below + target.DeleteAllBreakpoints() + + # resume the process and immediately try to set another breakpoint. When using the remote + # stub, this will trigger a request to stop the process just as it is about to stop + # naturally due to a SIGSTOP signal it raises. Make sure we do not lose this signal. + process.Continue() + self.assertTrue(target.BreakpointCreateByName("handler").IsValid(), VALID_BREAKPOINT) + + # Clear the events again + while listener.WaitForEvent(2, event): + if self.TraceOn(): + print("Process changing state to:", self.dbg.StateAsCString(process.GetStateFromEvent(event))) + + # The process should be stopped due to a signal + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) + self.assertTrue(thread.IsValid(), "Thread should be stopped due to a signal") + self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") + signo = process.GetUnixSignals().GetSignalNumberFromName("SIGSTOP") + self.assertEqual(thread.GetStopReasonDataAtIndex(0), signo, + "The stop signal was %s" % signal) + + # We are done + process.Kill() diff --git a/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c b/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c new file mode 100644 index 0000000..8827174 --- /dev/null +++ b/packages/Python/lldbsuite/test/functionalities/signal/raise/main.c @@ -0,0 +1,42 @@ +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +void handler(int signo) +{ + _exit(signo); +} + +int main (int argc, char *argv[]) +{ +#ifndef __APPLE__ + // Real time signals not supported on apple platforms. + if (signal(SIGRTMIN, handler) == SIG_ERR) + { + perror("signal(SIGRTMIN)"); + return 1; + } +#endif + + if (argc < 2) + { + puts("Please specify a signal to raise"); + return 1; + } + + if (strcmp(argv[1], "SIGSTOP") == 0) + raise(SIGSTOP); +#ifndef __APPLE__ + else if (strcmp(argv[1], "SIGRTMIN") == 0) + raise(SIGRTMIN); +#endif + else + { + printf("Unknown signal: %s\n", argv[1]); + return 1; + } + + return 0; +} + |