diff options
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 000000000000..0d70f2595019 --- /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 000000000000..971b82a7c75d --- /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 000000000000..b09a579159d4 --- /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 000000000000..feed5bfb3c76 --- /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 000000000000..27d9b8e500ab --- /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 000000000000..77e760503410 --- /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 000000000000..b09a579159d4 --- /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 000000000000..39e7753397d1 --- /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 000000000000..8827174e758e --- /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; +} + | 
