[Lldb-commits] [lldb] r215458 - llgs: corrected Linux signal reception notification for SIGABRT, SIGSEGV and their ilk.
Todd Fiala
todd.fiala at gmail.com
Tue Aug 12 10:02:07 PDT 2014
Author: tfiala
Date: Tue Aug 12 12:02:07 2014
New Revision: 215458
URL: http://llvm.org/viewvc/llvm-project?rev=215458&view=rev
Log:
llgs: corrected Linux signal reception notification for SIGABRT, SIGSEGV and their ilk.
Added llgs/debugserver gdb-remote tests around SIGABRT and SIGSEGV signal reception
notification. Found a few bugs in exception signal handling in Linux llgs. Fixed those.
Added:
lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/
lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/Makefile
lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteAbort.py
lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteSegFault.py
lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/main.cpp
Modified:
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=215458&r1=215457&r2=215458&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Tue Aug 12 12:02:07 2014
@@ -2154,77 +2154,78 @@ NativeProcessLinux::MonitorSignal(const
info->si_pid,
(info->si_pid == getpid ()) ? "is monitor" : "is not monitor",
pid);
+ }
- if ((info->si_pid == 0) && info->si_code == SI_USER)
+ // Check for new thread notification.
+ if ((info->si_pid == 0) && (info->si_code == SI_USER))
+ {
+ // A new thread creation is being signaled. This is one of two parts that come in
+ // a non-deterministic order. pid is the thread id.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": new thread notification",
+ __FUNCTION__, GetID (), pid);
+
+ // Did we already create the thread?
+ bool already_tracked = false;
+ thread_sp = GetOrCreateThread (pid, already_tracked);
+ assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+ // If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
+ if (already_tracked)
+ {
+ // We can now resume this thread up since it is fully created.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+ Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+ }
+ else
{
- // A new thread creation is being signaled. This is one of two parts that come in
- // a non-deterministic order. pid is the thread id.
- if (log)
- log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": new thread notification",
- __FUNCTION__, GetID (), pid);
-
- // Did we already create the thread?
- bool already_tracked = false;
- thread_sp = GetOrCreateThread (pid, already_tracked);
- assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
-
- // If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
- if (already_tracked)
- {
- // We can now resume this thread up since it is fully created.
- reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
- Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
- }
- else
- {
- // Mark the thread as currently launching. Need to wait for SIGTRAP clone on the main thread before
- // this thread is ready to go.
- reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
- }
+ // Mark the thread as currently launching. Need to wait for SIGTRAP clone on the main thread before
+ // this thread is ready to go.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
}
- else if (info->si_pid == getpid () && (signo == SIGSTOP))
+
+ // Done handling.
+ return;
+ }
+
+ // Check for thread stop notification.
+ if ((info->si_pid == getpid ()) && (info->si_code == SI_TKILL) && (signo == SIGSTOP))
+ {
+ // This is a tgkill()-based stop.
+ if (thread_sp)
{
- // This is a tgkill()-based stop.
- if (thread_sp)
- {
- // An inferior thread just stopped. Mark it as such.
- reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
- SetCurrentThreadID (thread_sp->GetID ());
+ // An inferior thread just stopped. Mark it as such.
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+ SetCurrentThreadID (thread_sp->GetID ());
- // Remove this tid from the wait-for-stop set.
- Mutex::Locker locker (m_wait_for_stop_tids_mutex);
+ // Remove this tid from the wait-for-stop set.
+ Mutex::Locker locker (m_wait_for_stop_tids_mutex);
- auto removed_count = m_wait_for_stop_tids.erase (thread_sp->GetID ());
- if (removed_count < 1)
- {
- log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": tgkill()-stopped thread not in m_wait_for_stop_tids",
- __FUNCTION__, GetID (), thread_sp->GetID ());
+ auto removed_count = m_wait_for_stop_tids.erase (thread_sp->GetID ());
+ if (removed_count < 1)
+ {
+ log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": tgkill()-stopped thread not in m_wait_for_stop_tids",
+ __FUNCTION__, GetID (), thread_sp->GetID ());
- }
+ }
- // If this is the last thread in the m_wait_for_stop_tids, we need to notify
- // the delegate that a stop has occurred now that every thread that was supposed
- // to stop has stopped.
- if (m_wait_for_stop_tids.empty ())
+ // If this is the last thread in the m_wait_for_stop_tids, we need to notify
+ // the delegate that a stop has occurred now that every thread that was supposed
+ // to stop has stopped.
+ if (m_wait_for_stop_tids.empty ())
+ {
+ if (log)
{
- if (log)
- {
- log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", setting process state to stopped now that all tids marked for stop have completed",
- __FUNCTION__,
- GetID (),
- pid);
- }
- SetState (StateType::eStateStopped, true);
+ log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", setting process state to stopped now that all tids marked for stop have completed",
+ __FUNCTION__,
+ GetID (),
+ pid);
}
+ SetState (StateType::eStateStopped, true);
}
}
- else
- {
- // Hmm, not sure what to do with this.
- if (log)
- log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " unsure how to handle SI_KILL or SI_USER signal", __FUNCTION__, GetID ());
- }
+ // Done handling.
return;
}
@@ -2265,38 +2266,40 @@ NativeProcessLinux::MonitorSignal(const
}
break;
+ case SIGABRT:
case SIGILL:
- {
- // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
- // Can get the reason from here.
- // ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
- // FIXME save the crash reason
- SetState (StateType::eStateCrashed, true);
- }
- break;
-
case SIGFPE:
- {
- // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
- // Can get the crash reason from below.
- // ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
- // FIXME save the crash reason
- SetState (StateType::eStateCrashed, true);
- }
- break;
-
case SIGBUS:
{
- // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
- // Can get the crash reason from below.
- // ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
- // FIXME save the crash reason
- SetState (StateType::eStateCrashed);
+ // Break these out into separate cases once I have more data for each type of signal.
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ if (!exited)
+ {
+ // This is just a pre-signal-delivery notification of the incoming signal.
+ // Send a stop to the debugger.
+ if (thread_sp)
+ {
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+ SetCurrentThreadID (thread_sp->GetID ());
+ }
+ SetState (StateType::eStateStopped, true);
+ }
+ else
+ {
+ if (thread_sp)
+ {
+ // FIXME figure out how to report exit by signal correctly.
+ const uint64_t exception_type = static_cast<uint64_t> (SIGABRT);
+ reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (exception_type, fault_addr);
+ }
+ SetState (StateType::eStateCrashed, true);
+ }
}
break;
default:
- // FIXME Stop all threads here.
+ if (log)
+ log->Printf ("NativeProcessLinux::%s unhandled signal %s (%d)", __FUNCTION__, GetUnixSignals ().GetSignalAsCString (signo), signo);
break;
}
}
Modified: lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py?rev=215458&r1=215457&r2=215458&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py Tue Aug 12 12:02:07 2014
@@ -284,11 +284,12 @@ class GdbRemoteTestCaseBase(TestBase):
raise Exception("failed to create a socket to the launched debug monitor after %d tries" % attempts)
- def launch_process_for_attach(self,inferior_args=None, sleep_seconds=3):
+ def launch_process_for_attach(self,inferior_args=None, sleep_seconds=3, exe_path=None):
# We're going to start a child process that the debug monitor stub can later attach to.
# This process needs to be started so that it just hangs around for a while. We'll
# have it sleep.
- exe_path = os.path.abspath("a.out")
+ if not exe_path:
+ exe_path = os.path.abspath("a.out")
args = [exe_path]
if inferior_args:
@@ -298,7 +299,7 @@ class GdbRemoteTestCaseBase(TestBase):
return subprocess.Popen(args)
- def prep_debug_monitor_and_inferior(self, inferior_args=None, inferior_sleep_seconds=3):
+ def prep_debug_monitor_and_inferior(self, inferior_args=None, inferior_sleep_seconds=3, inferior_exe_path=None):
"""Prep the debug monitor, the inferior, and the expected packet stream.
Handle the separate cases of using the debug monitor in attach-to-inferior mode
@@ -323,7 +324,7 @@ class GdbRemoteTestCaseBase(TestBase):
if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY:
# Launch the process that we'll use as the inferior.
- inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds)
+ inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds, exe_path=inferior_exe_path)
self.assertIsNotNone(inferior)
self.assertTrue(inferior.pid > 0)
if self._inferior_startup == self._STARTUP_ATTACH:
@@ -336,7 +337,9 @@ class GdbRemoteTestCaseBase(TestBase):
if self._inferior_startup == self._STARTUP_LAUNCH:
# Build launch args
- launch_args = [os.path.abspath('a.out')]
+ if not inferior_exe_path:
+ inferior_exe_path = os.path.abspath("a.out")
+ launch_args = [inferior_exe_path]
if inferior_args:
launch_args.extend(inferior_args)
Added: lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/Makefile?rev=215458&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/Makefile (added)
+++ lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/Makefile Tue Aug 12 12:02:07 2014
@@ -0,0 +1,8 @@
+LEVEL = ../../../make
+
+CFLAGS_EXTRAS := -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS -std=c++11
+# LD_EXTRAS := -lpthread
+CXX_SOURCES := main.cpp
+MAKE_DSYM :=NO
+
+include $(LEVEL)/Makefile.rules
Added: lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteAbort.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteAbort.py?rev=215458&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteAbort.py (added)
+++ lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteAbort.py Tue Aug 12 12:02:07 2014
@@ -0,0 +1,45 @@
+import unittest2
+
+# Add the directory above ours to the python library path since we
+# will import from there.
+import os.path
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
+
+import gdbremote_testcase
+import signal
+from lldbtest import *
+
+class TestGdbRemoteAbort(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ def inferior_abort_received(self):
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["abort"])
+ self.assertIsNotNone(procs)
+
+ self.test_sequence.add_log_lines([
+ "read packet: $vCont;c#00",
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture":{ 1:"hex_exit_code"} },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ hex_exit_code = context.get("hex_exit_code")
+ self.assertIsNotNone(hex_exit_code)
+ self.assertEquals(int(hex_exit_code, 16), signal.SIGABRT)
+
+ @debugserver_test
+ @dsym_test
+ def test_inferior_abort_received_debugserver_dsym(self):
+ self.init_debugserver_test()
+ self.buildDsym()
+ self.inferior_abort_received()
+
+ @llgs_test
+ @dwarf_test
+ def test_inferior_abort_received_llgs_dwarf(self):
+ self.init_llgs_test()
+ self.buildDwarf()
+ self.inferior_abort_received()
+
Added: lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteSegFault.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteSegFault.py?rev=215458&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteSegFault.py (added)
+++ lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/TestGdbRemoteSegFault.py Tue Aug 12 12:02:07 2014
@@ -0,0 +1,46 @@
+import unittest2
+
+# Add the directory above ours to the python library path since we
+# will import from there.
+import os.path
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
+
+import gdbremote_testcase
+# import signal
+from lldbtest import *
+
+class TestGdbRemoteSegFault(gdbremote_testcase.GdbRemoteTestCaseBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ GDB_REMOTE_STOP_CODE_BAD_ACCESS = 0x91
+
+ def inferior_seg_fault_received(self):
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["segfault"])
+ self.assertIsNotNone(procs)
+
+ self.test_sequence.add_log_lines([
+ "read packet: $vCont;c#00",
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture":{ 1:"hex_exit_code"} },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ hex_exit_code = context.get("hex_exit_code")
+ self.assertIsNotNone(hex_exit_code)
+ self.assertEquals(int(hex_exit_code, 16), self.GDB_REMOTE_STOP_CODE_BAD_ACCESS)
+
+ @debugserver_test
+ @dsym_test
+ def test_inferior_seg_fault_received_debugserver_dsym(self):
+ self.init_debugserver_test()
+ self.buildDsym()
+ self.inferior_seg_fault_received()
+
+ @llgs_test
+ @dwarf_test
+ def test_inferior_seg_fault_received_llgs_dwarf(self):
+ self.init_llgs_test()
+ self.buildDwarf()
+ self.inferior_seg_fault_received()
Added: lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/main.cpp?rev=215458&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/main.cpp (added)
+++ lldb/trunk/test/tools/lldb-gdbserver/inferior-crash/main.cpp Tue Aug 12 12:02:07 2014
@@ -0,0 +1,39 @@
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+namespace
+{
+ const char *const SEGFAULT_COMMAND = "segfault";
+ const char *const ABORT_COMMAND = "abort";
+}
+
+int main (int argc, char **argv)
+{
+ if (argc < 2)
+ {
+ std::cout << "expected at least one command provided on the command line" << std::endl;
+ }
+
+ // Process command line args.
+ for (int i = 1; i < argc; ++i)
+ {
+ const char *const command = argv[i];
+ if (std::strstr (command, SEGFAULT_COMMAND))
+ {
+ // Perform a null pointer access.
+ int *const null_int_ptr = nullptr;
+ *null_int_ptr = 0xDEAD;
+ }
+ else if (std::strstr (command, ABORT_COMMAND))
+ {
+ std::abort();
+ }
+ else
+ {
+ std::cout << "Unsupported command: " << command << std::endl;
+ }
+ }
+
+ return 0;
+}
More information about the lldb-commits
mailing list