aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Interpreter/OptionValueString.h5
-rw-r--r--lldb/include/lldb/Target/Platform.h2
-rw-r--r--lldb/include/lldb/Utility/StringExtractorGDBRemote.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp129
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h14
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td9
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp21
-rw-r--r--lldb/source/Target/Platform.cpp4
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp2
-rw-r--r--lldb/test/API/macosx/ignore_exceptions/Makefile4
-rw-r--r--lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py60
-rw-r--r--lldb/test/API/macosx/ignore_exceptions/main.c27
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp17
-rw-r--r--lldb/tools/debugserver/source/DNB.h8
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachException.cpp47
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachException.h1
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h11
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.mm32
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.h4
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.mm11
-rw-r--r--lldb/tools/debugserver/source/RNBContext.cpp15
-rw-r--r--lldb/tools/debugserver/source/RNBContext.h12
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp47
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h2
-rw-r--r--lldb/tools/debugserver/source/debugserver.cpp6
25 files changed, 444 insertions, 47 deletions
diff --git a/lldb/include/lldb/Interpreter/OptionValueString.h b/lldb/include/lldb/Interpreter/OptionValueString.h
index be42deb..820656d 100644
--- a/lldb/include/lldb/Interpreter/OptionValueString.h
+++ b/lldb/include/lldb/Interpreter/OptionValueString.h
@@ -109,6 +109,11 @@ public:
bool IsCurrentValueEmpty() const { return m_current_value.empty(); }
bool IsDefaultValueEmpty() const { return m_default_value.empty(); }
+
+ void SetValidator(ValidatorCallback validator, void *baton = nullptr) {
+ m_validator = validator;
+ m_validator_baton = baton;
+ }
protected:
std::string m_current_value;
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index 8b8ca62..6032008 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -847,6 +847,8 @@ public:
}
virtual CompilerType GetSiginfoType(const llvm::Triple &triple);
+
+ virtual Args GetExtraStartupCommands();
protected:
/// Create a list of ArchSpecs with the given OS and a architectures. The
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 459adae..f10bfb1 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -174,6 +174,7 @@ public:
eServerPacketType_QMemTags, // write memory tags
eServerPacketType_qLLDBSaveCore,
+ eServerPacketType_QSetIgnoredExceptions
};
ServerPacketType GetServerPacketType() const;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index cac9c67..455b760 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -19,11 +19,15 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/XML.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/Options.h"
#include "lldb/Symbol/LocateSymbolFile.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
@@ -48,12 +52,137 @@
using namespace lldb;
using namespace lldb_private;
+static Status ExceptionMaskValidator(const char *string, void *unused) {
+ Status error;
+ llvm::StringRef str_ref(string);
+ llvm::SmallVector<llvm::StringRef> candidates;
+ str_ref.split(candidates, '|');
+ for (auto candidate : candidates) {
+ if (!(candidate == "EXC_BAD_ACCESS"
+ || candidate == "EXC_BAD_INSTRUCTION"
+ || candidate == "EXC_ARITHMETIC"
+ || candidate == "EXC_RESOURCE"
+ || candidate == "EXC_GUARD")) {
+ error.SetErrorStringWithFormat("invalid exception type: '%s'",
+ candidate.str().c_str());
+ return error;
+ }
+ }
+ return {};
+}
+
/// Destructor.
///
/// The destructor is virtual since this class is designed to be
/// inherited from by the plug-in instance.
PlatformDarwin::~PlatformDarwin() = default;
+// Static Variables
+static uint32_t g_initialize_count = 0;
+
+void PlatformDarwin::Initialize() {
+ Platform::Initialize();
+
+ if (g_initialize_count++ == 0) {
+ PluginManager::RegisterPlugin(PlatformDarwin::GetPluginNameStatic(),
+ PlatformDarwin::GetDescriptionStatic(),
+ PlatformDarwin::CreateInstance,
+ PlatformDarwin::DebuggerInitialize);
+ }
+}
+
+void PlatformDarwin::Terminate() {
+ if (g_initialize_count > 0) {
+ if (--g_initialize_count == 0) {
+ PluginManager::UnregisterPlugin(PlatformDarwin::CreateInstance);
+ }
+ }
+
+ Platform::Terminate();
+}
+
+llvm::StringRef PlatformDarwin::GetDescriptionStatic() {
+ return "Darwin platform plug-in.";
+}
+
+PlatformSP PlatformDarwin::CreateInstance(bool force, const ArchSpec *arch) {
+ // We only create subclasses of the PlatformDarwin plugin.
+ return PlatformSP();
+}
+
+#define LLDB_PROPERTIES_platformdarwin
+#include "PlatformMacOSXProperties.inc"
+
+#define LLDB_PROPERTIES_platformdarwin
+enum {
+#include "PlatformMacOSXPropertiesEnum.inc"
+};
+
+class PlatformDarwinProperties : public Properties {
+public:
+ static ConstString &GetSettingName() {
+ static ConstString g_setting_name("darwin");
+ return g_setting_name;
+ }
+
+ PlatformDarwinProperties() : Properties() {
+ m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
+ m_collection_sp->Initialize(g_platformdarwin_properties);
+ }
+
+ ~PlatformDarwinProperties() override = default;
+
+ const char *GetIgnoredExceptions() const {
+ const uint32_t idx = ePropertyIgnoredExceptions;
+ const OptionValueString *option_value =
+ m_collection_sp->GetPropertyAtIndexAsOptionValueString(
+ NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+ }
+
+ OptionValueString *GetIgnoredExceptionValue() {
+ const uint32_t idx = ePropertyIgnoredExceptions;
+ OptionValueString *option_value =
+ m_collection_sp->GetPropertyAtIndexAsOptionValueString(
+ NULL, false, idx);
+ assert(option_value);
+ return option_value;
+ }
+};
+
+static PlatformDarwinProperties &GetGlobalProperties() {
+ static PlatformDarwinProperties g_settings;
+ return g_settings;
+}
+
+void PlatformDarwin::DebuggerInitialize(
+ lldb_private::Debugger &debugger) {
+ if (!PluginManager::GetSettingForPlatformPlugin(
+ debugger, PlatformDarwinProperties::GetSettingName())) {
+ const bool is_global_setting = false;
+ PluginManager::CreateSettingForPlatformPlugin(
+ debugger, GetGlobalProperties().GetValueProperties(),
+ ConstString("Properties for the Darwin platform plug-in."),
+ is_global_setting);
+ OptionValueString *value = GetGlobalProperties().GetIgnoredExceptionValue();
+ value->SetValidator(ExceptionMaskValidator);
+ }
+}
+
+Args
+PlatformDarwin::GetExtraStartupCommands() {
+ std::string ignored_exceptions
+ = GetGlobalProperties().GetIgnoredExceptions();
+ if (ignored_exceptions.empty())
+ return {};
+ Args ret_args;
+ std::string packet = "QSetIgnoredExceptions:";
+ packet.append(ignored_exceptions);
+ ret_args.AppendArgument(packet);
+ return ret_args;
+}
+
lldb_private::Status
PlatformDarwin::PutFile(const lldb_private::FileSpec &source,
const lldb_private::FileSpec &destination, uint32_t uid,
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
index b4c791e..334410e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -48,6 +48,18 @@ public:
~PlatformDarwin() override;
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+ static void DebuggerInitialize(lldb_private::Debugger &debugger);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "darwin"; }
+
+ static llvm::StringRef GetDescriptionStatic();
+
Status PutFile(const FileSpec &source, const FileSpec &destination,
uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override;
@@ -96,6 +108,8 @@ public:
FileSpec LocateExecutable(const char *basename) override;
Status LaunchProcess(ProcessLaunchInfo &launch_info) override;
+
+ Args GetExtraStartupCommands() override;
static std::tuple<llvm::VersionTuple, llvm::StringRef>
ParseVersionBuildDir(llvm::StringRef str);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
index 39e9641..f0d305a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td
@@ -5,3 +5,12 @@ let Definition = "platformdarwinkernel" in {
DefaultStringValue<"">,
Desc<"Directories/KDKs to search for kexts in when starting a kernel debug session.">;
}
+
+let Definition = "platformdarwin" in {
+ def IgnoredExceptions: Property<"ignored-exceptions", "String">,
+ DefaultStringValue<"">,
+ Desc<"List the mach exceptions to ignore, separated by '|' "
+ "(e.g. 'EXC_BAD_ACCESS|EXC_BAD_INSTRUCTION'). "
+ "lldb will instead stop on the BSD signal the exception was converted "
+ "into, if there is one.">;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index f7e2188..a00961d 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -954,12 +954,23 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
m_gdb_comm.GetVAttachOrWaitSupported();
m_gdb_comm.EnableErrorStringInPacket();
- size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
- for (size_t idx = 0; idx < num_cmds; idx++) {
- StringExtractorGDBRemote response;
- m_gdb_comm.SendPacketAndWaitForResponse(
- GetExtraStartupCommands().GetArgumentAtIndex(idx), response);
+ // First dispatch any commands from the platform:
+ auto handle_cmds = [&] (const Args &args) -> void {
+ for (const Args::ArgEntry &entry : args) {
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse(
+ entry.c_str(), response);
+ }
+ };
+
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (platform_sp) {
+ handle_cmds(platform_sp->GetExtraStartupCommands());
}
+
+ // Then dispatch any process commands:
+ handle_cmds(GetExtraStartupCommands());
+
return error;
}
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 1976aa6..559f766 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1945,6 +1945,10 @@ CompilerType Platform::GetSiginfoType(const llvm::Triple& triple) {
return CompilerType();
}
+Args Platform::GetExtraStartupCommands() {
+ return {};
+}
+
PlatformSP PlatformList::GetOrCreate(llvm::StringRef name) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const PlatformSP &platform_sp : m_platforms) {
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index d6bbf71..f1e54b3 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -126,6 +126,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_QSetWorkingDir;
if (PACKET_STARTS_WITH("QSetLogging:"))
return eServerPacketType_QSetLogging;
+ if (PACKET_STARTS_WITH("QSetIgnoredExceptions"))
+ return eServerPacketType_QSetIgnoredExceptions;
if (PACKET_STARTS_WITH("QSetMaxPacketSize:"))
return eServerPacketType_QSetMaxPacketSize;
if (PACKET_STARTS_WITH("QSetMaxPayloadSize:"))
diff --git a/lldb/test/API/macosx/ignore_exceptions/Makefile b/lldb/test/API/macosx/ignore_exceptions/Makefile
new file mode 100644
index 0000000..695335e
--- /dev/null
+++ b/lldb/test/API/macosx/ignore_exceptions/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -std=c99
+
+include Makefile.rules
diff --git a/lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py b/lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py
new file mode 100644
index 0000000..378ce7a
--- /dev/null
+++ b/lldb/test/API/macosx/ignore_exceptions/TestIgnoredExceptions.py
@@ -0,0 +1,60 @@
+"""
+Test that by turning off EXC_BAD_ACCESS catching, we can
+debug into and out of a signal handler.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class TestDarwinSignalHandlers(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ NO_DEBUG_INFO_TESTCASE = True
+
+ @skipUnlessDarwin
+ def test_ignored_thread(self):
+ """It isn't possible to convert an EXC_BAD_ACCESS to a signal when
+ running under the debugger, which makes debugging SIGBUS handlers
+ and so forth difficult. This test sends QIgnoreExceptions and that
+ should get us into the signal handler and out again. """
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ self.suspended_thread_test()
+
+ def suspended_thread_test(self):
+ # Make sure that we don't accept bad values:
+ self.match("settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_AXESS", "EXC_BAD_AXESS", error=True)
+ # Now set ourselves to ignore some exceptions. The test depends on ignoring EXC_BAD_ACCESS, but I passed a couple
+ # to make sure they parse:
+ self.runCmd("settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_ACCESS|EXC_ARITHMETIC")
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
+ "Stop here to get things going", self.main_source_file)
+
+ sig_bkpt = target.BreakpointCreateBySourceRegex("stop here in the signal handler",
+ self.main_source_file)
+ self.assertEqual(sig_bkpt.GetNumLocations(), 1, "Found sig handler breakpoint")
+ return_bkpt = target.BreakpointCreateBySourceRegex("Break here to make sure we got past the signal handler",
+ self.main_source_file)
+ self.assertEqual(return_bkpt.GetNumLocations(), 1, "Found return breakpoint")
+ # Now continue, and we should stop with a stop reason of SIGBUS:
+ process.Continue()
+ self.assertEqual(process.state, lldb.eStateStopped, "Stopped after continue to SIGBUS")
+ self.assertEqual(thread.stop_reason, lldb.eStopReasonSignal)
+ self.assertEqual(thread.GetStopReasonDataAtIndex(0), 10, "Got a SIGBUS")
+
+ # Now when we continue, we'll find our way into the signal handler:
+ threads = lldbutil.continue_to_breakpoint(process, sig_bkpt)
+ self.assertEqual(len(threads), 1, "Stopped at sig breakpoint")
+
+ threads = lldbutil.continue_to_breakpoint(process, return_bkpt)
+ self.assertEqual(len(threads), 1, "Stopped at return breakpoint")
+
+ # Make sure we really changed the value:
+
+ process.Continue()
+ self.assertEqual(process.state, lldb.eStateExited, "Process exited")
+ self.assertEqual(process.exit_state, 20, "Got the right exit status")
+
diff --git a/lldb/test/API/macosx/ignore_exceptions/main.c b/lldb/test/API/macosx/ignore_exceptions/main.c
new file mode 100644
index 0000000..7b89dbf
--- /dev/null
+++ b/lldb/test/API/macosx/ignore_exceptions/main.c
@@ -0,0 +1,27 @@
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+int g_ints[] = {10, 20, 30, 40, 50, 60};
+
+void
+saction_handler(int signo, siginfo_t info, void *baton) {
+ printf("Got into handler.\n");
+ mprotect(g_ints, sizeof(g_ints), PROT_READ|PROT_WRITE); // stop here in the signal handler
+ g_ints[0] = 20;
+}
+int
+main()
+{
+ mprotect(g_ints, 10*sizeof(int) , PROT_NONE);
+ struct sigaction my_action;
+ sigemptyset(&my_action.sa_mask);
+ my_action.sa_handler = (void (*)(int)) saction_handler;
+ my_action.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGBUS, &my_action, NULL); // Stop here to get things going.
+ int local_value = g_ints[1];
+ return local_value; // Break here to make sure we got past the signal handler
+}
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index c037c48..ebb7607 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -352,7 +352,7 @@ nub_process_t DNBProcessLaunch(
pid_t pid = processSP->LaunchForDebug(
path, argv, envp, working_directory, stdin_path, stdout_path,
stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data,
- ctx->GetUnmaskSignals(), launch_err);
+ ctx->GetIgnoredExceptions(), launch_err);
if (err_str) {
*err_str = '\0';
if (launch_err.Fail()) {
@@ -412,7 +412,8 @@ nub_process_t DNBProcessGetPIDByName(const char *name) {
}
nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
- bool unmask_signals, char *err_str,
+ const RNBContext::IgnoredExceptions
+ &ignored_exceptions, char *err_str,
size_t err_len) {
if (err_str && err_len > 0)
err_str[0] = '\0';
@@ -434,11 +435,13 @@ nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
}
return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
- unmask_signals, err_str, err_len);
+ ignored_exceptions, err_str, err_len);
}
nub_process_t DNBProcessAttach(nub_process_t attach_pid,
- struct timespec *timeout, bool unmask_signals,
+ struct timespec *timeout,
+ const RNBContext::IgnoredExceptions
+ &ignored_exceptions,
char *err_str, size_t err_len) {
if (err_str && err_len > 0)
err_str[0] = '\0';
@@ -487,7 +490,8 @@ nub_process_t DNBProcessAttach(nub_process_t attach_pid,
DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
attach_pid);
pid =
- processSP->AttachForDebug(attach_pid, unmask_signals, err_str, err_len);
+ processSP->AttachForDebug(attach_pid, ignored_exceptions, err_str,
+ err_len);
if (pid != INVALID_NUB_PROCESS) {
bool res = AddProcessToMap(pid, processSP);
@@ -782,7 +786,8 @@ DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name,
DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
waitfor_process_name, waitfor_pid);
waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime,
- ctx->GetUnmaskSignals(), err_str, err_len);
+ ctx->GetIgnoredExceptions(), err_str,
+ err_len);
}
bool success = waitfor_pid != INVALID_NUB_PROCESS;
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index c04249d..f29078c 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -51,10 +51,14 @@ nub_process_t DNBProcessLaunch(
nub_process_t DNBProcessGetPIDByName(const char *name);
nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout,
- bool unmask_signals, char *err_str,
+ const RNBContext::IgnoredExceptions
+ &ignored_exceptions,
+ char *err_str,
size_t err_len);
nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
- bool unmask_signals, char *err_str,
+ const RNBContext::IgnoredExceptions
+ &ignored_exceptions,
+ char *err_str,
size_t err_len);
nub_process_t DNBProcessAttachWait(RNBContext *ctx, const char *wait_name,
bool ignore_existing,
diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.cpp b/lldb/tools/debugserver/source/MacOSX/MachException.cpp
index db154d1..b27ef60 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachException.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachException.cpp
@@ -512,3 +512,50 @@ const char *MachException::Name(exception_type_t exc_type) {
}
return NULL;
}
+
+// Returns the exception mask for a given exception name.
+// 0 is not a legit mask, so we return that in the case of an error.
+exception_mask_t MachException::ExceptionMask(const char *name) {
+ static const char *exception_prefix = "EXC_";
+ static const int prefix_len = strlen(exception_prefix);
+
+ // All mach exceptions start with this prefix:
+ if (strstr(name, exception_prefix) != name)
+ return 0;
+
+ name += prefix_len;
+ std::string name_str = name;
+ if (name_str == "BAD_ACCESS")
+ return EXC_MASK_BAD_ACCESS;
+ if (name_str == "BAD_INSTRUCTION")
+ return EXC_MASK_BAD_INSTRUCTION;
+ if (name_str == "ARITHMETIC")
+ return EXC_MASK_ARITHMETIC;
+ if (name_str == "EMULATION")
+ return EXC_MASK_EMULATION;
+ if (name_str == "SOFTWARE")
+ return EXC_MASK_SOFTWARE;
+ if (name_str == "BREAKPOINT")
+ return EXC_MASK_BREAKPOINT;
+ if (name_str == "SYSCALL")
+ return EXC_MASK_SYSCALL;
+ if (name_str == "MACH_SYSCALL")
+ return EXC_MASK_MACH_SYSCALL;
+ if (name_str == "RPC_ALERT")
+ return EXC_MASK_RPC_ALERT;
+#ifdef EXC_CRASH
+ if (name_str == "CRASH")
+ return EXC_MASK_CRASH;
+#endif
+ if (name_str == "RESOURCE")
+ return EXC_MASK_RESOURCE;
+#ifdef EXC_GUARD
+ if (name_str == "GUARD")
+ return EXC_MASK_GUARD;
+#endif
+#ifdef EXC_CORPSE_NOTIFY
+ if (name_str == "CORPSE_NOTIFY")
+ return EXC_MASK_CORPSE_NOTIFY;
+#endif
+ return 0;
+}
diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.h b/lldb/tools/debugserver/source/MacOSX/MachException.h
index e6cb317..bf9771e 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachException.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachException.h
@@ -127,6 +127,7 @@ public:
uint8_t flags; // Action flags describing what to do with the exception
};
static const char *Name(exception_type_t exc_type);
+ static exception_mask_t ExceptionMask(const char *name);
};
#endif
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
index 33c3d62..3b250bf 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -34,6 +34,7 @@
#include "PThreadCondition.h"
#include "PThreadEvent.h"
#include "PThreadMutex.h"
+#include "RNBContext.h"
#include "ThreadInfo.h"
class DNBThreadResumeActions;
@@ -78,14 +79,17 @@ public:
};
// Child process control
- pid_t AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
+ pid_t AttachForDebug(pid_t pid,
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
+ char *err_str,
size_t err_len);
pid_t LaunchForDebug(const char *path, char const *argv[], char const *envp[],
const char *working_directory, const char *stdin_path,
const char *stdout_path, const char *stderr_path,
bool no_stdio, nub_launch_flavor_t launch_flavor,
int disable_aslr, const char *event_data,
- bool unmask_signals, DNBError &err);
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
+ DNBError &err);
static uint32_t GetCPUTypeForLocalProcess(pid_t pid);
static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[],
@@ -109,7 +113,8 @@ public:
pid_t BoardServiceLaunchForDebug(const char *app_bundle_path,
char const *argv[], char const *envp[],
bool no_stdio, bool disable_aslr,
- const char *event_data, bool unmask_signals,
+ const char *event_data,
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
DNBError &launch_err);
pid_t BoardServiceForkChildForPTraceDebugging(
const char *path, char const *argv[], char const *envp[], bool no_stdio,
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
index 9ab33cc..b41cb22 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -2590,8 +2590,11 @@ void *MachProcess::ProfileThread(void *arg) {
return NULL;
}
-pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
- size_t err_len) {
+pid_t MachProcess::AttachForDebug(
+ pid_t pid,
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
+ char *err_str,
+ size_t err_len) {
// Clear out and clean up from any current state
Clear();
if (pid != 0) {
@@ -2608,7 +2611,7 @@ pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str,
SetState(eStateAttaching);
m_pid = pid;
- if (!m_task.StartExceptionThread(unmask_signals, err)) {
+ if (!m_task.StartExceptionThread(ignored_exceptions, err)) {
const char *err_cstr = err.AsString();
::snprintf(err_str, err_len, "%s",
err_cstr ? err_cstr : "unable to start the exception thread");
@@ -3112,7 +3115,9 @@ pid_t MachProcess::LaunchForDebug(
// working directory for inferior to this
const char *stdin_path, const char *stdout_path, const char *stderr_path,
bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr,
- const char *event_data, bool unmask_signals, DNBError &launch_err) {
+ const char *event_data,
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
+ DNBError &launch_err) {
// Clear out and clean up from any current state
Clear();
@@ -3138,7 +3143,7 @@ pid_t MachProcess::LaunchForDebug(
m_flags |= (eMachProcessFlagsUsingFBS | eMachProcessFlagsBoardCalculated);
if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
no_stdio, disable_aslr, event_data,
- unmask_signals, launch_err) != 0)
+ ignored_exceptions, launch_err) != 0)
return m_pid; // A successful SBLaunchForDebug() returns and assigns a
// non-zero m_pid.
}
@@ -3152,7 +3157,7 @@ pid_t MachProcess::LaunchForDebug(
m_flags |= (eMachProcessFlagsUsingBKS | eMachProcessFlagsBoardCalculated);
if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
no_stdio, disable_aslr, event_data,
- unmask_signals, launch_err) != 0)
+ ignored_exceptions, launch_err) != 0)
return m_pid; // A successful SBLaunchForDebug() returns and assigns a
// non-zero m_pid.
}
@@ -3164,7 +3169,7 @@ pid_t MachProcess::LaunchForDebug(
std::string app_bundle_path = GetAppBundle(path);
if (!app_bundle_path.empty()) {
if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
- disable_aslr, unmask_signals, launch_err) != 0)
+ disable_aslr, ignored_exceptions, launch_err) != 0)
return m_pid; // A successful SBLaunchForDebug() returns and assigns a
// non-zero m_pid.
}
@@ -3198,7 +3203,7 @@ pid_t MachProcess::LaunchForDebug(
for (i = 0; (arg = argv[i]) != NULL; i++)
m_args.push_back(arg);
- m_task.StartExceptionThread(unmask_signals, launch_err);
+ m_task.StartExceptionThread(ignored_exceptions, launch_err);
if (launch_err.Fail()) {
if (launch_err.AsString() == NULL)
launch_err.SetErrorString("unable to start the exception thread");
@@ -3566,7 +3571,9 @@ static CFStringRef CopyBundleIDForPath(const char *app_bundle_path,
pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[],
char const *envp[], bool no_stdio,
- bool disable_aslr, bool unmask_signals,
+ bool disable_aslr,
+ const RNBContext::IgnoredExceptions
+ &ignored_exceptions,
DNBError &launch_err) {
// Clear out and clean up from any current state
Clear();
@@ -3583,7 +3590,7 @@ pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[],
char const *arg;
for (i = 0; (arg = argv[i]) != NULL; i++)
m_args.push_back(arg);
- m_task.StartExceptionThread(unmask_signals, launch_err);
+ m_task.StartExceptionThread(ignored_exceptions, launch_err);
if (launch_err.Fail()) {
if (launch_err.AsString() == NULL)
@@ -3784,7 +3791,8 @@ pid_t MachProcess::SBForkChildForPTraceDebugging(
#if defined(WITH_BKS) || defined(WITH_FBS)
pid_t MachProcess::BoardServiceLaunchForDebug(
const char *path, char const *argv[], char const *envp[], bool no_stdio,
- bool disable_aslr, const char *event_data, bool unmask_signals,
+ bool disable_aslr, const char *event_data,
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
DNBError &launch_err) {
DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
@@ -3798,7 +3806,7 @@ pid_t MachProcess::BoardServiceLaunchForDebug(
char const *arg;
for (i = 0; (arg = argv[i]) != NULL; i++)
m_args.push_back(arg);
- m_task.StartExceptionThread(unmask_signals, launch_err);
+ m_task.StartExceptionThread(ignored_exceptions, launch_err);
if (launch_err.Fail()) {
if (launch_err.AsString() == NULL)
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h
index e9cb885..a58d5be 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachTask.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h
@@ -21,6 +21,7 @@
#include <map>
#include <string>
#include "DNBDefs.h"
+#include "RNBContext.h"
#include "MachException.h"
#include "MachVMMemory.h"
#include "PThreadMutex.h"
@@ -67,7 +68,8 @@ public:
kern_return_t RestoreExceptionPortInfo();
kern_return_t ShutDownExcecptionThread();
- bool StartExceptionThread(bool unmask_signals, DNBError &err);
+ bool StartExceptionThread(
+ const RNBContext::IgnoredExceptions &ignored_exceptions, DNBError &err);
nub_addr_t GetDYLDAllImageInfosAddress(DNBError &err);
kern_return_t BasicInfo(struct task_basic_info *info);
static kern_return_t BasicInfo(task_t task, struct task_basic_info *info);
diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
index 767dc59..1e03faf 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm
@@ -602,7 +602,9 @@ bool MachTask::IsValid(task_t task) {
return false;
}
-bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) {
+bool MachTask::StartExceptionThread(
+ const RNBContext::IgnoredExceptions &ignored_exceptions,
+ DNBError &err) {
DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__);
task_t task = TaskPortForProcessID(err);
@@ -631,10 +633,9 @@ bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) {
return false;
}
- if (unmask_signals) {
- m_exc_port_info.mask = m_exc_port_info.mask &
- ~(EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION |
- EXC_MASK_ARITHMETIC);
+ if (!ignored_exceptions.empty()) {
+ for (exception_mask_t mask : ignored_exceptions)
+ m_exc_port_info.mask = m_exc_port_info.mask & ~mask;
}
// Set the ability to get all exceptions on this port
diff --git a/lldb/tools/debugserver/source/RNBContext.cpp b/lldb/tools/debugserver/source/RNBContext.cpp
index 0617ef3..1518f30 100644
--- a/lldb/tools/debugserver/source/RNBContext.cpp
+++ b/lldb/tools/debugserver/source/RNBContext.cpp
@@ -24,6 +24,7 @@
#include "DNB.h"
#include "DNBLog.h"
#include "RNBRemote.h"
+#include "MacOSX/MachException.h"
// Destructor
RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
@@ -286,3 +287,17 @@ bool RNBContext::ProcessStateRunning() const {
nub_state_t pid_state = DNBProcessGetState(m_pid);
return pid_state == eStateRunning || pid_state == eStateStepping;
}
+
+bool RNBContext::AddIgnoredException(const char *exception_name) {
+ exception_mask_t exc_mask = MachException::ExceptionMask(exception_name);
+ if (exc_mask == 0)
+ return false;
+ m_ignored_exceptions.push_back(exc_mask);
+ return true;
+}
+
+void RNBContext::AddDefaultIgnoredExceptions() {
+ m_ignored_exceptions.push_back(EXC_MASK_BAD_ACCESS);
+ m_ignored_exceptions.push_back(EXC_MASK_BAD_INSTRUCTION);
+ m_ignored_exceptions.push_back(EXC_MASK_ARITHMETIC);
+}
diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h
index 183aa0a3..1abef6b 100644
--- a/lldb/tools/debugserver/source/RNBContext.h
+++ b/lldb/tools/debugserver/source/RNBContext.h
@@ -21,6 +21,7 @@
class RNBContext {
public:
+ using IgnoredExceptions = std::vector<exception_mask_t>;
enum {
event_proc_state_changed = 0x001,
event_proc_thread_running = 0x002, // Sticky
@@ -118,10 +119,13 @@ public:
void SetDetachOnError(bool detach) { m_detach_on_error = detach; }
bool GetDetachOnError() { return m_detach_on_error; }
- void SetUnmaskSignals(bool unmask_signals) {
- m_unmask_signals = unmask_signals;
+ bool AddIgnoredException(const char *exception_name);
+
+ void AddDefaultIgnoredExceptions();
+
+ const IgnoredExceptions &GetIgnoredExceptions() {
+ return m_ignored_exceptions;
}
- bool GetUnmaskSignals() { return m_unmask_signals; }
protected:
// Classes that inherit from RNBContext can see and modify these
@@ -144,7 +148,7 @@ protected:
std::string m_working_directory;
std::string m_process_event;
bool m_detach_on_error = false;
- bool m_unmask_signals = false;
+ IgnoredExceptions m_ignored_exceptions;
void StartProcessStatusThread();
void StopProcessStatusThread();
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 7c68f85..ebb2125 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -394,9 +394,12 @@ void RNBRemote::CreatePacketTable() {
"'G', 'p', and 'P') support having the thread ID appended "
"to the end of the command"));
t.push_back(Packet(set_logging_mode, &RNBRemote::HandlePacket_QSetLogging,
- NULL, "QSetLogging:", "Check if register packets ('g', "
- "'G', 'p', and 'P' support having "
- "the thread ID prefix"));
+ NULL, "QSetLogging:", "Turn on log channels in debugserver"));
+ t.push_back(Packet(set_ignored_exceptions, &RNBRemote::HandlePacket_QSetIgnoredExceptions,
+ NULL, "QSetIgnoredExceptions:", "Set the exception types "
+ "debugserver won't wait for, allowing "
+ "them to be turned into the equivalent "
+ "BSD signals by the normal means."));
t.push_back(Packet(
set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize, NULL,
"QSetMaxPacketSize:",
@@ -2210,6 +2213,37 @@ rnb_err_t set_logging(const char *p) {
return rnb_success;
}
+rnb_err_t RNBRemote::HandlePacket_QSetIgnoredExceptions(const char *p) {
+ // We can't set the ignored exceptions if we have a running process:
+ if (m_ctx.HasValidProcessID())
+ return SendPacket("E35");
+
+ p += sizeof("QSetIgnoredExceptions:") - 1;
+ bool success = true;
+ while(1) {
+ const char *bar = strchr(p, '|');
+ if (bar == nullptr) {
+ success = m_ctx.AddIgnoredException(p);
+ break;
+ } else {
+ std::string exc_str(p, bar - p);
+ if (exc_str.empty()) {
+ success = false;
+ break;
+ }
+
+ success = m_ctx.AddIgnoredException(exc_str.c_str());
+ if (!success)
+ break;
+ p = bar + 1;
+ }
+ }
+ if (success)
+ return SendPacket("OK");
+ else
+ return SendPacket("E36");
+}
+
rnb_err_t RNBRemote::HandlePacket_QThreadSuffixSupported(const char *p) {
m_thread_suffix_supported = true;
return SendPacket("OK");
@@ -3791,8 +3825,8 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
"'%s'",
getpid(), attach_name.c_str());
attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL,
- Context().GetUnmaskSignals(), err_str,
- sizeof(err_str));
+ Context().GetIgnoredExceptions(),
+ err_str, sizeof(err_str));
} else if (strstr(p, "vAttach;") == p) {
p += strlen("vAttach;");
@@ -3806,7 +3840,8 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) {
DNBLog("[LaunchAttach] START %d vAttach to pid %d", getpid(),
pid_attaching_to);
attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime,
- false, err_str, sizeof(err_str));
+ m_ctx.GetIgnoredExceptions(),
+ err_str, sizeof(err_str));
}
} else {
return HandlePacket_UNIMPLEMENTED(p);
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index 527b2a7..41b9aed 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -110,6 +110,7 @@ public:
start_noack_mode, // 'QStartNoAckMode'
prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID
set_logging_mode, // 'QSetLogging:'
+ set_ignored_exceptions, // 'QSetIgnoredExceptions'
set_max_packet_size, // 'QSetMaxPacketSize:'
set_max_payload_size, // 'QSetMaxPayloadSize:'
set_environment_variable, // 'QEnvironment:'
@@ -197,6 +198,7 @@ public:
rnb_err_t HandlePacket_QStartNoAckMode(const char *p);
rnb_err_t HandlePacket_QThreadSuffixSupported(const char *p);
rnb_err_t HandlePacket_QSetLogging(const char *p);
+ rnb_err_t HandlePacket_QSetIgnoredExceptions(const char *p);
rnb_err_t HandlePacket_QSetDisableASLR(const char *p);
rnb_err_t HandlePacket_QSetSTDIO(const char *p);
rnb_err_t HandlePacket_QSetWorkingDir(const char *p);
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp
index 8719871..cbff6ac 100644
--- a/lldb/tools/debugserver/source/debugserver.cpp
+++ b/lldb/tools/debugserver/source/debugserver.cpp
@@ -368,7 +368,7 @@ RNBRunLoopMode RNBRunLoopLaunchAttaching(RNBRemote *remote,
DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__,
attach_pid);
char err_str[1024];
- pid = DNBProcessAttach(attach_pid, NULL, ctx.GetUnmaskSignals(), err_str,
+ pid = DNBProcessAttach(attach_pid, NULL, ctx.GetIgnoredExceptions(), err_str,
sizeof(err_str));
g_pid = pid;
@@ -1275,7 +1275,7 @@ int main(int argc, char *argv[]) {
break;
case 'U':
- ctx.SetUnmaskSignals(true);
+ ctx.AddDefaultIgnoredExceptions();
break;
case '2':
@@ -1574,7 +1574,7 @@ int main(int argc, char *argv[]) {
RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str());
nub_process_t pid = DNBProcessAttachByName(
- attach_pid_name.c_str(), timeout_ptr, ctx.GetUnmaskSignals(),
+ attach_pid_name.c_str(), timeout_ptr, ctx.GetIgnoredExceptions(),
err_str, sizeof(err_str));
g_pid = pid;
if (pid == INVALID_NUB_PROCESS) {