diff options
9 files changed, 811 insertions, 276 deletions
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h index 7236bf65904..4f0f3a962d3 100644 --- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -16,7 +16,6 @@ #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" @@ -285,6 +284,10 @@ namespace lldb_private bool UnregisterNativeDelegate (NativeDelegate &native_delegate); + // Called before termination of NativeProcessProtocol's instance. + virtual void + Terminate (); + virtual Error GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) = 0; @@ -304,11 +307,6 @@ namespace lldb_private /// inferior. Must outlive the NativeProcessProtocol /// instance. /// - /// @param[in] mainloop - /// The mainloop instance with which the process can register - /// callbacks. Must outlive the NativeProcessProtocol - /// instance. - /// /// @param[out] process_sp /// On successful return from the method, this parameter /// contains the shared pointer to the @@ -322,7 +320,6 @@ namespace lldb_private static Error Launch (ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); //------------------------------------------------------------------ @@ -338,11 +335,6 @@ namespace lldb_private /// inferior. Must outlive the NativeProcessProtocol /// instance. /// - /// @param[in] mainloop - /// The mainloop instance with which the process can register - /// callbacks. Must outlive the NativeProcessProtocol - /// instance. - /// /// @param[out] process_sp /// On successful return from the method, this parameter /// contains the shared pointer to the @@ -356,7 +348,6 @@ namespace lldb_private static Error Attach (lldb::pid_t pid, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); protected: diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp index 7d2f4012bf8..818d69bdabd 100644 --- a/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -436,6 +436,12 @@ NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */) // Default implementation does nothing. } +void +NativeProcessProtocol::Terminate () +{ + // Default implementation does nothing. +} + #ifndef __linux__ // These need to be implemented to support lldb-gdb-server on a given platform. Stubs are // provided to make the rest of the code link on non-supported platforms. @@ -443,7 +449,6 @@ NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */) Error NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp) { llvm_unreachable("Platform has no NativeProcessProtocol support"); @@ -452,7 +457,6 @@ NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, Error NativeProcessProtocol::Attach (lldb::pid_t pid, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp) { llvm_unreachable("Platform has no NativeProcessProtocol support"); diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 2eff354a1ae..372ac789d6a 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -11,6 +11,7 @@ // C Includes #include <errno.h> +#include <semaphore.h> #include <string.h> #include <stdint.h> #include <unistd.h> @@ -212,8 +213,157 @@ namespace } } - static constexpr unsigned k_ptrace_word_size = sizeof(void*); - static_assert(sizeof(long) >= k_ptrace_word_size, "Size of long must be larger than ptrace word size"); + //------------------------------------------------------------------------------ + // 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, + lldb::addr_t vm_addr, + void *buf, + size_t size, + size_t &bytes_read) + { + // ptrace word size is determined by the host, not the child + static const unsigned word_size = sizeof(void*); + unsigned char *dst = static_cast<unsigned char*>(buf); + size_t remainder; + long data; + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); + if (log) + ProcessPOSIXLog::IncNestLevel(); + if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) + log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %d, %p, %p, %zd, _)", __FUNCTION__, + pid, word_size, (void*)vm_addr, buf, size); + + assert(sizeof(data) >= word_size); + for (bytes_read = 0; bytes_read < size; bytes_read += remainder) + { + Error error = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKDATA, pid, (void*)vm_addr, nullptr, 0, &data); + if (error.Fail()) + { + if (log) + ProcessPOSIXLog::DecNestLevel(); + return error; + } + + remainder = size - bytes_read; + remainder = remainder > word_size ? word_size : remainder; + + // Copy the data into our buffer + for (unsigned i = 0; i < remainder; ++i) + dst[i] = ((data >> i*8) & 0xFF); + + if (log && ProcessPOSIXLog::AtTopNestLevel() && + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && + size <= POSIX_LOG_MEMORY_SHORT_BYTES))) + { + uintptr_t print_dst = 0; + // Format bytes from data by moving into print_dst for log output + for (unsigned i = 0; i < remainder; ++i) + print_dst |= (((data >> i*8) & 0xFF) << i*8); + log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, + (void*)vm_addr, print_dst, (unsigned long)data); + } + vm_addr += word_size; + dst += word_size; + } + + if (log) + ProcessPOSIXLog::DecNestLevel(); + return Error(); + } + + Error + DoWriteMemory( + lldb::pid_t pid, + lldb::addr_t vm_addr, + const void *buf, + size_t size, + size_t &bytes_written) + { + // ptrace word size is determined by the host, not the child + static const unsigned word_size = sizeof(void*); + const unsigned char *src = static_cast<const unsigned char*>(buf); + size_t remainder; + Error error; + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); + if (log) + ProcessPOSIXLog::IncNestLevel(); + if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) + log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %u, %p, %p, %" PRIu64 ")", __FUNCTION__, + pid, word_size, (void*)vm_addr, buf, size); + + for (bytes_written = 0; bytes_written < size; bytes_written += remainder) + { + remainder = size - bytes_written; + remainder = remainder > word_size ? word_size : remainder; + + if (remainder == word_size) + { + unsigned long data = 0; + assert(sizeof(data) >= word_size); + for (unsigned i = 0; i < word_size; ++i) + data |= (unsigned long)src[i] << i*8; + + if (log && ProcessPOSIXLog::AtTopNestLevel() && + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && + size <= POSIX_LOG_MEMORY_SHORT_BYTES))) + log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, + (void*)vm_addr, *(const unsigned long*)src, data); + + error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data); + if (error.Fail()) + { + if (log) + ProcessPOSIXLog::DecNestLevel(); + return error; + } + } + else + { + unsigned char buff[8]; + size_t bytes_read; + error = DoReadMemory(pid, vm_addr, buff, word_size, bytes_read); + if (error.Fail()) + { + if (log) + ProcessPOSIXLog::DecNestLevel(); + return error; + } + + memcpy(buff, src, remainder); + + size_t bytes_written_rec; + error = DoWriteMemory(pid, vm_addr, buff, word_size, bytes_written_rec); + if (error.Fail()) + { + if (log) + ProcessPOSIXLog::DecNestLevel(); + return error; + } + + if (log && ProcessPOSIXLog::AtTopNestLevel() && + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || + (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && + size <= POSIX_LOG_MEMORY_SHORT_BYTES))) + log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, + (void*)vm_addr, *(const unsigned long*)src, *(unsigned long*)buff); + } + + vm_addr += word_size; + src += word_size; + } + if (log) + ProcessPOSIXLog::DecNestLevel(); + return error; + } } // end of anonymous namespace // Simple helper function to ensure flags are enabled on the given file @@ -239,6 +389,406 @@ EnsureFDFlags(int fd, int flags) 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<InitialOperation> 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<Monitor *>(arg)->MainLoop(); + return nullptr; +} + + NativeProcessLinux::LaunchArgs::LaunchArgs(Module *module, char const **argv, char const **envp, @@ -269,7 +819,6 @@ Error NativeProcessProtocol::Launch ( ProcessLaunchInfo &launch_info, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -356,7 +905,6 @@ NativeProcessProtocol::Launch ( } std::static_pointer_cast<NativeProcessLinux> (native_process_sp)->LaunchInferior ( - mainloop, exe_module_sp.get(), launch_info.GetArguments ().GetConstArgumentVector (), launch_info.GetEnvironmentEntries ().GetConstArgumentVector (), @@ -384,7 +932,6 @@ Error NativeProcessProtocol::Attach ( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -411,7 +958,7 @@ NativeProcessProtocol::Attach ( return error; } - native_process_linux_sp->AttachToInferior (mainloop, pid, error); + native_process_linux_sp->AttachToInferior (pid, error); if (!error.Success ()) return error; @@ -432,9 +979,12 @@ NativeProcessLinux::NativeProcessLinux () : { } +//------------------------------------------------------------------------------ +// 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[], @@ -445,11 +995,6 @@ NativeProcessLinux::LaunchInferior ( 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 (); @@ -463,21 +1008,18 @@ NativeProcessLinux::LaunchInferior ( working_dir, launch_info)); - Launch(args.get(), error); + StartMonitorThread ([&] (Error &e) { return Launch(args.get(), e); }, error); + if (!error.Success ()) + return; } void -NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error) +NativeProcessLinux::AttachToInferior (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) @@ -515,7 +1057,15 @@ NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error m_pid = pid; SetState(eStateAttaching); - Attach(pid, error); + StartMonitorThread ([=] (Error &e) { return Attach(pid, e); }, error); + if (!error.Success ()) + return; +} + +void +NativeProcessLinux::Terminate () +{ + m_monitor_up->Terminate(); } ::pid_t @@ -1737,6 +2287,7 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions) bool software_single_step = !SupportHardwareSingleStepping(); + Monitor::ScopedOperationLock monitor_lock(*m_monitor_up); Mutex::Locker locker (m_threads_mutex); if (software_single_step) @@ -1856,7 +2407,7 @@ NativeProcessLinux::Detach () error = Detach (GetID ()); // Stop monitoring the inferior. - m_sigchld_handle.reset(); + m_monitor_up->Terminate(); // No error. return error; @@ -1891,6 +2442,7 @@ NativeProcessLinux::Interrupt () 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) @@ -2546,6 +3098,24 @@ NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info) #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()) { @@ -2574,52 +3144,7 @@ NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, size_t size, size_ // the call failed for some reason, let's retry the read using ptrace api. } - unsigned char *dst = static_cast<unsigned char*>(buf); - size_t remainder; - long data; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); - if (log) - ProcessPOSIXLog::IncNestLevel(); - if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) - log->Printf ("NativeProcessLinux::%s(%p, %p, %zd, _)", __FUNCTION__, (void*)addr, buf, size); - - for (bytes_read = 0; bytes_read < size; bytes_read += remainder) - { - Error error = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKDATA, GetID(), (void*)addr, nullptr, 0, &data); - if (error.Fail()) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return error; - } - - remainder = size - bytes_read; - remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; - - // Copy the data into our buffer - for (unsigned i = 0; i < remainder; ++i) - dst[i] = ((data >> i*8) & 0xFF); - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - { - uintptr_t print_dst = 0; - // Format bytes from data by moving into print_dst for log output - for (unsigned i = 0; i < remainder; ++i) - print_dst |= (((data >> i*8) & 0xFF) << i*8); - log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)addr, print_dst, (unsigned long)data); - } - addr += k_ptrace_word_size; - dst += k_ptrace_word_size; - } - - if (log) - ProcessPOSIXLog::DecNestLevel(); - return Error(); + return DoOperation([&] { return DoReadMemory(GetID(), addr, buf, size, bytes_read); }); } Error @@ -2633,79 +3158,7 @@ NativeProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t s Error NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) { - const unsigned char *src = static_cast<const unsigned char*>(buf); - size_t remainder; - Error error; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); - if (log) - ProcessPOSIXLog::IncNestLevel(); - if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) - log->Printf ("NativeProcessLinux::%s(%p, %p, %" PRIu64 ")", __FUNCTION__, (void*)addr, buf, size); - - for (bytes_written = 0; bytes_written < size; bytes_written += remainder) - { - remainder = size - bytes_written; - remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; - - if (remainder == k_ptrace_word_size) - { - unsigned long data = 0; - for (unsigned i = 0; i < k_ptrace_word_size; ++i) - data |= (unsigned long)src[i] << i*8; - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)addr, *(const unsigned long*)src, data); - - error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, GetID(), (void*)addr, (void*)data); - if (error.Fail()) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return error; - } - } - else - { - unsigned char buff[8]; - size_t bytes_read; - error = ReadMemory(addr, buff, k_ptrace_word_size, bytes_read); - if (error.Fail()) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return error; - } - - memcpy(buff, src, remainder); - - size_t bytes_written_rec; - error = WriteMemory(addr, buff, k_ptrace_word_size, bytes_written_rec); - if (error.Fail()) - { - if (log) - ProcessPOSIXLog::DecNestLevel(); - return error; - } - - if (log && ProcessPOSIXLog::AtTopNestLevel() && - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || - (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && - size <= POSIX_LOG_MEMORY_SHORT_BYTES))) - log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, - (void*)addr, *(const unsigned long*)src, *(unsigned long*)buff); - } - - addr += k_ptrace_word_size; - src += k_ptrace_word_size; - } - if (log) - ProcessPOSIXLog::DecNestLevel(); - return error; + return DoOperation([&] { return DoWriteMemory(GetID(), addr, buf, size, bytes_written); }); } Error @@ -2724,7 +3177,7 @@ NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo) if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - Error error = PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data); + Error error = DoOperation([&] { return PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data); }); if (log) log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " result = %s", __FUNCTION__, tid, error.Success() ? "true" : "false"); @@ -2739,19 +3192,19 @@ NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo) if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - return PtraceWrapper(PTRACE_SINGLESTEP, tid, nullptr, (void*)data); + return DoOperation([&] { return PtraceWrapper(PTRACE_SINGLESTEP, tid, nullptr, (void*)data); }); } Error NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) { - return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); + return DoOperation([&] { return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); }); } Error NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message) { - return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); + return DoOperation([&] { return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); }); } Error @@ -2760,7 +3213,7 @@ NativeProcessLinux::Detach(lldb::tid_t tid) if (tid == LLDB_INVALID_THREAD_ID) return Error(); - return PtraceWrapper(PTRACE_DETACH, tid); + return DoOperation([&] { return PtraceWrapper(PTRACE_DETACH, tid); }); } bool @@ -2777,6 +3230,16 @@ NativeProcessLinux::DupDescriptor(const FileSpec &file_spec, int fd, int flags) 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) { @@ -3245,65 +3708,10 @@ NativeProcessLinux::ThreadWasCreated (lldb::tid_t tid) } } -void -NativeProcessLinux::SigchldHandler() +Error +NativeProcessLinux::DoOperation(const Operation &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; - - Error error(errno, eErrorTypePOSIX); - if (log) - log->Printf("NativeProcessLinux::%s waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG) failed: %s", - __FUNCTION__, error.AsCString()); - break; - } - - bool exited = false; - int signal = 0; - int exit_status = 0; - const char *status_cstr = nullptr; - 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); - } + return m_monitor_up->DoOperation(op); } // Wrapper for ptrace to catch errors and log calls. diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h index 1632f7f6270..e3832d6eab2 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -43,16 +43,25 @@ namespace process_linux { 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, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp); + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_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<Error()> Operation; + // --------------------------------------------------------------------- // NativeProcessProtocol Interface // --------------------------------------------------------------------- @@ -104,9 +113,18 @@ namespace process_linux { 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; @@ -116,6 +134,9 @@ namespace process_linux { // --------------------------------------------------------------------- // Interface used by NativeRegisterContext-derived classes. // --------------------------------------------------------------------- + Error + DoOperation(const Operation &op); + static Error PtraceWrapper(int req, lldb::pid_t pid, @@ -133,9 +154,12 @@ namespace process_linux { private: - MainLoop::SignalHandleUP m_sigchld_handle; + class Monitor; + ArchSpec m_arch; + std::unique_ptr<Monitor> m_monitor_up; + LazyBool m_supports_mem_region; std::vector<MemoryRegionInfo> m_mem_region_cache; Mutex m_mem_region_cache_mutex; @@ -182,7 +206,6 @@ namespace process_linux { /// implementation of Process::DoLaunch. void LaunchInferior ( - MainLoop &mainloop, Module *module, char const *argv[], char const *envp[], @@ -196,7 +219,10 @@ namespace process_linux { /// Attaches to an existing process. Forms the /// implementation of Process::DoAttach void - AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error); + AttachToInferior (lldb::pid_t pid, Error &error); + + void + StartMonitorThread(const InitialOperation &operation, Error &error); ::pid_t Launch(LaunchArgs *args, Error &error); @@ -344,9 +370,6 @@ namespace process_linux { void ThreadWasCreated (lldb::tid_t tid); - void - SigchldHandler(); - // Member variables. PendingNotificationUP m_pending_notification_up; }; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index 9628b4e6f72..41ce680e377 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -50,7 +50,14 @@ NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue &r if (!reg_info) return Error("register %" PRIu32 " not found", reg_index); - return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); + NativeProcessProtocolSP process_sp(m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation([&] { + return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); + }); } Error @@ -101,70 +108,111 @@ NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterV } } + 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); - return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + return process_p->DoOperation([&] { + 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(); - return DoReadGPR(buf, buf_size); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation([&] { 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(); - return DoWriteGPR(buf, buf_size); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation([&] { 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(); - return DoReadFPR(buf, buf_size); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation([&] { 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(); - return DoWriteFPR(buf, buf_size); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation([&] { return DoWriteFPR(buf, buf_size); }); } Error NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), - static_cast<void *>(®set), buf, buf_size); + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + + return process_p->DoOperation([&] { + return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast<void *>(®set), buf, buf_size); + }); } Error NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - static_cast<void *>(®set), buf, buf_size); + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + + return process_p->DoOperation([&] { + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast<void *>(®set), buf, buf_size); + }); } Error diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 6904418644c..308ffe30505 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -715,23 +715,29 @@ Error 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<NativeProcessLinux*>(process_sp.get()); ::pid_t tid = m_thread.GetID(); - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Error error; + return process_p->DoOperation([&] { + 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 @@ -740,26 +746,33 @@ NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(lldb::addr_t *addr_buf, int type, int count) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Error error; + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get()); - memset (&dreg_state, 0, sizeof (dreg_state)); - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof (dreg_state); + return process_p->DoOperation([&] { + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Error error; - if (type == 0) - type = NT_ARM_HW_WATCH; - else - type = NT_ARM_HW_BREAK; + memset (&dreg_state, 0, sizeof (dreg_state)); + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof (dreg_state); - 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]; - } + 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]; + } - 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 diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 917f1351563..50de01ca774 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -877,13 +877,19 @@ NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_ // reading the current state of watch regs struct pt_watch_regs watch_readback; - Error error = DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&watch_readback)); + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + NativeProcessLinux *const process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + Error error = process_p->DoOperation([&] { + return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&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))); - DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&watch_readback)); + process_p->DoOperation([&] { + return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&watch_readback)); + }); is_hit = true; return error; @@ -924,7 +930,11 @@ NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index) struct pt_watch_regs regs; // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void*>(®s)); + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + NativeProcessLinux *const process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + process_p->DoOperation([&] { + return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void*>(®s)); + }); if (regs.style == pt_watch_style_mips32) { @@ -939,7 +949,9 @@ NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index) regs.mips64.watch_masks[wp_index] = default_watch_regs.mips64.watch_masks[wp_index]; } - Error error = DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + Error error = process_p->DoOperation([&] { + return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + }); if(!error.Fail()) { hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS; @@ -951,7 +963,11 @@ NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index) Error NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() { - return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&default_watch_regs)); + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + NativeProcessLinux *const process_p = static_cast<NativeProcessLinux *> (process_sp.get ()); + return process_p->DoOperation([&] { + return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(&default_watch_regs)); + }); } Error @@ -970,7 +986,11 @@ NativeRegisterContextLinux_mips64::SetHardwareWatchpoint ( struct pt_watch_regs regs; // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + NativeProcessLinux *const process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + process_p->DoOperation([&] { + return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + }); // Try if a new watch point fits in this state int index = GetVacantWatchIndex (®s, addr, size, watch_flags, NumSupportedHardwareWatchpoints()); @@ -981,7 +1001,9 @@ NativeRegisterContextLinux_mips64::SetHardwareWatchpoint ( // It fits, so we go ahead with updating the state of watch regs - DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + process_p->DoOperation([&] { + return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + }); // Storing exact address hw_addr_map[index] = addr; @@ -1005,7 +1027,17 @@ NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints () static int num_valid = 0; if (!num_valid) { - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + { + printf ("NativeProcessProtocol is NULL"); + return 0; + } + + NativeProcessLinux *const process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + process_p->DoOperation([&] { + return DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); + }); default_watch_regs = regs; // Keeping default watch regs values for future use switch (regs.style) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index c00ea9257f2..c4523252f19 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -96,6 +96,20 @@ GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( RegisterPacketHandlers(); } +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationServerLLGS::~GDBRemoteCommunicationServerLLGS() +{ + Mutex::Locker locker (m_debugged_process_mutex); + + if (m_debugged_process_sp) + { + m_debugged_process_sp->Terminate (); + m_debugged_process_sp.reset (); + } +} + void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { @@ -209,7 +223,6 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () error = NativeProcessProtocol::Launch( m_process_launch_info, *this, - m_mainloop, m_debugged_process_sp); } @@ -295,7 +308,7 @@ GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) } // Try to attach. - error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, m_debugged_process_sp); + error = NativeProcessProtocol::Attach(pid, *this, m_debugged_process_sp); if (!error.Success ()) { fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 74e3a33c60a..29f3fdebcfb 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -42,6 +42,9 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp, MainLoop &mainloop); + virtual + ~GDBRemoteCommunicationServerLLGS(); + //------------------------------------------------------------------ /// Specify the program to launch and its arguments. /// |