diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -18,10 +18,11 @@ #include "MacOSX/DarwinLog/DarwinLogEvent.h" #include "MacOSX/Genealogy.h" #include "MacOSX/ThreadInfo.h" -#include -#include +#include "RNBContext.h" #include #include +#include +#include #define DNB_EXPORT __attribute__((visibility("default"))) @@ -42,24 +43,27 @@ // Process control nub_process_t DNBProcessLaunch( - const char *path, char const *argv[], const char *envp[], + RNBContext *ctx, const char *path, char const *argv[], const char *envp[], const char *working_directory, // NULL => don't change, non-NULL => set // 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, char *err_str, size_t err_len); + bool no_stdio, int disable_aslr, const char *event_data, char *err_str, + size_t err_len); nub_process_t DNBProcessGetPIDByName(const char *name); nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout, - char *err_str, size_t err_len); + bool unmask_signals, char *err_str, + size_t err_len); nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, - char *err_str, size_t err_len); -nub_process_t -DNBProcessAttachWait(const char *wait_name, nub_launch_flavor_t launch_flavor, - bool ignore_existing, struct timespec *timeout, - useconds_t interval, char *err_str, size_t err_len, - DNBShouldCancelCallback should_cancel = NULL, - void *callback_data = NULL); + bool unmask_signals, char *err_str, + size_t err_len); +nub_process_t DNBProcessAttachWait(RNBContext *ctx, const char *wait_name, + bool ignore_existing, + struct timespec *timeout, + useconds_t interval, char *err_str, + size_t err_len, + DNBShouldCancelCallback should_cancel = NULL, + void *callback_data = NULL); // Resume a process with exact instructions on what to do with each thread: // - If no thread actions are supplied (actions is NULL or num_actions is zero), // then all threads are continued. diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -319,20 +319,21 @@ } nub_process_t DNBProcessLaunch( - const char *path, char const *argv[], const char *envp[], + RNBContext *ctx, const char *path, char const *argv[], const char *envp[], const char *working_directory, // NULL => don't change, non-NULL => set // 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, char *err_str, size_t err_len) { - DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, " - "working_dir=%s, stdin=%s, stdout=%s, " - "stderr=%s, no-stdio=%i, launch_flavor = %u, " - "disable_aslr = %d, err = %p, err_len = " - "%llu) called...", + bool no_stdio, int disable_aslr, const char *event_data, char *err_str, + size_t err_len) { + DNBLogThreadedIf(LOG_PROCESS, + "%s ( path='%s', argv = %p, envp = %p, " + "working_dir=%s, stdin=%s, stdout=%s, " + "stderr=%s, no-stdio=%i, launch_flavor = %u, " + "disable_aslr = %d, err = %p, err_len = " + "%llu) called...", __FUNCTION__, path, static_cast(argv), static_cast(envp), working_directory, stdin_path, - stdout_path, stderr_path, no_stdio, launch_flavor, + stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, static_cast(err_str), static_cast(err_len)); @@ -349,10 +350,10 @@ MachProcessSP processSP(new MachProcess); if (processSP.get()) { DNBError launch_err; - pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory, - stdin_path, stdout_path, stderr_path, - no_stdio, launch_flavor, disable_aslr, - event_data, launch_err); + 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); if (err_str) { *err_str = '\0'; if (launch_err.Fail()) { @@ -412,7 +413,8 @@ } nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, - char *err_str, size_t err_len) { + bool unmask_signals, char *err_str, + size_t err_len) { if (err_str && err_len > 0) err_str[0] = '\0'; std::vector matching_proc_infos; @@ -433,12 +435,12 @@ } return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout, - err_str, err_len); + unmask_signals, err_str, err_len); } nub_process_t DNBProcessAttach(nub_process_t attach_pid, - struct timespec *timeout, char *err_str, - size_t err_len) { + struct timespec *timeout, bool unmask_signals, + char *err_str, size_t err_len) { if (err_str && err_len > 0) err_str[0] = '\0'; @@ -480,7 +482,8 @@ if (processSP.get()) { DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid); - pid = processSP->AttachForDebug(attach_pid, err_str, err_len); + pid = + processSP->AttachForDebug(attach_pid, unmask_signals, err_str, err_len); if (pid != INVALID_NUB_PROCESS) { bool res = AddProcessToMap(pid, processSP); @@ -667,15 +670,18 @@ return matching_proc_infos.size(); } -nub_process_t DNBProcessAttachWait( - const char *waitfor_process_name, nub_launch_flavor_t launch_flavor, - bool ignore_existing, struct timespec *timeout_abstime, - useconds_t waitfor_interval, char *err_str, size_t err_len, - DNBShouldCancelCallback should_cancel_callback, void *callback_data) { +nub_process_t +DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name, + bool ignore_existing, struct timespec *timeout_abstime, + useconds_t waitfor_interval, char *err_str, size_t err_len, + DNBShouldCancelCallback should_cancel_callback, + void *callback_data) { DNBError prepare_error; std::vector exclude_proc_infos; size_t num_exclude_proc_infos; + nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor(); + // If the PrepareForAttach returns a valid token, use MachProcess to check // for the process, otherwise scan the process table. @@ -771,8 +777,8 @@ if (waitfor_pid != INVALID_NUB_PROCESS) { DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid); - waitfor_pid = - DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len); + waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime, + ctx->GetUnmaskSignals(), err_str, err_len); } bool success = waitfor_pid != INVALID_NUB_PROCESS; diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -78,12 +78,14 @@ }; // Child process control - pid_t AttachForDebug(pid_t pid, char *err_str, size_t err_len); + pid_t AttachForDebug(pid_t pid, bool unmask_signals, 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, DNBError &err); + int disable_aslr, const char *event_data, + bool unmask_signals, DNBError &err); static uint32_t GetCPUTypeForLocalProcess(pid_t pid); static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[], @@ -107,7 +109,7 @@ pid_t BoardServiceLaunchForDebug(const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, - const char *event_data, + const char *event_data, bool unmask_signals, DNBError &launch_err); pid_t BoardServiceForkChildForPTraceDebugging( const char *path, char const *argv[], char const *envp[], bool no_stdio, @@ -128,7 +130,7 @@ #ifdef WITH_SPRINGBOARD pid_t SBLaunchForDebug(const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, - DNBError &launch_err); + bool unmask_signals, DNBError &launch_err); static pid_t SBForkChildForPTraceDebugging(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 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -2600,7 +2600,8 @@ return NULL; } -pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { +pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str, + size_t err_len) { // Clear out and clean up from any current state Clear(); if (pid != 0) { @@ -2617,7 +2618,7 @@ SetState(eStateAttaching); m_pid = pid; - if (!m_task.StartExceptionThread(err)) { + if (!m_task.StartExceptionThread(unmask_signals, err)) { const char *err_cstr = err.AsString(); ::snprintf(err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread"); @@ -3077,7 +3078,7 @@ // 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, DNBError &launch_err) { + const char *event_data, bool unmask_signals, DNBError &launch_err) { // Clear out and clean up from any current state Clear(); @@ -3182,7 +3183,7 @@ for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, launch_err); if (launch_err.Fail()) { if (launch_err.AsString() == NULL) launch_err.SetErrorString("unable to start the exception thread"); @@ -3525,7 +3526,8 @@ pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], char const *envp[], bool no_stdio, - bool disable_aslr, DNBError &launch_err) { + bool disable_aslr, bool unmask_signals, + DNBError &launch_err) { // Clear out and clean up from any current state Clear(); @@ -3541,7 +3543,7 @@ char const *arg; for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, launch_err); if (launch_err.Fail()) { if (launch_err.AsString() == NULL) @@ -3738,7 +3740,8 @@ #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, DNBError &launch_err) { + bool disable_aslr, const char *event_data, bool unmask_signals, + DNBError &launch_err) { DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); // Fork a child process for debugging @@ -3751,7 +3754,7 @@ char const *arg; for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, 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 --- a/lldb/tools/debugserver/source/MacOSX/MachTask.h +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h @@ -67,7 +67,7 @@ kern_return_t RestoreExceptionPortInfo(); kern_return_t ShutDownExcecptionThread(); - bool StartExceptionThread(DNBError &err); + bool StartExceptionThread(bool unmask_signals, 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 --- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -595,7 +595,7 @@ return false; } -bool MachTask::StartExceptionThread(DNBError &err) { +bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) { DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__); task_t task = TaskPortForProcessID(err); @@ -624,6 +624,12 @@ 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); + } + // Set the ability to get all exceptions on this port err = ::task_set_exception_ports( task, m_exc_port_info.mask, m_exception_port, diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h --- a/lldb/tools/debugserver/source/RNBContext.h +++ b/lldb/tools/debugserver/source/RNBContext.h @@ -124,6 +124,11 @@ 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 GetUnmaskSignals() { return m_unmask_signals; } + protected: // Classes that inherit from RNBContext can see and modify these nub_process_t m_pid; @@ -147,6 +152,7 @@ void StartProcessStatusThread(); void StopProcessStatusThread(); static void *ThreadFunctionProcessStatus(void *arg); + bool m_unmask_signals; private: RNBContext(const RNBContext &rhs) = delete; diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3927,8 +3927,8 @@ } const bool ignore_existing = true; attach_pid = DNBProcessAttachWait( - attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, - 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str, + sizeof(err_str), RNBRemoteShouldCancelCallback); } else if (strstr(p, "vAttachOrWait;") == p) { p += strlen("vAttachOrWait;"); @@ -3939,8 +3939,8 @@ } const bool ignore_existing = false; attach_pid = DNBProcessAttachWait( - attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, - 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str, + sizeof(err_str), RNBRemoteShouldCancelCallback); } else if (strstr(p, "vAttachName;") == p) { p += strlen("vAttachName;"); if (!GetProcessNameFrom_vAttach(p, attach_name)) { @@ -3948,7 +3948,8 @@ __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt"); } - attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, err_str, + attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, + Context().GetUnmaskSignals(), err_str, sizeof(err_str)); } else if (strstr(p, "vAttach;") == p) { @@ -3961,7 +3962,7 @@ struct timespec attach_timeout_abstime; DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0); attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime, - err_str, sizeof(err_str)); + false, err_str, sizeof(err_str)); } } else { return HandlePacket_UNIMPLEMENTED(p); diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -245,8 +245,8 @@ : ctx.GetWorkingDirectory()); const char *process_event = ctx.GetProcessEvent(); nub_process_t pid = DNBProcessLaunch( - resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, stdin_path, - stdout_path, stderr_path, no_stdio, launch_flavor, g_disable_aslr, + &ctx, resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, + stdin_path, stdout_path, stderr_path, no_stdio, g_disable_aslr, process_event, launch_err_str, sizeof(launch_err_str)); g_pid = pid; @@ -368,7 +368,8 @@ DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid); char err_str[1024]; - pid = DNBProcessAttach(attach_pid, NULL, err_str, sizeof(err_str)); + pid = DNBProcessAttach(attach_pid, NULL, ctx.GetUnmaskSignals(), err_str, + sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { @@ -889,6 +890,10 @@ 'F'}, // When debugserver launches the process, forward debugserver's // current environment variables to the child process ("./debugserver // -F localhost:1234 -- /bin/ls" + {"unmask-signals", no_argument, NULL, + 'U'}, // debugserver will ignore EXC_MASK_BAD_ACCESS, + // EXC_MASK_BAD_INSTRUCTION and EXC_MASK_ARITHMETIC, which results in + // SIGSEGV, SIGILL and SIGFPE being propagated to the target process. {NULL, 0, NULL, 0}}; int communication_fd = -1; @@ -1260,6 +1265,10 @@ forward_env = true; break; + case 'U': + ctx.SetUnmaskSignals(true); + break; + case '2': // File descriptor passed to this process during fork/exec and is already // open and ready for communication. @@ -1514,8 +1523,8 @@ RNBLogSTDOUT("Waiting to attach to process %s...\n", waitfor_pid_name.c_str()); nub_process_t pid = DNBProcessAttachWait( - waitfor_pid_name.c_str(), launch_flavor, ignore_existing, - timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); + &ctx, waitfor_pid_name.c_str(), ignore_existing, timeout_ptr, + waitfor_interval, err_str, sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { @@ -1550,7 +1559,8 @@ RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str()); nub_process_t pid = DNBProcessAttachByName( - attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); + attach_pid_name.c_str(), timeout_ptr, ctx.GetUnmaskSignals(), + err_str, sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { ctx.LaunchStatus().SetError(-1, DNBError::Generic);