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.      ///  | 

