Index: include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- include/lldb/Host/common/NativeProcessProtocol.h +++ include/lldb/Host/common/NativeProcessProtocol.h @@ -16,6 +16,7 @@ #include "lldb/lldb-types.h" #include "lldb/Core/Error.h" #include "lldb/Host/Mutex.h" +#include "lldb/Host/MainLoop.h" #include "llvm/ADT/StringRef.h" #include "NativeBreakpointList.h" @@ -320,6 +321,7 @@ static Error Launch (ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp); //------------------------------------------------------------------ @@ -348,6 +350,7 @@ static Error Attach (lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp); protected: Index: source/Host/common/NativeProcessProtocol.cpp =================================================================== --- source/Host/common/NativeProcessProtocol.cpp +++ source/Host/common/NativeProcessProtocol.cpp @@ -449,6 +449,7 @@ Error NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp) { llvm_unreachable("Platform has no NativeProcessProtocol support"); @@ -457,6 +458,7 @@ Error NativeProcessProtocol::Attach (lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp) { llvm_unreachable("Platform has no NativeProcessProtocol support"); Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -43,25 +43,16 @@ friend Error NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp); friend Error NativeProcessProtocol::Attach (lldb::pid_t pid, - NativeProcessProtocol::NativeDelegate &native_delegate, - NativeProcessProtocolSP &native_process_sp); + NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop, + NativeProcessProtocolSP &process_sp); public: - //------------------------------------------------------------------------------ - /// @class Operation - /// @brief Represents a NativeProcessLinux operation. - /// - /// Under Linux, it is not possible to ptrace() from any other thread but the - /// one that spawned or attached to the process from the start. Therefore, when - /// a NativeProcessLinux is asked to deliver or change the state of an inferior - /// process the operation must be "funneled" to a specific thread to perform the - /// task. - typedef std::function Operation; - // --------------------------------------------------------------------- // NativeProcessProtocol Interface // --------------------------------------------------------------------- @@ -113,18 +104,9 @@ Error SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) override; - Error - SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override; - - Error - RemoveWatchpoint (lldb::addr_t addr) override; - void DoStopIDBumped (uint32_t newBumpId) override; - void - Terminate () override; - Error GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) override; @@ -134,9 +116,6 @@ // --------------------------------------------------------------------- // Interface used by NativeRegisterContext-derived classes. // --------------------------------------------------------------------- - Error - DoOperation(const Operation &op); - static Error PtraceWrapper(int req, lldb::pid_t pid, @@ -154,12 +133,9 @@ private: - class Monitor; - + MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; - std::unique_ptr m_monitor_up; - LazyBool m_supports_mem_region; std::vector m_mem_region_cache; Mutex m_mem_region_cache_mutex; @@ -206,6 +182,7 @@ /// implementation of Process::DoLaunch. void LaunchInferior ( + MainLoop &mainloop, Module *module, char const *argv[], char const *envp[], @@ -219,10 +196,7 @@ /// Attaches to an existing process. Forms the /// implementation of Process::DoAttach void - AttachToInferior (lldb::pid_t pid, Error &error); - - void - StartMonitorThread(const InitialOperation &operation, Error &error); + AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error); ::pid_t Launch(LaunchArgs *args, Error &error); @@ -370,6 +344,9 @@ void ThreadWasCreated (lldb::tid_t tid); + void + SigchldHandler(); + // Member variables. PendingNotificationUP m_pending_notification_up; }; Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -11,7 +11,6 @@ // C Includes #include -#include #include #include #include @@ -221,11 +220,6 @@ } } - //------------------------------------------------------------------------------ - // Static implementations of NativeProcessLinux::ReadMemory and - // NativeProcessLinux::WriteMemory. This enables mutual recursion between these - // functions without needed to go thru the thread funnel. - Error DoReadMemory( lldb::pid_t pid, @@ -397,406 +391,6 @@ return error; } -// This class encapsulates the privileged thread which performs all ptrace and wait operations on -// the inferior. The thread consists of a main loop which waits for events and processes them -// - SIGCHLD (delivered over a signalfd file descriptor): These signals notify us of events in -// the inferior process. Upon receiving this signal we do a waitpid to get more information -// and dispatch to NativeProcessLinux::MonitorCallback. -// - requests for ptrace operations: These initiated via the DoOperation method, which funnels -// them to the Monitor thread via m_operation member. The Monitor thread is signaled over a -// pipe, and the completion of the operation is signalled over the semaphore. -// - thread exit event: this is signaled from the Monitor destructor by closing the write end -// of the command pipe. -class NativeProcessLinux::Monitor -{ -private: - // The initial monitor operation (launch or attach). It returns a inferior process id. - std::unique_ptr m_initial_operation_up; - - ::pid_t m_child_pid = -1; - NativeProcessLinux * m_native_process; - - enum { READ, WRITE }; - int m_pipefd[2] = {-1, -1}; - int m_signal_fd = -1; - HostThread m_thread; - - // current operation which must be executed on the priviliged thread - Mutex m_operation_mutex; - const Operation *m_operation = nullptr; - sem_t m_operation_sem; - Error m_operation_error; - - unsigned m_operation_nesting_level = 0; - - static constexpr char operation_command = 'o'; - static constexpr char begin_block_command = '{'; - static constexpr char end_block_command = '}'; - - void - HandleSignals(); - - void - HandleWait(); - - // Returns true if the thread should exit. - bool - HandleCommands(); - - void - MainLoop(); - - static void * - RunMonitor(void *arg); - - Error - WaitForAck(); - - void - BeginOperationBlock() - { - write(m_pipefd[WRITE], &begin_block_command, sizeof operation_command); - WaitForAck(); - } - - void - EndOperationBlock() - { - write(m_pipefd[WRITE], &end_block_command, sizeof operation_command); - WaitForAck(); - } - -public: - Monitor(const InitialOperation &initial_operation, - NativeProcessLinux *native_process) - : m_initial_operation_up(new InitialOperation(initial_operation)), - m_native_process(native_process) - { - sem_init(&m_operation_sem, 0, 0); - } - - ~Monitor(); - - Error - Initialize(); - - void - Terminate(); - - Error - DoOperation(const Operation &op); - - class ScopedOperationLock { - Monitor &m_monitor; - - public: - ScopedOperationLock(Monitor &monitor) - : m_monitor(monitor) - { m_monitor.BeginOperationBlock(); } - - ~ScopedOperationLock() - { m_monitor.EndOperationBlock(); } - }; -}; -constexpr char NativeProcessLinux::Monitor::operation_command; -constexpr char NativeProcessLinux::Monitor::begin_block_command; -constexpr char NativeProcessLinux::Monitor::end_block_command; - -Error -NativeProcessLinux::Monitor::Initialize() -{ - Error error; - - // We get a SIGCHLD every time something interesting happens with the inferior. We shall be - // listening for these signals over a signalfd file descriptors. This allows us to wait for - // multiple kinds of events with select. - sigset_t signals; - sigemptyset(&signals); - sigaddset(&signals, SIGCHLD); - m_signal_fd = signalfd(-1, &signals, SFD_NONBLOCK | SFD_CLOEXEC); - if (m_signal_fd < 0) - { - return Error("NativeProcessLinux::Monitor::%s failed due to signalfd failure. Monitoring the inferior will be impossible: %s", - __FUNCTION__, strerror(errno)); - - } - - if (pipe2(m_pipefd, O_CLOEXEC) == -1) - { - error.SetErrorToErrno(); - return error; - } - - if ((error = EnsureFDFlags(m_pipefd[READ], O_NONBLOCK)).Fail()) { - return error; - } - - static const char g_thread_name[] = "lldb.process.nativelinux.monitor"; - m_thread = ThreadLauncher::LaunchThread(g_thread_name, Monitor::RunMonitor, this, nullptr); - if (!m_thread.IsJoinable()) - return Error("Failed to create monitor thread for NativeProcessLinux."); - - // Wait for initial operation to complete. - return WaitForAck(); -} - -Error -NativeProcessLinux::Monitor::DoOperation(const Operation &op) -{ - if (m_thread.EqualsThread(pthread_self())) { - // If we're on the Monitor thread, we can simply execute the operation. - return op(); - } - - // Otherwise we need to pass the operation to the Monitor thread so it can handle it. - Mutex::Locker lock(m_operation_mutex); - - m_operation = &op; - - // notify the thread that an operation is ready to be processed - write(m_pipefd[WRITE], &operation_command, sizeof operation_command); - - return WaitForAck(); -} - -void -NativeProcessLinux::Monitor::Terminate() -{ - if (m_pipefd[WRITE] >= 0) - { - close(m_pipefd[WRITE]); - m_pipefd[WRITE] = -1; - } - if (m_thread.IsJoinable()) - m_thread.Join(nullptr); -} - -NativeProcessLinux::Monitor::~Monitor() -{ - Terminate(); - if (m_pipefd[READ] >= 0) - close(m_pipefd[READ]); - if (m_signal_fd >= 0) - close(m_signal_fd); - sem_destroy(&m_operation_sem); -} - -void -NativeProcessLinux::Monitor::HandleSignals() -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // We don't really care about the content of the SIGCHLD siginfo structure, as we will get - // all the information from waitpid(). We just need to read all the signals so that we can - // sleep next time we reach select(). - while (true) - { - signalfd_siginfo info; - ssize_t size = read(m_signal_fd, &info, sizeof info); - if (size == -1) - { - if (errno == EAGAIN || errno == EWOULDBLOCK) - break; // We are done. - if (errno == EINTR) - continue; - if (log) - log->Printf("NativeProcessLinux::Monitor::%s reading from signalfd file descriptor failed: %s", - __FUNCTION__, strerror(errno)); - break; - } - if (size != sizeof info) - { - // We got incomplete information structure. This should not happen, let's just log - // that. - if (log) - log->Printf("NativeProcessLinux::Monitor::%s reading from signalfd file descriptor returned incomplete data: " - "structure size is %zd, read returned %zd bytes", - __FUNCTION__, sizeof info, size); - break; - } - if (log) - log->Printf("NativeProcessLinux::Monitor::%s received signal %s(%d).", __FUNCTION__, - Host::GetSignalAsCString(info.ssi_signo), info.ssi_signo); - } -} - -void -NativeProcessLinux::Monitor::HandleWait() -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - // Process all pending waitpid notifications. - while (true) - { - int status = -1; - ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG); - - if (wait_pid == 0) - break; // We are done. - - if (wait_pid == -1) - { - if (errno == EINTR) - continue; - - if (log) - log->Printf("NativeProcessLinux::Monitor::%s waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG) failed: %s", - __FUNCTION__, strerror(errno)); - break; - } - - bool exited = false; - int signal = 0; - int exit_status = 0; - const char *status_cstr = NULL; - if (WIFSTOPPED(status)) - { - signal = WSTOPSIG(status); - status_cstr = "STOPPED"; - } - else if (WIFEXITED(status)) - { - exit_status = WEXITSTATUS(status); - status_cstr = "EXITED"; - exited = true; - } - else if (WIFSIGNALED(status)) - { - signal = WTERMSIG(status); - status_cstr = "SIGNALED"; - if (wait_pid == m_child_pid) { - exited = true; - exit_status = -1; - } - } - else - status_cstr = "(\?\?\?)"; - - if (log) - log->Printf("NativeProcessLinux::Monitor::%s: waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG)" - "=> pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", - __FUNCTION__, wait_pid, status, status_cstr, signal, exit_status); - - m_native_process->MonitorCallback (wait_pid, exited, signal, exit_status); - } -} - -bool -NativeProcessLinux::Monitor::HandleCommands() -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - while (true) - { - char command = 0; - ssize_t size = read(m_pipefd[READ], &command, sizeof command); - if (size == -1) - { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return false; - if (errno == EINTR) - continue; - if (log) - log->Printf("NativeProcessLinux::Monitor::%s exiting because read from command file descriptor failed: %s", __FUNCTION__, strerror(errno)); - return true; - } - if (size == 0) // end of file - write end closed - { - if (log) - log->Printf("NativeProcessLinux::Monitor::%s exit command received, exiting...", __FUNCTION__); - assert(m_operation_nesting_level == 0 && "Unbalanced begin/end block commands detected"); - return true; // We are done. - } - - switch (command) - { - case operation_command: - m_operation_error = (*m_operation)(); - break; - case begin_block_command: - ++m_operation_nesting_level; - break; - case end_block_command: - assert(m_operation_nesting_level > 0); - --m_operation_nesting_level; - break; - default: - if (log) - log->Printf("NativeProcessLinux::Monitor::%s received unknown command '%c'", - __FUNCTION__, command); - } - - // notify calling thread that the command has been processed - sem_post(&m_operation_sem); - } -} - -void -NativeProcessLinux::Monitor::MainLoop() -{ - ::pid_t child_pid = (*m_initial_operation_up)(m_operation_error); - m_initial_operation_up.reset(); - m_child_pid = child_pid; - sem_post(&m_operation_sem); - - while (true) - { - fd_set fds; - FD_ZERO(&fds); - // Only process waitpid events if we are outside of an operation block. Any pending - // events will be processed after we leave the block. - if (m_operation_nesting_level == 0) - FD_SET(m_signal_fd, &fds); - FD_SET(m_pipefd[READ], &fds); - - int max_fd = std::max(m_signal_fd, m_pipefd[READ]) + 1; - int r = select(max_fd, &fds, nullptr, nullptr, nullptr); - if (r < 0) - { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("NativeProcessLinux::Monitor::%s exiting because select failed: %s", - __FUNCTION__, strerror(errno)); - return; - } - - if (FD_ISSET(m_pipefd[READ], &fds)) - { - if (HandleCommands()) - return; - } - - if (FD_ISSET(m_signal_fd, &fds)) - { - HandleSignals(); - HandleWait(); - } - } -} - -Error -NativeProcessLinux::Monitor::WaitForAck() -{ - Error error; - while (sem_wait(&m_operation_sem) != 0) - { - if (errno == EINTR) - continue; - - error.SetErrorToErrno(); - return error; - } - - return m_operation_error; -} - -void * -NativeProcessLinux::Monitor::RunMonitor(void *arg) -{ - static_cast(arg)->MainLoop(); - return nullptr; -} - - NativeProcessLinux::LaunchArgs::LaunchArgs(Module *module, char const **argv, char const **envp, @@ -827,6 +421,7 @@ NativeProcessProtocol::Launch ( ProcessLaunchInfo &launch_info, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -913,6 +508,7 @@ } std::static_pointer_cast (native_process_sp)->LaunchInferior ( + mainloop, exe_module_sp.get(), launch_info.GetArguments ().GetConstArgumentVector (), launch_info.GetEnvironmentEntries ().GetConstArgumentVector (), @@ -940,6 +536,7 @@ NativeProcessProtocol::Attach ( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -966,7 +563,7 @@ return error; } - native_process_linux_sp->AttachToInferior (pid, error); + native_process_linux_sp->AttachToInferior (mainloop, pid, error); if (!error.Success ()) return error; @@ -987,12 +584,9 @@ { } -//------------------------------------------------------------------------------ -// NativeProcessLinux spawns a new thread which performs all operations on the inferior process. -// Refer to Monitor and Operation classes to see why this is necessary. -//------------------------------------------------------------------------------ void NativeProcessLinux::LaunchInferior ( + MainLoop &mainloop, Module *module, const char *argv[], const char *envp[], @@ -1003,6 +597,11 @@ const ProcessLaunchInfo &launch_info, Error &error) { + m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD, + [this] (MainLoopBase &) { SigchldHandler(); }, error); + if (! m_sigchld_handle) + return; + if (module) m_arch = module->GetArchitecture (); @@ -1016,18 +615,21 @@ working_dir, launch_info)); - StartMonitorThread ([&] (Error &e) { return Launch(args.get(), e); }, error); - if (!error.Success ()) - return; + Launch(args.get(), error); } void -NativeProcessLinux::AttachToInferior (lldb::pid_t pid, Error &error) +NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ")", __FUNCTION__, pid); + m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD, + [this] (MainLoopBase &) { SigchldHandler(); }, error); + if (! m_sigchld_handle) + return; + // We can use the Host for everything except the ResolveExecutable portion. PlatformSP platform_sp = Platform::GetHostPlatform (); if (!platform_sp) @@ -1065,15 +667,7 @@ m_pid = pid; SetState(eStateAttaching); - StartMonitorThread ([=] (Error &e) { return Attach(pid, e); }, error); - if (!error.Success ()) - return; -} - -void -NativeProcessLinux::Terminate () -{ - m_monitor_up->Terminate(); + Attach(pid, error); } ::pid_t @@ -2295,7 +1889,6 @@ bool software_single_step = !SupportHardwareSingleStepping(); - Monitor::ScopedOperationLock monitor_lock(*m_monitor_up); Mutex::Locker locker (m_threads_mutex); if (software_single_step) @@ -2415,7 +2008,7 @@ error = Detach (GetID ()); // Stop monitoring the inferior. - m_monitor_up->Terminate(); + m_sigchld_handle.reset(); // No error. return error; @@ -2450,7 +2043,6 @@ if (log) log->Printf ("NativeProcessLinux::%s selecting running thread for interrupt target", __FUNCTION__); - Monitor::ScopedOperationLock monitor_lock(*m_monitor_up); Mutex::Locker locker (m_threads_mutex); for (auto thread_sp : m_threads) @@ -3106,24 +2698,6 @@ #endif Error -NativeProcessLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) -{ - // The base SetWatchpoint will end up executing monitor operations. Let's lock the monitor - // for it. - Monitor::ScopedOperationLock monitor_lock(*m_monitor_up); - return NativeProcessProtocol::SetWatchpoint(addr, size, watch_flags, hardware); -} - -Error -NativeProcessLinux::RemoveWatchpoint (lldb::addr_t addr) -{ - // The base RemoveWatchpoint will end up executing monitor operations. Let's lock the monitor - // for it. - Monitor::ScopedOperationLock monitor_lock(*m_monitor_up); - return NativeProcessProtocol::RemoveWatchpoint(addr); -} - -Error NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) { if (ProcessVmReadvSupported()) { @@ -3152,7 +2726,7 @@ // the call failed for some reason, let's retry the read using ptrace api. } - return DoOperation([&] { return DoReadMemory(GetID(), addr, buf, size, bytes_read); }); + return DoReadMemory(GetID(), addr, buf, size, bytes_read); } Error @@ -3166,7 +2740,7 @@ Error NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) { - return DoOperation([&] { return DoWriteMemory(GetID(), addr, buf, size, bytes_written); }); + return DoWriteMemory(GetID(), addr, buf, size, bytes_written); } Error @@ -3185,7 +2759,7 @@ if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - Error error = DoOperation([&] { return PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data); }); + Error error = PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data); if (log) log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " result = %s", __FUNCTION__, tid, error.Success() ? "true" : "false"); @@ -3200,19 +2774,19 @@ if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - return DoOperation([&] { return PtraceWrapper(PTRACE_SINGLESTEP, tid, nullptr, (void*)data); }); + return PtraceWrapper(PTRACE_SINGLESTEP, tid, nullptr, (void*)data); } Error NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) { - return DoOperation([&] { return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); }); + return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); } Error NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message) { - return DoOperation([&] { return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); }); + return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); } Error @@ -3221,7 +2795,7 @@ if (tid == LLDB_INVALID_THREAD_ID) return Error(); - return DoOperation([&] { return PtraceWrapper(PTRACE_DETACH, tid); }); + return PtraceWrapper(PTRACE_DETACH, tid); } bool @@ -3238,16 +2812,6 @@ return (close(target_fd) == -1) ? false : true; } -void -NativeProcessLinux::StartMonitorThread(const InitialOperation &initial_operation, Error &error) -{ - m_monitor_up.reset(new Monitor(initial_operation, this)); - error = m_monitor_up->Initialize(); - if (error.Fail()) { - m_monitor_up.reset(); - } -} - bool NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id) { @@ -3716,10 +3280,64 @@ } } -Error -NativeProcessLinux::DoOperation(const Operation &op) +void +NativeProcessLinux::SigchldHandler() { - return m_monitor_up->DoOperation(op); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Process all pending waitpid notifications. + while (true) + { + int status = -1; + ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG); + + if (wait_pid == 0) + break; // We are done. + + if (wait_pid == -1) + { + if (errno == EINTR) + continue; + + if (log) + log->Printf("NativeProcessLinux::%s waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG) failed: %s", + __FUNCTION__, strerror(errno)); + break; + } + + bool exited = false; + int signal = 0; + int exit_status = 0; + const char *status_cstr = NULL; + if (WIFSTOPPED(status)) + { + signal = WSTOPSIG(status); + status_cstr = "STOPPED"; + } + else if (WIFEXITED(status)) + { + exit_status = WEXITSTATUS(status); + status_cstr = "EXITED"; + exited = true; + } + else if (WIFSIGNALED(status)) + { + signal = WTERMSIG(status); + status_cstr = "SIGNALED"; + if (wait_pid == static_cast<::pid_t>(GetID())) { + exited = true; + exit_status = -1; + } + } + else + status_cstr = "(\?\?\?)"; + + if (log) + log->Printf("NativeProcessLinux::%s: waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG)" + "=> pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", + __FUNCTION__, wait_pid, status, status_cstr, signal, exit_status); + + MonitorCallback (wait_pid, exited, signal, exit_status); + } } // Wrapper for ptrace to catch errors and log calls. Index: source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -50,14 +50,7 @@ if (!reg_info) return Error("register %" PRIu32 " not found", reg_index); - NativeProcessProtocolSP process_sp(m_thread.GetProcess()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - - NativeProcessLinux* process_p = static_cast(process_sp.get()); - return process_p->DoOperation([&] { - return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); - }); + return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); } Error @@ -108,111 +101,70 @@ } } - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); - NativeProcessLinux* process_p = static_cast (process_sp.get ()); - return process_p->DoOperation([&] { - return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); - }); + return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); } Error NativeRegisterContextLinux::ReadGPR() { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - void* buf = GetGPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetGPRSize(); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - return process_p->DoOperation([&] { return DoReadGPR(buf, buf_size); }); + return DoReadGPR(buf, buf_size); } Error NativeRegisterContextLinux::WriteGPR() { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - void* buf = GetGPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetGPRSize(); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - return process_p->DoOperation([&] { return DoWriteGPR(buf, buf_size); }); + return DoWriteGPR(buf, buf_size); } Error NativeRegisterContextLinux::ReadFPR() { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - void* buf = GetFPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetFPRSize(); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - return process_p->DoOperation([&] { return DoReadFPR(buf, buf_size); }); + return DoReadFPR(buf, buf_size); } Error NativeRegisterContextLinux::WriteFPR() { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - void* buf = GetFPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetFPRSize(); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - return process_p->DoOperation([&] { return DoWriteFPR(buf, buf_size); }); + return DoWriteFPR(buf, buf_size); } Error NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) { - NativeProcessProtocolSP process_sp (m_thread.GetProcess()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - - return process_p->DoOperation([&] { - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), - static_cast(®set), buf, buf_size); - }); + return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast(®set), buf, buf_size); } Error NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) { - NativeProcessProtocolSP process_sp (m_thread.GetProcess()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - NativeProcessLinux* process_p = static_cast(process_sp.get()); - - return process_p->DoOperation([&] { - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - static_cast(®set), buf, buf_size); - }); + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast(®set), buf, buf_size); } Error Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -715,29 +715,23 @@ NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo(unsigned int &watch_count, unsigned int &break_count) { - NativeProcessProtocolSP process_sp (m_thread.GetProcess()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - NativeProcessLinux *const process_p = reinterpret_cast(process_sp.get()); ::pid_t tid = m_thread.GetID(); - return process_p->DoOperation([&] { - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Error error; + int regset = NT_ARM_HW_WATCH; + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Error error; - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof (dreg_state); - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); - watch_count = dreg_state.dbg_info & 0xff; + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof (dreg_state); + error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); + watch_count = dreg_state.dbg_info & 0xff; - regset = NT_ARM_HW_BREAK; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); - break_count = dreg_state.dbg_info & 0xff; + regset = NT_ARM_HW_BREAK; + error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); + break_count = dreg_state.dbg_info & 0xff; - return error; - }); + return error; } Error @@ -746,33 +740,26 @@ int type, int count) { - NativeProcessProtocolSP process_sp (m_thread.GetProcess()); - if (!process_sp) - return Error("NativeProcessProtocol is NULL"); - NativeProcessLinux *const process_p = reinterpret_cast(process_sp.get()); - - return process_p->DoOperation([&] { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Error error; + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Error error; - memset (&dreg_state, 0, sizeof (dreg_state)); - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof (dreg_state); + memset (&dreg_state, 0, sizeof (dreg_state)); + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof (dreg_state); - if (type == 0) - type = NT_ARM_HW_WATCH; - else - type = NT_ARM_HW_BREAK; + if (type == 0) + type = NT_ARM_HW_WATCH; + else + type = NT_ARM_HW_BREAK; - for (int i = 0; i < count; i++) - { - dreg_state.dbg_regs[i].addr = addr_buf[i]; - dreg_state.dbg_regs[i].ctrl = cntrl_buf[i]; - } + for (int i = 0; i < count; i++) + { + dreg_state.dbg_regs[i].addr = addr_buf[i]; + dreg_state.dbg_regs[i].ctrl = cntrl_buf[i]; + } - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &type, &ioVec, ioVec.iov_len); - }); + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &type, &ioVec, ioVec.iov_len); } Error Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -877,19 +877,13 @@ // reading the current state of watch regs struct pt_watch_regs watch_readback; - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - NativeProcessLinux *const process_p = static_cast (process_sp.get ()); - Error error = process_p->DoOperation([&] { - return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); - }); + Error error = DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); if (GetWatchHi (&watch_readback, wp_index) & (IRW)) { // clear hit flag in watchhi SetWatchHi (&watch_readback, wp_index, (GetWatchHi (&watch_readback, wp_index) & ~(IRW))); - process_p->DoOperation([&] { - return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); - }); + DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); is_hit = true; return error; @@ -930,11 +924,7 @@ struct pt_watch_regs regs; // First reading the current state of watch regs - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - NativeProcessLinux *const process_p = static_cast (process_sp.get ()); - process_p->DoOperation([&] { - return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); - }); + DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); if (regs.style == pt_watch_style_mips32) { @@ -949,9 +939,7 @@ regs.mips64.watch_masks[wp_index] = default_watch_regs.mips64.watch_masks[wp_index]; } - Error error = process_p->DoOperation([&] { - return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); - }); + Error error = DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); if(!error.Fail()) { hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS; @@ -963,11 +951,7 @@ Error NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - NativeProcessLinux *const process_p = static_cast (process_sp.get ()); - return process_p->DoOperation([&] { - return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&default_watch_regs)); - }); + return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&default_watch_regs)); } Error @@ -986,11 +970,7 @@ struct pt_watch_regs regs; // First reading the current state of watch regs - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - NativeProcessLinux *const process_p = static_cast (process_sp.get ()); - process_p->DoOperation([&] { - return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); - }); + DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); // Try if a new watch point fits in this state int index = GetVacantWatchIndex (®s, addr, size, watch_flags, NumSupportedHardwareWatchpoints()); @@ -1001,9 +981,7 @@ // It fits, so we go ahead with updating the state of watch regs - process_p->DoOperation([&] { - return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); - }); + DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); // Storing exact address hw_addr_map[index] = addr; @@ -1027,17 +1005,7 @@ static int num_valid = 0; if (!num_valid) { - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - { - printf ("NativeProcessProtocol is NULL"); - return 0; - } - - NativeProcessLinux *const process_p = static_cast (process_sp.get ()); - process_p->DoOperation([&] { - return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); - }); + DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); default_watch_regs = regs; // Keeping default watch regs values for future use switch (regs.style) { Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -223,6 +223,7 @@ error = NativeProcessProtocol::Launch( m_process_launch_info, *this, + m_mainloop, m_debugged_process_sp); } @@ -308,7 +309,7 @@ } // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_debugged_process_sp); + error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, m_debugged_process_sp); if (!error.Success ()) { fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ());