diff options
Diffstat (limited to 'source/Plugins/Process')
29 files changed, 1894 insertions, 888 deletions
diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp new file mode 100644 index 0000000000000..493f36ca8b48e --- /dev/null +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -0,0 +1,69 @@ +//===-- FreeBSDThread.cpp ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/State.h" + +// Project includes +#include "FreeBSDThread.h" +#include "ProcessFreeBSD.h" +#include "ProcessPOSIXLog.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) +    : POSIXThread(process, tid) +{ +} + +FreeBSDThread::~FreeBSDThread() +{ +} + +//------------------------------------------------------------------------------ +// ProcessInterface protocol. + +void +FreeBSDThread::WillResume(lldb::StateType resume_state) +{ +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); +    if (log) +        log->Printf("tid %lu resume_state = %s", GetID(), +                    lldb_private::StateAsCString(resume_state)); +    ProcessSP process_sp(GetProcess()); +    ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); +    int signo = GetResumeSignal(); +    bool signo_valid = process->GetUnixSignals().SignalIsValid(signo); + +    switch (resume_state) +    { +    case eStateSuspended: +    case eStateStopped: +        process->m_suspend_tids.push_back(GetID()); +        break; +    case eStateRunning: +        process->m_run_tids.push_back(GetID()); +        if (signo_valid) +            process->m_resume_signo = signo; +        break; +    case eStateStepping: +        process->m_step_tids.push_back(GetID()); +        if (signo_valid) +            process->m_resume_signo = signo; +        break;  +    default: +        break; +    } +} diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/source/Plugins/Process/FreeBSD/FreeBSDThread.h new file mode 100644 index 0000000000000..8741075cb60be --- /dev/null +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -0,0 +1,39 @@ +//===-- FreeBSDThread.h -----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FreeBSDThread_H_ +#define liblldb_FreeBSDThread_H_ + +// Other libraries and framework includes +#include "POSIXThread.h" + +//------------------------------------------------------------------------------ +// @class FreeBSDThread +// @brief Abstraction of a FreeBSD thread. +class FreeBSDThread +    : public POSIXThread +{ +public: + +    //------------------------------------------------------------------ +    // Constructors and destructors +    //------------------------------------------------------------------ +    FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); + +    virtual ~FreeBSDThread(); + +    //-------------------------------------------------------------------------- +    // FreeBSDThread internal API. + +    // POSIXThread override +    virtual void +    WillResume(lldb::StateType resume_state); +}; + +#endif // #ifndef liblldb_FreeBSDThread_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 952ec95f5873e..083f08ebba842 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -23,7 +23,7 @@  #include "ProcessPOSIXLog.h"  #include "Plugins/Process/Utility/InferiorCallPOSIX.h"  #include "ProcessMonitor.h" -#include "POSIXThread.h" +#include "FreeBSDThread.h"  using namespace lldb;  using namespace lldb_private; @@ -140,29 +140,136 @@ ProcessFreeBSD::DoDetach(bool keep_stopped)      return error;  } +Error +ProcessFreeBSD::DoResume() +{ +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + +    // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent." +    int resume_signal = 0; + +    SetPrivateState(eStateRunning); + +    Mutex::Locker lock(m_thread_list.GetMutex()); +    bool do_step = false; + +    for (tid_collection::const_iterator t_pos = m_run_tids.begin(), t_end = m_run_tids.end(); t_pos != t_end; ++t_pos) +    { +        m_monitor->ThreadSuspend(*t_pos, false); +    } +    for (tid_collection::const_iterator t_pos = m_step_tids.begin(), t_end = m_step_tids.end(); t_pos != t_end; ++t_pos) +    { +        m_monitor->ThreadSuspend(*t_pos, false); +        do_step = true; +    } +    for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), t_end = m_suspend_tids.end(); t_pos != t_end; ++t_pos) +    { +        m_monitor->ThreadSuspend(*t_pos, true); +        // XXX Cannot PT_CONTINUE properly with suspended threads. +        do_step = true; +    } + +    if (log) +        log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue"); +    if (do_step) +        m_monitor->SingleStep(GetID(), resume_signal); +    else +        m_monitor->Resume(GetID(), resume_signal); + +    return Error(); +} +  bool  ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)  { -    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); -    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) -        log->Printf ("ProcessFreeBSD::%s() (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - -    bool has_updated = false; -    const lldb::pid_t pid = GetID(); -    // Update the process thread list with this new thread. -    // FIXME: We should be using tid, not pid. -    assert(m_monitor); -    ThreadSP thread_sp (old_thread_list.FindThreadByID (pid, false)); -    if (!thread_sp) { -        ProcessSP me = this->shared_from_this(); -        thread_sp.reset(new POSIXThread(*me, pid)); -        has_updated = true; +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); +    if (log) +        log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); + +    std::vector<lldb::pid_t> tds; +    if (!GetMonitor().GetCurrentThreadIDs(tds)) +    { +        return false;      } -    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) -        log->Printf ("ProcessFreeBSD::%s() updated tid = %" PRIu64, __FUNCTION__, pid); +    ThreadList old_thread_list_copy(old_thread_list); +    for (size_t i = 0; i < tds.size(); ++i) +    { +        tid_t tid = tds[i]; +        ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false)); +        if (!thread_sp) +        { +            thread_sp.reset(new FreeBSDThread(*this, tid)); +            if (log) +                log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid); +        } +        else +        { +            if (log) +                log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid); +        } +        new_thread_list.AddThread(thread_sp); +    } +    for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) +    { +        ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); +        if (old_thread_sp) +        { +            if (log) +                log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__); +        } +    } -    new_thread_list.AddThread(thread_sp); +    return true; +} -    return has_updated; // the list has been updated +Error +ProcessFreeBSD::WillResume() +{ +    m_suspend_tids.clear(); +    m_run_tids.clear(); +    m_step_tids.clear(); +    return ProcessPOSIX::WillResume();  } + +void +ProcessFreeBSD::SendMessage(const ProcessMessage &message) +{ +    Mutex::Locker lock(m_message_mutex); + +    switch (message.GetKind()) +    { +    case ProcessMessage::eInvalidMessage: +        return; + +    case ProcessMessage::eAttachMessage: +        SetPrivateState(eStateStopped); +        return; + +    case ProcessMessage::eLimboMessage: +    case ProcessMessage::eExitMessage: +        m_exit_status = message.GetExitStatus(); +        SetExitStatus(m_exit_status, NULL); +        break; + +    case ProcessMessage::eSignalMessage: +    case ProcessMessage::eSignalDeliveredMessage: +    case ProcessMessage::eBreakpointMessage: +    case ProcessMessage::eTraceMessage: +    case ProcessMessage::eWatchpointMessage: +    case ProcessMessage::eCrashMessage: +        SetPrivateState(eStateStopped); +        break; + +    case ProcessMessage::eNewThreadMessage: +        assert(0 && "eNewThreadMessage unexpected on FreeBSD"); +        break; + +    case ProcessMessage::eExecMessage: +        SetPrivateState(eStateStopped); +        break; +    } + +    m_message_queue.push(message); +} + diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h index fb549745b80c6..d6ae3462c73b1 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h @@ -60,6 +60,15 @@ public:      virtual bool      UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list); +    virtual lldb_private::Error +    DoResume(); + +    virtual lldb_private::Error +    WillResume(); + +    virtual void +    SendMessage(const ProcessMessage &message); +      //------------------------------------------------------------------      // PluginInterface protocol      //------------------------------------------------------------------ @@ -80,6 +89,16 @@ public:      EnablePluginLogging(lldb_private::Stream *strm,                          lldb_private::Args &command); +protected: +    friend class FreeBSDThread; + +    typedef std::vector<lldb::tid_t> tid_collection; +    tid_collection m_suspend_tids; +    tid_collection m_run_tids; +    tid_collection m_step_tids; + +    int m_resume_signo; +  }; -#endif  // liblldb_MacOSXProcess_H_ +#endif  // liblldb_ProcessFreeBSD_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index ac5357916501e..3b260538b1907 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -560,6 +560,31 @@ LwpInfoOperation::Execute(ProcessMonitor *monitor)  }  //------------------------------------------------------------------------------ +/// @class ThreadSuspendOperation +/// @brief Implements ProcessMonitor::ThreadSuspend. +class ThreadSuspendOperation : public Operation +{ +public: +    ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) +        : m_tid(tid), m_suspend(suspend), m_result(result) { } + +    void Execute(ProcessMonitor *monitor); + +private: +    lldb::tid_t m_tid; +    bool m_suspend; +    bool &m_result; +} ; + +void +ThreadSuspendOperation::Execute(ProcessMonitor *monitor) +{ +    m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0); +} + + + +//------------------------------------------------------------------------------  /// @class EventMessageOperation  /// @brief Implements ProcessMonitor::GetEventMessage.  class EventMessageOperation : public Operation @@ -871,7 +896,8 @@ ProcessMonitor::Launch(LaunchArgs *args)          eDupStdoutFailed,          eDupStderrFailed,          eChdirFailed, -        eExecFailed +        eExecFailed, +        eSetGidFailed      };      // Child process. @@ -882,7 +908,8 @@ ProcessMonitor::Launch(LaunchArgs *args)              exit(ePtraceFailed);          // Do not inherit setgid powers. -        setgid(getgid()); +        if (setgid(getgid()) != 0) +            exit(eSetGidFailed);          // Let us have our own process group.          setpgid(0, 0); @@ -947,6 +974,9 @@ ProcessMonitor::Launch(LaunchArgs *args)              case eExecFailed:                  args->m_error.SetErrorString("Child exec failed.");                  break; +            case eSetGidFailed: +                args->m_error.SetErrorString("Child setgid failed."); +                break;              default:                  args->m_error.SetErrorString("Child returned unknown exit status.");                  break; @@ -1041,6 +1071,29 @@ FINISH:      return args->m_error.Success();  } +size_t +ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t>&thread_ids) +{ +    lwpid_t *tids; +    int tdcnt; + +    thread_ids.clear(); + +    tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0); +    if (tdcnt <= 0) +        return 0; +    tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids)); +    if (tids == NULL) +        return 0; +    if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) { +        free(tids); +        return 0; +    } +    thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt); +    free(tids); +    return thread_ids.size(); +} +  bool  ProcessMonitor::MonitorCallback(void *callback_baton,                                  lldb::pid_t pid, @@ -1073,11 +1126,11 @@ ProcessMonitor::MonitorCallback(void *callback_baton,          switch (plwp.pl_siginfo.si_signo)          {          case SIGTRAP: -            message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, pid); +            message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid);              break;          default: -            message = MonitorSignal(monitor, &plwp.pl_siginfo, pid); +            message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid);              break;          } @@ -1090,7 +1143,7 @@ ProcessMonitor::MonitorCallback(void *callback_baton,  ProcessMessage  ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, -                               const siginfo_t *info, lldb::pid_t pid) +                               const siginfo_t *info, lldb::tid_t tid)  {      ProcessMessage message; @@ -1111,26 +1164,26 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,          // state of "limbo" until we are explicitly commanded to detach,          // destroy, resume, etc.          unsigned long data = 0; -        if (!monitor->GetEventMessage(pid, &data)) +        if (!monitor->GetEventMessage(tid, &data))              data = -1;          if (log) -            log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid); -        message = ProcessMessage::Limbo(pid, (data >> 8)); +            log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, tid = %" PRIu64, __FUNCTION__, data, tid); +        message = ProcessMessage::Limbo(tid, (data >> 8));          break;      }      case 0:      case TRAP_TRACE:          if (log) -            log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid); -        message = ProcessMessage::Trace(pid); +            log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64, __FUNCTION__, tid); +        message = ProcessMessage::Trace(tid);          break;      case SI_KERNEL:      case TRAP_BRKPT:          if (log) -            log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid); -        message = ProcessMessage::Break(pid); +            log->Printf ("ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, __FUNCTION__, tid); +        message = ProcessMessage::Break(tid);          break;      } @@ -1139,7 +1192,7 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,  ProcessMessage  ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, -                              const siginfo_t *info, lldb::pid_t pid) +                              const siginfo_t *info, lldb::tid_t tid)  {      ProcessMessage message;      int signo = info->si_signo; @@ -1163,9 +1216,9 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,                              "SI_USER",                              info->si_pid);          if (info->si_pid == getpid()) -            return ProcessMessage::SignalDelivered(pid, signo); +            return ProcessMessage::SignalDelivered(tid, signo);          else -            return ProcessMessage::Signal(pid, signo); +            return ProcessMessage::Signal(tid, signo);      }      if (log) @@ -1174,30 +1227,30 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,      if (signo == SIGSEGV) {          lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);          ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info); -        return ProcessMessage::Crash(pid, reason, signo, fault_addr); +        return ProcessMessage::Crash(tid, reason, signo, fault_addr);      }      if (signo == SIGILL) {          lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);          ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info); -        return ProcessMessage::Crash(pid, reason, signo, fault_addr); +        return ProcessMessage::Crash(tid, reason, signo, fault_addr);      }      if (signo == SIGFPE) {          lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);          ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info); -        return ProcessMessage::Crash(pid, reason, signo, fault_addr); +        return ProcessMessage::Crash(tid, reason, signo, fault_addr);      }      if (signo == SIGBUS) {          lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);          ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info); -        return ProcessMessage::Crash(pid, reason, signo, fault_addr); +        return ProcessMessage::Crash(tid, reason, signo, fault_addr);      }      // Everything else is "normal" and does not require any special action on      // our part. -    return ProcessMessage::Signal(pid, signo); +    return ProcessMessage::Signal(tid, signo);  }  ProcessMessage::CrashReason @@ -1508,6 +1561,15 @@ ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)  }  bool +ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend) +{ +    bool result; +    ThreadSuspendOperation op(tid, suspend, result); +    DoOperation(&op); +    return result; +} + +bool  ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)  {      bool result; diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 44219c4eb9e3e..84bbac16e5e5b 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -104,8 +104,6 @@ public:      /// dependent) offset.      ///      /// This method is provided for use by RegisterContextFreeBSD derivatives. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,                        unsigned size, lldb_private::RegisterValue &value); @@ -114,49 +112,35 @@ public:      /// (architecture dependent) offset.      ///      /// This method is provided for use by RegisterContextFreeBSD derivatives. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,                         const lldb_private::RegisterValue &value);      /// Reads all general purpose registers into the specified buffer. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);      /// Reads all floating point registers into the specified buffer. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);      /// Reads the specified register set into the specified buffer.      ///      /// This method is provided for use by RegisterContextFreeBSD derivatives. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);      /// Writes all general purpose registers into the specified buffer. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);      /// Writes all floating point registers into the specified buffer. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);      /// Writes the specified register set into the specified buffer.      ///      /// This method is provided for use by RegisterContextFreeBSD derivatives. -    /// FIXME: The FreeBSD implementation of this function should use tid in order -    ///        to enable support for debugging threaded programs.      bool      WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); @@ -164,11 +148,19 @@ public:      bool      ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); +    /// Returns current thread IDs in process +    size_t +    GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids); +      /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID      /// to the memory region pointed to by @p lwpinfo.      bool      GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no); +    /// Suspends or unsuspends a thread prior to process resume or step. +    bool +    ThreadSuspend(lldb::tid_t tid, bool suspend); +      /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)      /// corresponding to the given thread IDto the memory pointed to by @p      /// message. diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp index 16399748c5443..8d4c71ff269a9 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -83,6 +83,7 @@ POSIXThread::GetMonitor()      return process.GetMonitor();  } +// Overridden by FreeBSDThread; this is used only on Linux.  void  POSIXThread::RefreshStateAfterStop()  { @@ -150,8 +151,6 @@ POSIXThread::GetRegisterContext()          {              case ArchSpec::eCore_mips64:              { -                RegisterInfoInterface *reg_interface = NULL; -                  switch (target_arch.GetTriple().getOS())                  {                      case llvm::Triple::FreeBSD: @@ -257,6 +256,7 @@ POSIXThread::GetUnwinder()      return m_unwinder_ap.get();  } +// Overridden by FreeBSDThread; this is used only on Linux.  void  POSIXThread::WillResume(lldb::StateType resume_state)  { diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 70ad3a66d9ef2..62394623c59d9 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -200,7 +200,7 @@ ProcessPOSIX::GetFilePath(  Error  ProcessPOSIX::DoLaunch (Module *module, -                       const ProcessLaunchInfo &launch_info) +                        ProcessLaunchInfo &launch_info)  {      Error error;      assert(m_monitor == NULL); @@ -632,20 +632,6 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)      return error;  } -addr_t -ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error) -{ -    addr_t function_addr = LLDB_INVALID_ADDRESS; -    if (address == NULL) { -        error.SetErrorStringWithFormat("unable to determine direct function call for NULL address"); -    } else if (!InferiorCall(this, address, function_addr)) { -        function_addr = LLDB_INVALID_ADDRESS; -        error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s", -                                       address->CalculateSymbolContextSymbol()->GetName().AsCString()); -    } -    return function_addr; -} -  size_t  ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)  { diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h index 790041be321a9..7f705d33fe68c 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -58,7 +58,7 @@ public:      virtual lldb_private::Error      DoLaunch (lldb_private::Module *exe_module,  -              const lldb_private::ProcessLaunchInfo &launch_info); +              lldb_private::ProcessLaunchInfo &launch_info);      virtual void      DidLaunch(); @@ -104,9 +104,6 @@ public:      virtual lldb_private::Error      DoDeallocateMemory(lldb::addr_t ptr); -    virtual lldb::addr_t -    ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error); -      virtual size_t      GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); @@ -148,7 +145,8 @@ public:      // ProcessPOSIX internal API.      /// Registers the given message with this process. -    void SendMessage(const ProcessMessage &message); +    virtual void +    SendMessage(const ProcessMessage &message);      ProcessMonitor &      GetMonitor() { assert(m_monitor); return *m_monitor; } diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp index 521136295fd5a..d045bc7e10d7f 100644 --- a/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -25,7 +25,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process,                                std::vector<lldb::addr_t> pcs,                                 uint32_t stop_id,                                 bool stop_id_is_valid) :  -        Thread (process, LLDB_INVALID_THREAD_ID), +        Thread (process, tid),          m_framelist_mutex(),          m_framelist(),          m_pcs (pcs), diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h index 01fdd1608706f..f9a431d8340b9 100644 --- a/source/Plugins/Process/Utility/HistoryThread.h +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -22,6 +22,16 @@  namespace lldb_private { +//---------------------------------------------------------------------- +/// @class HistoryThread HistoryThread.h "HistoryThread.h" +/// @brief A thread object representing a backtrace from a previous point in the process execution +/// +/// This subclass of Thread is used to provide a backtrace from earlier in +/// process execution.  It is given a backtrace list of pc addresses and  +/// optionally a stop_id of when those pc addresses were collected, and it will +/// create stack frames for them. +//---------------------------------------------------------------------- +  class HistoryThread : public lldb_private::Thread  {  public: diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 6d1b04f7f1a77..1d5d19fad25f3 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -34,9 +34,16 @@  using namespace lldb;  using namespace lldb_private; -bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, -                                    addr_t addr, addr_t length, unsigned prot, -                                    unsigned flags, addr_t fd, addr_t offset) { +bool +lldb_private::InferiorCallMmap (Process *process, +                                addr_t &allocated_addr, +                                addr_t addr, +                                addr_t length, +                                unsigned prot, +                                unsigned flags, +                                addr_t fd, +                                addr_t offset) +{      Thread *thread = process->GetThreadList().GetSelectedThread().get();      if (thread == NULL)          return false; @@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,      return false;  } -bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, -                                      addr_t length) { +bool +lldb_private::InferiorCallMunmap (Process *process, +                                  addr_t addr, +                                  addr_t length) +{     Thread *thread = process->GetThreadList().GetSelectedThread().get();     if (thread == NULL)         return false; @@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,      return false;  } -bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { +// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a +// function of the form "void * (*)(void)".  We should find a better place to put this. + +bool +lldb_private::InferiorCall (Process *process, +                            const Address *address, +                            addr_t &returned_func) +{      Thread *thread = process->GetThreadList().GetSelectedThread().get();      if (thread == NULL || address == NULL)          return false; @@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t      lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);      if (call_plan_sp)      { -        StreamFile error_strm; +        StreamString error_strm;          // This plan is a utility plan, so set it to discard itself when done.          call_plan_sp->SetIsMasterPlan (true);          call_plan_sp->SetOkayToDiscard(true); diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index c19aec3a02c7d..f87db58107406 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -21,15 +21,17 @@  #include "lldb/Symbol/FuncUnwinders.h"  #include "lldb/Symbol/Function.h"  #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolContext.h"  #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h"  #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h"  #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h"  #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h"  #include "lldb/Target/StackFrame.h"  #include "lldb/Target/Target.h"  #include "lldb/Target/Thread.h" -#include "lldb/Target/DynamicLoader.h"  #include "RegisterContextLLDB.h" @@ -75,13 +77,44 @@ RegisterContextLLDB::RegisterContextLLDB      // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet      if (IsFrameZero() -        || next_frame->m_frame_type == eSigtrampFrame +        || next_frame->m_frame_type == eTrapHandlerFrame          || next_frame->m_frame_type == eDebuggerFrame)      {          m_all_registers_available = true;      }  } +bool +RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) +{ +    if (!unwind_plan_sp) +        return false; + +    // check if m_current_pc is valid +    if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) +    { +        // yes - current offset can be used as is +        valid_pc_offset = m_current_offset; +        return true; +    } + +    // if m_current_offset <= 0, we've got nothing else to try +    if (m_current_offset <= 0) +        return false; + +    // check pc - 1 to see if it's valid +    Address pc_minus_one (m_current_pc); +    pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); +    if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) +    { +        // *valid_pc_offset = m_current_offset - 1; +        valid_pc_offset = m_current_pc.GetOffset() - 1; +        return true; +    } + +    return false; +} +  // Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently  // executing frame. @@ -95,6 +128,7 @@ RegisterContextLLDB::InitializeZerothFrame()      if (reg_ctx_sp.get() == NULL)      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("frame does not have a register context");          return;      } @@ -103,6 +137,7 @@ RegisterContextLLDB::InitializeZerothFrame()      if (current_pc == LLDB_INVALID_ADDRESS)      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("frame does not have a pc");          return;      } @@ -117,7 +152,7 @@ RegisterContextLLDB::InitializeZerothFrame()          current_pc = abi->FixCodeAddress(current_pc);      // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. -    process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc); +    m_current_pc.SetLoadAddress (current_pc, &process->GetTarget());      // If we don't have a Module for some reason, we're not going to find symbol/function information - just      // stick in some reasonable defaults and hope we can unwind past this frame. @@ -137,11 +172,9 @@ RegisterContextLLDB::InitializeZerothFrame()      AddressRange addr_range;      m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); -    static ConstString g_sigtramp_name ("_sigtramp"); -    if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || -        (m_sym_ctx.symbol   && m_sym_ctx.symbol->GetName()   == g_sigtramp_name)) +    if (IsTrapHandlerSymbol (process, m_sym_ctx))      { -        m_frame_type = eSigtrampFrame; +        m_frame_type = eTrapHandlerFrame;      }      else      { @@ -197,6 +230,7 @@ RegisterContextLLDB::InitializeZerothFrame()      if (!active_row.get())      { +        UnwindLogMsg ("could not find an unwindplan row for this frame's pc");          m_frame_type = eNotAValidFrame;          return;      } @@ -205,6 +239,7 @@ RegisterContextLLDB::InitializeZerothFrame()      addr_t cfa_regval = LLDB_INVALID_ADDRESS;      if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))      { +        UnwindLogMsg ("could not read CFA register for this frame.");          m_frame_type = eNotAValidFrame;          return;      } @@ -229,17 +264,20 @@ RegisterContextLLDB::InitializeNonZerothFrame()      if (IsFrameZero ())      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen.");          return;      }      if (!GetNextFrame().get() || !GetNextFrame()->IsValid())      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("Could not get next frame, marking this frame as invalid.");          return;      }      if (!m_thread.GetRegisterContext())      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid.");          return;      } @@ -265,6 +303,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()      if (pc == 0)      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("this frame has a pc of 0x0");          return;      } @@ -276,7 +315,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()      if (abi)          pc = abi->FixCodeAddress(pc); -    process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc); +    m_current_pc.SetLoadAddress (pc, &process->GetTarget());      // If we don't have a Module for some reason, we're not going to find symbol/function information - just      // stick in some reasonable defaults and hope we can unwind past this frame. @@ -304,6 +343,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()              {                  // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.                  m_frame_type = eNotAValidFrame; +                UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk.");                  return;              }          } @@ -352,6 +392,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()                      && (permissions & ePermissionsReadable) == 0)                  {                      m_frame_type = eNotAValidFrame; +                    UnwindLogMsg ("the CFA points to a region of memory that is not readable");                      return;                  }              } @@ -366,10 +407,15 @@ RegisterContextLLDB::InitializeNonZerothFrame()              return;          }          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind.");          return;      }      bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... +                                           // This will handle the case where the saved pc does not point to  +                                           // a function/symbol because it is beyond the bounds of the correct +                                           // function and there's no symbol there.  ResolveSymbolContextForAddress +                                           // will fail to find a symbol, back up the pc by 1 and re-search.      uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,                                                                              eSymbolContextFunction | eSymbolContextSymbol,                                                                              m_sym_ctx, resolve_tail_call_address); @@ -392,18 +438,35 @@ RegisterContextLLDB::InitializeNonZerothFrame()      if (m_sym_ctx_valid == false)         decr_pc_and_recompute_addr_range = true; -    // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and -    // our "current" pc is the start of a function or our "current" pc is one past the end of a function... +    // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), +    // and our "current" pc is the start of a function...      if (m_sym_ctx_valid -        && GetNextFrame()->m_frame_type != eSigtrampFrame +        && GetNextFrame()->m_frame_type != eTrapHandlerFrame          && GetNextFrame()->m_frame_type != eDebuggerFrame          && addr_range.GetBaseAddress().IsValid() -        && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) +        && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() +        && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())      { -        if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || -            addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) +        decr_pc_and_recompute_addr_range = true; +    } + +    // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" +    // value is pointing to the next function, e.g. if a function ends with a CALL instruction. +    // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function +    // to the ABI plugin and consult that. +    if (decr_pc_and_recompute_addr_range) +    { +        Address temporary_pc(m_current_pc); +        temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); +        m_sym_ctx.Clear(false); +        m_sym_ctx_valid = false; +        if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) +        { +            m_sym_ctx_valid = true; +        } +        if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false,  addr_range))          { -            decr_pc_and_recompute_addr_range = true; +            m_sym_ctx_valid = false;          }      } @@ -428,11 +491,9 @@ RegisterContextLLDB::InitializeNonZerothFrame()          m_current_offset_backed_up_one = -1;      } -    static ConstString sigtramp_name ("_sigtramp"); -    if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name) -        || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name)) +    if (IsTrapHandlerSymbol (process, m_sym_ctx))      { -        m_frame_type = eSigtrampFrame; +        m_frame_type = eTrapHandlerFrame;      }      else      { @@ -467,9 +528,10 @@ RegisterContextLLDB::InitializeNonZerothFrame()      else      {          m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); -        if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) +        int valid_offset = -1; +        if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset))          { -            active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); +            active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset);              row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();              if (active_row.get() && log)              { @@ -483,6 +545,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()      if (!active_row.get())      {          m_frame_type = eNotAValidFrame; +        UnwindLogMsg ("could not find unwind row for this pc");          return;      } @@ -551,7 +614,7 @@ RegisterContextLLDB::IsFrameZero () const  //  // On entry to this method,  // -//   1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +//   1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,  //   2. m_sym_ctx should already be filled in, and  //   3. m_current_pc should have the current pc value for this frame  //   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -573,7 +636,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()          return unwind_plan_sp;      // If we're in _sigtramp(), unwinding past this frame requires special knowledge. -    if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) +    if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)          return unwind_plan_sp;      unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); @@ -602,7 +665,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()  // On entry to this method,  // -//   1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +//   1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,  //   2. m_sym_ctx should already be filled in, and  //   3. m_current_pc should have the current pc value for this frame  //   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -627,7 +690,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()      bool behaves_like_zeroth_frame = false;      if (IsFrameZero () -        || GetNextFrame()->m_frame_type == eSigtrampFrame +        || GetNextFrame()->m_frame_type == eTrapHandlerFrame          || GetNextFrame()->m_frame_type == eDebuggerFrame)      {          behaves_like_zeroth_frame = true; @@ -648,7 +711,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()          uint32_t permissions;          addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());          if (current_pc_addr == 0 -            || (process->GetLoadAddressPermissions(current_pc_addr, permissions) +            || (process->GetLoadAddressPermissions (current_pc_addr, permissions)                  && (permissions & ePermissionsExecutable) == 0))          {              unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); @@ -697,7 +760,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()      // is properly encoded in the eh_frame section, so prefer that if available.      // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of      // how to unwind out of sigtramp. -    if (m_frame_type == eSigtrampFrame) +    if (m_frame_type == eTrapHandlerFrame)      {          m_fast_unwind_plan_sp.reset();          unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); @@ -735,7 +798,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()      // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites      unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); -    if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) +    int valid_offset = -1; +    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))      {          UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());          return unwind_plan_sp; @@ -744,7 +808,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()      // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've      // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.      unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); -    if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) +    if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))      {          UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());          return unwind_plan_sp; @@ -915,6 +979,12 @@ RegisterContextLLDB::IsValid () const      return m_frame_type != eNotAValidFrame;  } +bool +RegisterContextLLDB::IsTrapHandlerFrame () const +{ +    return m_frame_type == eTrapHandlerFrame; +} +  // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther  // up the stack if we keep looking.  It's always the second frame in an unwind (i.e. the first frame after  // frame zero) where unwinding can be the trickiest.  Ideally we'll mark up this frame in some way so the @@ -927,6 +997,35 @@ RegisterContextLLDB::IsSkipFrame () const      return m_frame_type == eSkipFrame;  } +bool +RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const +{ +    PlatformSP platform_sp (process->GetTarget().GetPlatform()); +    if (platform_sp) +    { +        const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); +        for (ConstString name : trap_handler_names) +        { +            if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || +                (m_sym_ctx.symbol   && m_sym_ctx.symbol->GetName()   == name)) +            { +                return true; +            } +        } +    } +    const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames()); +    for (ConstString name : user_specified_trap_handler_names) +    {    +        if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || +            (m_sym_ctx.symbol   && m_sym_ctx.symbol->GetName()   == name)) +        {    +            return true; +        }    +    }    + +    return false; +} +  // Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?  enum UnwindLLDB::RegisterSearchResult @@ -1161,7 +1260,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat          regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;          regloc.location.inferred_value = m_cfa + offset;          m_registers[lldb_regnum] = regloc; -        UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum); +        UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset);          return UnwindLLDB::RegisterSearchResult::eRegisterFound;      } @@ -1171,7 +1270,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat          regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;          regloc.location.target_memory_location = m_cfa + offset;          m_registers[lldb_regnum] = regloc; -        UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum); +        UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset);          return UnwindLLDB::RegisterSearchResult::eRegisterFound;      } @@ -1550,3 +1649,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)      }  } + diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index dc6d8c61fa4ad..bf9dd9a29319d 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -73,6 +73,9 @@ public:      IsValid () const;      bool +    IsTrapHandlerFrame () const; + +    bool      GetCFA (lldb::addr_t& cfa);      bool @@ -86,7 +89,7 @@ private:      enum FrameType      {          eNormalFrame, -        eSigtrampFrame, +        eTrapHandlerFrame,          eDebuggerFrame,  // a debugger inferior function call frame; we get caller's registers from debugger          eSkipFrame,      // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet          eNotAValidFrame  // this frame is invalid for some reason - most likely it is past the top (end) of the stack @@ -120,6 +123,19 @@ private:      bool      IsSkipFrame () const; + +    //------------------------------------------------------------------ +    /// Determines if a SymbolContext is a trap handler or not +    /// +    /// Given a SymbolContext, determines if this is a trap handler function +    /// aka asynchronous signal handler. +    /// +    /// @return +    ///     Returns true if the SymbolContext is a trap handler. +    //------------------------------------------------------------------ +    bool +    IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const; +      // Provide a location for where THIS function saved the CALLER's register value      // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this      // function didn't modify/use. @@ -164,6 +180,10 @@ private:      void      UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +    bool +    IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset); + +      lldb_private::Thread& m_thread;      /// diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 552ae501bd212..a3a7002ea099c 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -26,8 +26,21 @@ using namespace lldb_private;  UnwindLLDB::UnwindLLDB (Thread &thread) :      Unwind (thread),      m_frames(), -    m_unwind_complete(false) +    m_unwind_complete(false), +    m_user_supplied_trap_handler_functions()  { +    ProcessSP process_sp(thread.GetProcess()); +    if (process_sp) +    { +        Args args; +        process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames (args); +        size_t count = args.GetArgumentCount(); +        for (size_t i = 0; i < count; i++) +        { +            const char *func_name = args.GetArgumentAtIndex(i); +            m_user_supplied_trap_handler_functions.push_back (ConstString (func_name)); +        } +    }  }  uint32_t @@ -95,7 +108,13 @@ UnwindLLDB::AddFirstFrame ()      first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;      m_frames.push_back (first_cursor_sp);      return true; +  unwind_done: +    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); +    if (log) +    { +        log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); +    }      m_unwind_complete = true;      return false;  } @@ -138,7 +157,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)      }      if (reg_ctx_sp.get() == NULL) +    { +        if (log) +            log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.", +                         cur_idx < 100 ? cur_idx : 100, "", cur_idx);          goto unwind_done; +    }      if (!reg_ctx_sp->IsValid())      { @@ -160,12 +184,18 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)      }      if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))      { -        if (log) +        // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have +        // its (constructed) CFA aligned correctly -- don't do the abi alignment check for +        // these. +        if (reg_ctx_sp->IsTrapHandlerFrame() == false)          { -            log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", -                        cur_idx < 100 ? cur_idx : 100, "", cur_idx); +            if (log) +            { +                log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", +                            cur_idx < 100 ? cur_idx : 100, "", cur_idx); +            } +            goto unwind_done;          } -        goto unwind_done;      }      if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))      { @@ -185,12 +215,26 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)          }          goto unwind_done;      } +    if (!m_frames.empty()) +    { +        // Infinite loop where the current cursor is the same as the previous one... +        if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa) +        { +            if (log) +                log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); +            goto unwind_done;  +        } +    }      cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;      m_frames.push_back (cursor_sp);      return true;  unwind_done: +    if (log) +    { +        log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); +    }      m_unwind_complete = true;      return false;  } diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h index 5725654a6869f..eb5400389df3e 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/source/Plugins/Process/Utility/UnwindLLDB.h @@ -13,6 +13,7 @@  #include <vector>  #include "lldb/lldb-public.h" +#include "lldb/Core/ConstString.h"  #include "lldb/Symbol/FuncUnwinders.h"  #include "lldb/Symbol/UnwindPlan.h"  #include "lldb/Target/RegisterContext.h" @@ -90,6 +91,24 @@ protected:      SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_register); +    //------------------------------------------------------------------ +    /// Provide the list of user-specified trap handler functions +    /// +    /// The Platform is one source of trap handler function names; that +    /// may be augmented via a setting.  The setting needs to be converted +    /// into an array of ConstStrings before it can be used - we only want +    /// to do that once per thread so it's here in the UnwindLLDB object. +    /// +    /// @return +    ///     Vector of ConstStrings of trap handler function names.  May be +    ///     empty. +    //------------------------------------------------------------------ +    const std::vector<ConstString> & +    GetUserSpecifiedTrapHandlerFunctionNames () +    { +        return m_user_supplied_trap_handler_functions; +    } +  private:      struct Cursor @@ -110,6 +129,7 @@ private:                              // number of frames, etc.  Otherwise we've only gone as far as directly asked, and m_frames.size()                              // is how far we've currently gone. +    std::vector<ConstString> m_user_supplied_trap_handler_functions;      bool AddOneMoreFrame (ABI *abi);      bool AddFirstFrame (); diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 93641ede1bc78..7ea5c89e7df4f 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -131,7 +131,8 @@ ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *head      VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();      if (last_entry &&          last_entry->GetRangeEnd() == range_entry.GetRangeBase() && -        last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) +        last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && +        last_entry->GetByteSize() == last_entry->data.GetByteSize())      {          last_entry->SetRangeEnd (range_entry.GetRangeEnd());          last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); @@ -294,9 +295,13 @@ ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &      size_t zero_fill_size = 0;   // Padding      lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address -    if (file_end > offset) -        bytes_left = file_end - offset; +    // Figure out how many on-disk bytes remain in this segment +    // starting at the given offset +    if (file_end > file_start + offset) +        bytes_left = file_end - (file_start + offset); +    // Figure out how many bytes we need to zero-fill if we are +    // reading more bytes than available in the on-disk segment      if (bytes_to_read > bytes_left)      {          zero_fill_size = bytes_to_read - bytes_left; @@ -365,12 +370,12 @@ enum {  // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.  static void -ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, +ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,                       ArchSpec &arch)  {      lldb::offset_t offset = 0; -    bool have_padding = (arch.GetMachine() == llvm::Triple::mips64 || -                         arch.GetMachine() == llvm::Triple::x86_64); +    bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || +                 arch.GetMachine() == llvm::Triple::x86_64);      int pr_version = data.GetU32(&offset);      Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); @@ -380,23 +385,26 @@ ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data,              log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version);      } -    if (have_padding) -        offset += 4; -    offset += 28;       // pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate -    thread_data->signo = data.GetU32(&offset); // pr_cursig +    // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate +    if (lp64) +        offset += 32; +    else +        offset += 16; + +    thread_data.signo = data.GetU32(&offset); // pr_cursig      offset += 4;        // pr_pid -    if (have_padding) +    if (lp64)          offset += 4;      size_t len = data.GetByteSize() - offset; -    thread_data->gpregset = DataExtractor(data, offset, len); +    thread_data.gpregset = DataExtractor(data, offset, len);  }  static void -ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data) +ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data)  {      lldb::offset_t offset = 0; -    thread_data->name = data.GetCStr(&offset, 20); +    thread_data.name = data.GetCStr(&offset, 20);  }  /// Parse Thread context from PT_NOTE segment and store it in the thread list @@ -418,13 +426,13 @@ ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data)  ///    For case (b) there may be either one NT_PRPSINFO per thread, or a single  ///    one that applies to all threads (depending on the platform type).  void -ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,  +ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,                                                     DataExtractor segment_data)  {      assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);      lldb::offset_t offset = 0; -    ThreadData *thread_data = new ThreadData(); +    std::unique_ptr<ThreadData> thread_data(new ThreadData);      bool have_prstatus = false;      bool have_prpsinfo = false; @@ -447,7 +455,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *              assert(thread_data->gpregset.GetByteSize() > 0);              // Add the new thread to thread list              m_thread_data.push_back(*thread_data); -            thread_data = new ThreadData(); +            *thread_data = ThreadData();              have_prstatus = false;              have_prpsinfo = false;          } @@ -464,7 +472,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *              {                  case NT_FREEBSD_PRSTATUS:                      have_prstatus = true; -                    ParseFreeBSDPrStatus(thread_data, note_data, arch); +                    ParseFreeBSDPrStatus(*thread_data, note_data, arch);                      break;                  case NT_FREEBSD_FPREGSET:                      thread_data->fpregset = note_data; @@ -473,7 +481,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *                      have_prpsinfo = true;                      break;                  case NT_FREEBSD_THRMISC: -                    ParseFreeBSDThrMisc(thread_data, note_data); +                    ParseFreeBSDThrMisc(*thread_data, note_data);                      break;                  case NT_FREEBSD_PROCSTAT_AUXV:                      // FIXME: FreeBSD sticks an int at the beginning of the note diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index 610506c20a0bd..3e09c7bc20322 100644 --- a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -63,8 +63,16 @@ RegisterContextCorePOSIX_x86_64::WriteFPR()  bool  RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)  { -    value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); -    return true; +    switch (reg_info->byte_size) +    { +        case 4: +            value = *(uint32_t *)(m_gpregset + reg_info->byte_offset); +            return true; +        case 8: +            value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); +            return true; +    } +    return false;  }  bool diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 3bda86dc0f739..cadcf53ca5431 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -17,6 +17,7 @@  #include "ThreadElfCore.h"  #include "ProcessElfCore.h"  #include "RegisterContextLinux_x86_64.h" +#include "RegisterContextFreeBSD_i386.h"  #include "RegisterContextFreeBSD_mips64.h"  #include "RegisterContextFreeBSD_x86_64.h"  #include "RegisterContextPOSIXCore_mips64.h" @@ -85,45 +86,66 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)          ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());          ArchSpec arch = process->GetArchitecture(); -        switch (arch.GetMachine()) +        RegisterInfoInterface *reg_interface = NULL; + +        switch (arch.GetTriple().getOS())          { -            case llvm::Triple::mips64: -                switch (arch.GetTriple().getOS()) +            case llvm::Triple::FreeBSD: +            { +                switch (arch.GetMachine())                  { -                    case llvm::Triple::FreeBSD: -                        m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, new RegisterContextFreeBSD_mips64(arch), m_gpregset_data, m_fpregset_data)); +                    case llvm::Triple::mips64: +                        reg_interface = new RegisterContextFreeBSD_mips64(arch); +                        break; +                    case llvm::Triple::x86: +                        reg_interface = new RegisterContextFreeBSD_i386(arch); +                        break; +                    case llvm::Triple::x86_64: +                        reg_interface = new RegisterContextFreeBSD_x86_64(arch);                          break;                      default: -                        if (log) -                            log->Printf ("elf-core::%s:: OS(%d) not supported", -                                         __FUNCTION__, arch.GetTriple().getOS()); -                        assert (false && "OS not supported");                          break;                  }                  break; -            case llvm::Triple::x86_64: -                switch (arch.GetTriple().getOS()) +            } +  +            case llvm::Triple::Linux: +            { +                switch (arch.GetMachine())                  { -                    case llvm::Triple::FreeBSD: -                        m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextFreeBSD_x86_64(arch), m_gpregset_data, m_fpregset_data)); -                        break; -                    case llvm::Triple::Linux: -                        m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextLinux_x86_64(arch), m_gpregset_data, m_fpregset_data)); +                    case llvm::Triple::x86_64: +                        reg_interface = new RegisterContextLinux_x86_64(arch);                          break;                      default: -                        if (log) -                            log->Printf ("elf-core::%s:: OS(%d) not supported", -                                         __FUNCTION__, arch.GetTriple().getOS()); -                        assert (false && "OS not supported");                          break;                  }                  break; +            } + +            default: +                break; +        } + +        if (!reg_interface) { +            if (log) +                log->Printf ("elf-core::%s:: Architecture(%d) or OS(%d) not supported", +                             __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); +                assert (false && "Architecture or OS not supported"); +        } + +        switch (arch.GetMachine()) +        { +            case llvm::Triple::mips64: +                m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); +                break; +            case llvm::Triple::x86: +            case llvm::Triple::x86_64: +                m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); +                break;              default: -                if (log) -                    log->Printf ("elf-core::%s:: Architecture(%d) not supported", -                                 __FUNCTION__, arch.GetMachine()); -                assert (false && "Architecture not supported"); +                break;          } +          reg_ctx_sp = m_thread_reg_ctx_sp;      }      else if (m_unwinder_ap.get()) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f67e1b5d49c3c..1ec75a4bc7af9 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,9 +13,11 @@  // C Includes  #include <limits.h>  #include <string.h> +#include <sys/stat.h>  // C++ Includes  // Other libraries and framework includes +#include "lldb/Core/ConnectionFileDescriptor.h"  #include "lldb/Core/Log.h"  #include "lldb/Core/StreamFile.h"  #include "lldb/Core/StreamString.h" @@ -143,7 +145,9 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,      m_private_is_running (false),      m_history (512),      m_send_acks (true), -    m_is_platform (is_platform) +    m_is_platform (is_platform), +    m_listen_thread (LLDB_INVALID_HOST_THREAD), +    m_listen_url ()  {  } @@ -195,14 +199,14 @@ GDBRemoteCommunication::SendNack ()      return bytes_written;  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)  {      Mutex::Locker locker(m_sequence_mutex);      return SendPacketNoLock (payload, payload_length);  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)  {      if (IsConnected()) @@ -235,32 +239,32 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le          if (bytes_written == packet.GetSize())          {              if (GetSendAcks ()) -            { -                if (GetAck () != '+') -                { -                    if (log) -                        log->Printf("get ack failed..."); -                    return 0; -                } -            } +                return GetAck (); +            else +                return PacketResult::Success;          }          else          {              if (log)                  log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());          } -        return bytes_written;      } -    return 0; +    return PacketResult::ErrorSendFailed;  } -char +GDBRemoteCommunication::PacketResult  GDBRemoteCommunication::GetAck ()  {      StringExtractorGDBRemote packet; -    if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1) -        return packet.GetChar(); -    return 0; +    PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()); +    if (result == PacketResult::Success) +    { +        if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) +            return PacketResult::Success; +        else +            return PacketResult::ErrorSendAck; +    } +    return result;  }  bool @@ -280,7 +284,7 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)      return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)  {      uint8_t buffer[8192]; @@ -290,9 +294,10 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac      // Check for a packet from our cache first without trying any reading...      if (CheckForPacket (NULL, 0, packet)) -        return packet.GetStringRef().size(); +        return PacketResult::Success;      bool timed_out = false; +    bool disconnected = false;      while (IsConnected() && !timed_out)      {          lldb::ConnectionStatus status = eConnectionStatusNoConnection; @@ -309,7 +314,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac          if (bytes_read > 0)          {              if (CheckForPacket (buffer, bytes_read, packet)) -                return packet.GetStringRef().size(); +                return PacketResult::Success;          }          else          { @@ -326,13 +331,19 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac              case eConnectionStatusNoConnection:              case eConnectionStatusLostConnection:              case eConnectionStatusError: +                disconnected = true;                  Disconnect();                  break;              }          }      } -    packet.Clear ();     -    return 0; +    packet.Clear (); +    if (disconnected) +        return PacketResult::ErrorDisconnected; +    if (timed_out) +        return PacketResult::ErrorReplyTimeout; +    else +        return PacketResult::ErrorReplyFailed;  }  bool @@ -538,18 +549,65 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri  }  Error -GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, -                                                 const char *unix_socket_name,  // For handshaking -                                                 lldb_private::ProcessLaunchInfo &launch_info) +GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port)  {      Error error; +    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) +    { +        error.SetErrorString("listen thread already running"); +    } +    else +    { +        char listen_url[512]; +        if (hostname && hostname[0]) +            snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); +        else +            snprintf(listen_url, sizeof(listen_url), "listen://%i", port); +        m_listen_url = listen_url; +        SetConnection(new ConnectionFileDescriptor()); +        m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error); +    } +    return error; +} + +bool +GDBRemoteCommunication::JoinListenThread () +{ +    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) +    { +        Host::ThreadJoin(m_listen_thread, NULL, NULL); +        m_listen_thread = LLDB_INVALID_HOST_THREAD; +    } +    return true; +} + +lldb::thread_result_t +GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) +{ +    GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; +    Error error; +    ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); +     +    if (connection) +    { +        // Do the listen on another thread so we can continue on... +        if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) +            comm->SetConnection(NULL); +    } +    return NULL; +} + +Error +GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, +                                                 uint16_t in_port, +                                                 lldb_private::ProcessLaunchInfo &launch_info, +                                                 uint16_t &out_port) +{ +    out_port = in_port; +    Error error;      // If we locate debugserver, keep that located version around      static FileSpec g_debugserver_file_spec; -    // This function will fill in the launch information for the debugserver -    // instance that gets launched. -    launch_info.Clear(); -          char debugserver_path[PATH_MAX];      FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); @@ -591,19 +649,88 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,          // Start args with "debugserver /file/path -r --"          debugserver_args.AppendArgument(debugserver_path); -        debugserver_args.AppendArgument(debugserver_url); + +        // If a host and port is supplied then use it +        char host_and_port[128]; +        if (hostname) +        { +            snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); +            debugserver_args.AppendArgument(host_and_port); +        } +        else +        { +            host_and_port[0] = '\0'; +        } +          // use native registers, not the GDB registers          debugserver_args.AppendArgument("--native-regs");             // make debugserver run in its own session so signals generated by           // special terminal key sequences (^C) don't affect debugserver          debugserver_args.AppendArgument("--setsid"); -         -        if (unix_socket_name && unix_socket_name[0]) + +        char named_pipe_path[PATH_MAX]; +        named_pipe_path[0] = '\0'; + +        bool listen = false; +        if (host_and_port[0])          { -            debugserver_args.AppendArgument("--unix-socket"); -            debugserver_args.AppendArgument(unix_socket_name); +            // Create a temporary file to get the stdout/stderr and redirect the +            // output of the command into this file. We will later read this file +            // if all goes well and fill the data into "command_output_ptr" + +            if (in_port == 0) +            { +                // Binding to port zero, we need to figure out what port it ends up +                // using using a named pipe... +                FileSpec tmpdir_file_spec; +                if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) +                { +                    tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); +                    strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); +                } +                else +                { +                    strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); +                } + +                if (::mktemp (named_pipe_path)) +                { +#if defined(_MSC_VER) +                    if ( false ) +#else +                    if (::mkfifo(named_pipe_path, 0600) == 0) +#endif +                    { +                        debugserver_args.AppendArgument("--named-pipe"); +                        debugserver_args.AppendArgument(named_pipe_path); +                    } +                } +            } +            else +            { +                listen = true; +            } +        } +        else +        { +            // No host and port given, so lets listen on our end and make the debugserver +            // connect to us.. +            error = StartListenThread ("localhost", 0); +            if (error.Fail()) +                return error; + +            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); +            out_port = connection->GetBoundPort(3); +            assert (out_port != 0); +            char port_cstr[32]; +            snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); +            // Send the host and port down that debugserver and specify an option +            // so that it connects back to the port we are listening to in this process +            debugserver_args.AppendArgument("--reverse-connect"); +            debugserver_args.AppendArgument(port_cstr);          } +                  const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");          if (env_debugserver_log_file)          { @@ -617,46 +744,41 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,              ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);              debugserver_args.AppendArgument(arg_cstr);          } -        //            debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); -        //            debugserver_args.AppendArgument("--log-flags=0x802e0e"); -        // We currently send down all arguments, attach pids, or attach  -        // process names in dedicated GDB server packets, so we don't need -        // to pass them as arguments. This is currently because of all the -        // things we need to setup prior to launching: the environment, -        // current working dir, file actions, etc. -#if 0 -        // Now append the program arguments -        if (inferior_argv) +        // Close STDIN, STDOUT and STDERR. We might need to redirect them +        // to "/dev/null" if we run into any problems. +        launch_info.AppendCloseFileAction (STDIN_FILENO); +        launch_info.AppendCloseFileAction (STDOUT_FILENO); +        launch_info.AppendCloseFileAction (STDERR_FILENO); +         +        error = Host::LaunchProcess(launch_info); +         +        if (named_pipe_path[0])          { -            // Terminate the debugserver args so we can now append the inferior args -            debugserver_args.AppendArgument("--"); -             -            for (int i = 0; inferior_argv[i] != NULL; ++i) -                debugserver_args.AppendArgument (inferior_argv[i]); +            File name_pipe_file; +            error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); +            if (error.Success()) +            { +                char port_cstr[256]; +                port_cstr[0] = '\0'; +                size_t num_bytes = sizeof(port_cstr); +                error = name_pipe_file.Read(port_cstr, num_bytes); +                assert (error.Success()); +                assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); +                out_port = Args::StringToUInt32(port_cstr, 0); +                name_pipe_file.Close(); +            } +            Host::Unlink(named_pipe_path);          } -        else if (attach_pid != LLDB_INVALID_PROCESS_ID) +        else if (listen)          { -            ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); -            debugserver_args.AppendArgument (arg_cstr); +                      } -        else if (attach_name && attach_name[0]) +        else          { -            if (wait_for_launch) -                debugserver_args.AppendArgument ("--waitfor"); -            else -                debugserver_args.AppendArgument ("--attach"); -            debugserver_args.AppendArgument (attach_name); +            // Make sure we actually connect with the debugserver... +            JoinListenThread();          } -#endif -         -        // Close STDIN, STDOUT and STDERR. We might need to redirect them -        // to "/dev/null" if we run into any problems. -//        launch_info.AppendCloseFileAction (STDIN_FILENO); -//        launch_info.AppendCloseFileAction (STDOUT_FILENO); -//        launch_info.AppendCloseFileAction (STDERR_FILENO); -         -        error = Host::LaunchProcess(launch_info);      }      else      { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index a1077957c6a62..d8361113ddc84 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -35,6 +35,19 @@ public:      {          eBroadcastBitRunPacketSent = kLoUserBroadcastBit      }; +     +    enum class PacketResult +    { +        Success = 0,        // Success +        ErrorSendFailed,    // Error sending the packet +        ErrorSendAck,       // Didn't get an ack back after sending a packet +        ErrorReplyFailed,   // Error getting the reply +        ErrorReplyTimeout,  // Timed out waiting for reply +        ErrorReplyInvalid,  // Got a reply but it wasn't valid for the packet that was sent +        ErrorReplyAck,      // Sending reply ack failed +        ErrorDisconnected,  // We were disconnected +        ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request +    };      //------------------------------------------------------------------      // Constructors and Destructors      //------------------------------------------------------------------ @@ -45,7 +58,7 @@ public:      virtual      ~GDBRemoteCommunication(); -    char +    PacketResult      GetAck ();      size_t @@ -109,9 +122,10 @@ public:      // supplied connection URL.      //------------------------------------------------------------------      lldb_private::Error -    StartDebugserverProcess (const char *connect_url, -                             const char *unix_socket_name, -                             lldb_private::ProcessLaunchInfo &launch_info);  +    StartDebugserverProcess (const char *hostname, +                             uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit +                             lldb_private::ProcessLaunchInfo &launch_info, +                             uint16_t &out_port);      void      DumpHistory(lldb_private::Stream &strm); @@ -223,15 +237,15 @@ protected:          mutable bool m_dumped_to_log;      }; -    size_t +    PacketResult      SendPacket (const char *payload,                  size_t payload_length); -    size_t +    PacketResult      SendPacketNoLock (const char *payload,                         size_t payload_length); -    size_t +    PacketResult      WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response,                                                   uint32_t timeout_usec); @@ -242,7 +256,7 @@ protected:      // Classes that inherit from GDBRemoteCommunication can see and modify these      //------------------------------------------------------------------      uint32_t m_packet_timeout; -#ifdef LLDB_CONFIGURATION_DEBUG +#ifdef ENABLE_MUTEX_ERROR_CHECKING      lldb_private::TrackingMutex m_sequence_mutex;  #else      lldb_private::Mutex m_sequence_mutex;    // Restrict access to sending/receiving packets to a single thread at a time @@ -256,9 +270,22 @@ protected:                          // a single process +    lldb_private::Error +    StartListenThread (const char *hostname = "localhost", +                       uint16_t port = 0); + +    bool +    JoinListenThread (); +    static lldb::thread_result_t +    ListenThread (lldb::thread_arg_t arg);  private: +     +    lldb::thread_t m_listen_thread; +    std::string m_listen_url; +     +      //------------------------------------------------------------------      // For GDBRemoteCommunication only      //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2690992eeed3e..aa60ec1b4a277 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -66,6 +66,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_prepare_for_reg_writing_reply (eLazyBoolCalculate),      m_supports_p (eLazyBoolCalculate),      m_supports_QSaveRegisterState (eLazyBoolCalculate), +    m_supports_qXfer_libraries_read (eLazyBoolCalculate), +    m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), +    m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),      m_supports_qProcessInfoPID (true),      m_supports_qfProcessInfo (true),      m_supports_qUserName (true), @@ -84,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_async_mutex (Mutex::eMutexTypeRecursive),      m_async_packet_predicate (false),      m_async_packet (), +    m_async_result (PacketResult::Success),      m_async_response (),      m_async_signal (-1),      m_thread_id_to_used_usec_map (), @@ -95,7 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :      m_os_build (),      m_os_kernel (),      m_hostname (), -    m_default_packet_timeout (0) +    m_default_packet_timeout (0), +    m_max_packet_size (0)  {  } @@ -117,6 +122,14 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)      // fail to send the handshake ack, there is no reason to continue...      if (SendAck())      { +        // Wait for any responses that might have been queued up in the remote +        // GDB server and flush them all +        StringExtractorGDBRemote response; +        PacketResult packet_result = PacketResult::Success; +        const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response +        while (packet_result == PacketResult::Success) +            packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec); +          // The return value from QueryNoAckModeSupported() is true if the packet          // was sent and _any_ response (including UNIMPLEMENTED) was received),          // or false if no response was received. This quickly tells us if we have @@ -140,6 +153,46 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)  }  bool +GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () +{ +    if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) +    { +        GetRemoteQSupported(); +    } +    return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () +{ +    if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) +    { +        GetRemoteQSupported(); +    } +    return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () +{ +    if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) +    { +        GetRemoteQSupported(); +    } +    return (m_supports_qXfer_libraries_read == eLazyBoolYes); +} + +uint64_t +GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() +{ +    if (m_max_packet_size == 0) +    { +        GetRemoteQSupported(); +    } +    return m_max_packet_size; +} + +bool  GDBRemoteCommunicationClient::QueryNoAckModeSupported ()  {      if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -148,7 +201,7 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()          m_supports_not_sending_acks = eLazyBoolNo;          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) +        if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())              { @@ -169,7 +222,7 @@ GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()          m_supports_threads_in_stop_reply = eLazyBoolNo;          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false)) +        if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  m_supports_threads_in_stop_reply = eLazyBoolYes; @@ -185,7 +238,7 @@ GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()          m_attach_or_wait_reply = eLazyBoolNo;          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false)) +        if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  m_attach_or_wait_reply = eLazyBoolYes; @@ -205,7 +258,7 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()          m_prepare_for_reg_writing_reply = eLazyBoolNo;          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false)) +        if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  m_prepare_for_reg_writing_reply = eLazyBoolYes; @@ -236,6 +289,9 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()      m_supports_memory_region_info = eLazyBoolCalculate;      m_prepare_for_reg_writing_reply = eLazyBoolCalculate;      m_attach_or_wait_reply = eLazyBoolCalculate; +    m_supports_qXfer_libraries_read = eLazyBoolCalculate; +    m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; +    m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;      m_supports_qProcessInfoPID = true;      m_supports_qfProcessInfo = true; @@ -251,8 +307,50 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()      m_supports_QEnvironmentHexEncoded = true;      m_host_arch.Clear();      m_process_arch.Clear(); + +    m_max_packet_size = 0;  } +void +GDBRemoteCommunicationClient::GetRemoteQSupported () +{ +    // Clear out any capabilities we expect to see in the qSupported response +    m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; +    m_supports_qXfer_libraries_read = eLazyBoolNo; +    m_supports_augmented_libraries_svr4_read = eLazyBoolNo; +    m_max_packet_size = UINT64_MAX;  // It's supposed to always be there, but if not, we assume no limit + +    StringExtractorGDBRemote response; +    if (SendPacketAndWaitForResponse("qSupported", +                                     response, +                                     /*send_async=*/false) == PacketResult::Success) +    { +        const char *response_cstr = response.GetStringRef().c_str(); +        if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) +            m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; +        if (::strstr (response_cstr, "augmented-libraries-svr4-read")) +        { +            m_supports_qXfer_libraries_svr4_read = eLazyBoolYes;  // implied +            m_supports_augmented_libraries_svr4_read = eLazyBoolYes; +        } +        if (::strstr (response_cstr, "qXfer:libraries:read+")) +            m_supports_qXfer_libraries_read = eLazyBoolYes; + +        const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); +        if (packet_size_str) +        { +            StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); +            m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); +            if (m_max_packet_size == 0) +            { +                m_max_packet_size = UINT64_MAX;  // Must have been a garbled response +                Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +                if (log) +                    log->Printf ("Garbled PacketSize spec in qSupported response"); +            } +        } +    } +}  bool  GDBRemoteCommunicationClient::GetThreadSuffixSupported () @@ -261,7 +359,7 @@ GDBRemoteCommunicationClient::GetThreadSuffixSupported ()      {          StringExtractorGDBRemote response;          m_supports_thread_suffix = eLazyBoolNo; -        if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) +        if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  m_supports_thread_suffix = eLazyBoolYes; @@ -281,7 +379,7 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor)          m_supports_vCont_C = eLazyBoolNo;          m_supports_vCont_s = eLazyBoolNo;          m_supports_vCont_S = eLazyBoolNo; -        if (SendPacketAndWaitForResponse("vCont?", response, false)) +        if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success)          {              const char *response_cstr = response.GetStringRef().c_str();              if (::strstr (response_cstr, ";c")) @@ -345,7 +443,7 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)          else              snprintf(packet, sizeof(packet), "p0"); -        if (SendPacketAndWaitForResponse(packet, response, false)) +        if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)          {              if (response.IsNormalResponse())                  m_supports_p = eLazyBoolYes; @@ -354,7 +452,63 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)      return m_supports_p;  } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses +( +    const char *payload_prefix, +    std::string &response_string +) +{ +    Mutex::Locker locker; +    if (!GetSequenceMutex(locker, +                          "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex")) +    { +        Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); +        if (log) +            log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'", +                        payload_prefix); +        return PacketResult::ErrorNoSequenceLock; +    } + +    response_string = ""; +    std::string payload_prefix_str(payload_prefix); +    unsigned int response_size = 0x1000; +    if (response_size > GetRemoteMaxPacketSize()) {  // May send qSupported packet +        response_size = GetRemoteMaxPacketSize(); +    } + +    for (unsigned int offset = 0; true; offset += response_size) +    { +        StringExtractorGDBRemote this_response; +        // Construct payload +        char sizeDescriptor[128]; +        snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); +        PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(), +                                                           this_response, +                                                           /*send_async=*/false); +        if (result != PacketResult::Success) +            return result; + +        const std::string &this_string = this_response.GetStringRef(); + +        // Check for m or l as first character; l seems to mean this is the last chunk +        char first_char = *this_string.c_str(); +        if (first_char != 'm' && first_char != 'l') +        { +            return PacketResult::ErrorReplyInvalid; +        } +        // Skip past m or l +        const char *s = this_string.c_str() + 1; + +        // Concatenate the result so far +        response_string += s; +        if (first_char == 'l') +            // We're done +            return PacketResult::Success; +    } +} + +GDBRemoteCommunicationClient::PacketResult  GDBRemoteCommunicationClient::SendPacketAndWaitForResponse  (      const char *payload, @@ -368,7 +522,18 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse                                           send_async);  } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload, +                                                                  size_t payload_length, +                                                                  StringExtractorGDBRemote &response) +{ +    PacketResult packet_result = SendPacketNoLock (payload, payload_length); +    if (packet_result == PacketResult::Success) +        packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); +    return packet_result; +} + +GDBRemoteCommunicationClient::PacketResult  GDBRemoteCommunicationClient::SendPacketAndWaitForResponse  (      const char *payload, @@ -377,18 +542,13 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse      bool send_async  )  { +    PacketResult packet_result = PacketResult::ErrorSendFailed;      Mutex::Locker locker;      Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));      size_t response_len = 0;      if (GetSequenceMutex (locker))      { -        if (SendPacketNoLock (payload, payload_length)) -           response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); -        else  -        { -            if (log) -                log->Printf("error: failed to send '%*s'", (int) payload_length, payload);    -        } +        packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);      }      else      { @@ -424,6 +584,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse                              // Swap the response buffer to avoid malloc and string copy                              response.GetStringRef().swap (m_async_response.GetStringRef());                              response_len = response.GetStringRef().size(); +                            packet_result = m_async_result;                          }                          else                          { @@ -456,13 +617,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse                          if (log)                               log->Printf ("async: got lock without sending interrupt");                          // Send the packet normally since we got the lock -                        if (SendPacketNoLock (payload, payload_length)) -                            response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); -                        else  -                        { -                            if (log) -                                log->Printf("error: failed to send '%*s'", (int) payload_length, payload);    -                        } +                        packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);                      }                  }                  else @@ -483,12 +638,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse                  log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);          }      } -    if (response_len == 0) -    { -        if (log)  -            log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload); -    }         -    return response_len; +    return packet_result;  }  static const char *end_delimiter = "--end--;"; @@ -615,7 +765,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse          {              if (log)                  log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); -            if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0) +            if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success)                  state = eStateInvalid;              m_private_is_running.SetValue (true, eBroadcastAlways); @@ -626,7 +776,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse          if (log)              log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); -        if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX)) +        if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success)          {              if (response.Empty())                  state = eStateInvalid; @@ -683,7 +833,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse                                  // packet to make sure it doesn't get in the way                                  StringExtractorGDBRemote extra_stop_reply_packet;                                  uint32_t timeout_usec = 1000; -                                if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec)) +                                if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec) == PacketResult::Success)                                  {                                      switch (extra_stop_reply_packet.GetChar())                                      { @@ -747,11 +897,12 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse                              Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));                              // We are supposed to send an asynchronous packet while -                            // we are running.  +                            // we are running.                              m_async_response.Clear();                              if (m_async_packet.empty())                              { -                                if (packet_log)  +                                m_async_result = PacketResult::ErrorSendFailed; +                                if (packet_log)                                      packet_log->Printf ("async: error: empty async packet");                                                          } @@ -760,10 +911,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse                                  if (packet_log)                                       packet_log->Printf ("async: sending packet"); -                                SendPacketAndWaitForResponse (&m_async_packet[0],  -                                                              m_async_packet.size(), -                                                              m_async_response, -                                                              false); +                                m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0], +                                                                               m_async_packet.size(), +                                                                               m_async_response, +                                                                               false);                              }                              // Let the other thread that was trying to send the async                              // packet know that the packet has been sent and response is @@ -973,7 +1124,7 @@ lldb::pid_t  GDBRemoteCommunicationClient::GetCurrentProcessID ()  {      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false)) +    if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)      {          if (response.GetChar() == 'Q')              if (response.GetChar() == 'C') @@ -987,7 +1138,7 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)  {      error_str.clear();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false)) +    if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success)      {          if (response.IsOKResponse())              return true; @@ -1050,7 +1201,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun          }          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1097,7 +1248,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu              {                  packet.PutCString("QEnvironmentHexEncoded:");                  packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); -                if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +                if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)                  {                      if (response.IsOKResponse())                          return 0; @@ -1113,7 +1264,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu          else if (m_supports_QEnvironment)          {              packet.Printf("QEnvironment:%s", name_equal_value); -            if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +            if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)              {                  if (response.IsOKResponse())                      return 0; @@ -1136,7 +1287,7 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)          StreamString packet;          packet.Printf("QLaunchArch:%s", arch);          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1236,7 +1387,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)      {          m_qHostInfo_is_valid = eLazyBoolNo;          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) +        if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success)          {              if (response.IsNormalResponse())              { @@ -1248,6 +1399,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)                  std::string os_name;                  std::string vendor_name;                  std::string triple; +                std::string distribution_id;                  uint32_t pointer_byte_size = 0;                  StringExtractor extractor;                  ByteOrder byte_order = eByteOrderInvalid; @@ -1281,6 +1433,13 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)                          extractor.GetHexByteString (triple);                          ++num_keys_decoded;                      } +                    else if (name.compare ("distribution_id") == 0) +                    { +                        extractor.GetStringRef ().swap (value); +                        extractor.SetFilePos (0); +                        extractor.GetHexByteString (distribution_id); +                        ++num_keys_decoded; +                    }                      else if (name.compare("os_build") == 0)                      {                          extractor.GetStringRef().swap(value); @@ -1455,7 +1614,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)                      {                          assert (byte_order == m_host_arch.GetByteOrder());                      } -                }        +                } +                if (!distribution_id.empty ()) +                    m_host_arch.SetDistributionId (distribution_id.c_str ());              }          }      } @@ -1474,7 +1635,7 @@ GDBRemoteCommunicationClient::SendAttach          char packet[64];          const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid);          assert (packet_len < (int)sizeof(packet)); -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              if (response.IsErrorResponse())                  return response.GetError(); @@ -1514,7 +1675,7 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)                                             permissions & lldb::ePermissionsExecutable ? "x" : "");          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              if (!response.IsErrorResponse())                  return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -1537,7 +1698,7 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)          const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return true; @@ -1563,7 +1724,7 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped)              const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");              assert (packet_len < (int)sizeof(packet));              StringExtractorGDBRemote response; -            if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +            if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)              {                  m_supports_detach_stay_stopped = eLazyBoolYes;                      } @@ -1580,15 +1741,15 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped)          }          else          { -            size_t num_sent = SendPacket ("D1", 2); -            if (num_sent == 0) +            PacketResult packet_result = SendPacket ("D1", 2); +            if (packet_result != PacketResult::Success)                  error.SetErrorString ("Sending extended disconnect packet failed.");          }      }      else      { -        size_t num_sent = SendPacket ("D", 1); -        if (num_sent == 0) +        PacketResult packet_result = SendPacket ("D", 1); +        if (packet_result != PacketResult::Success)              error.SetErrorString ("Sending disconnect packet failed.");      }      return error; @@ -1608,7 +1769,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,          const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              std::string name;              std::string value; @@ -1711,7 +1872,7 @@ GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num)          const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:");          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              m_supports_watchpoint_support_info = eLazyBoolYes;                      std::string name; @@ -1773,7 +1934,7 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path)          packet.PutBytesAsRawHex8(path, strlen(path));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1795,7 +1956,7 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path)          packet.PutBytesAsRawHex8(path, strlen(path));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1817,7 +1978,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path)          packet.PutBytesAsRawHex8(path, strlen(path));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1833,7 +1994,7 @@ bool  GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)  {      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) +    if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success)      {          if (response.IsUnsupportedResponse())              return false; @@ -1855,7 +2016,7 @@ GDBRemoteCommunicationClient::SetWorkingDir (char const *path)          packet.PutBytesAsRawHex8(path, strlen(path));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              if (response.IsOKResponse())                  return 0; @@ -1874,7 +2035,7 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable)      const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0);      assert (packet_len < (int)sizeof(packet));      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)      {          if (response.IsOKResponse())              return 0; @@ -1893,6 +2054,11 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot          std::string name;          std::string value;          StringExtractor extractor; + +        uint32_t cpu = LLDB_INVALID_CPUTYPE; +        uint32_t sub = 0; +        std::string vendor; +        std::string os_type;          while (response.GetNameColonValue(name, value))          { @@ -1938,6 +2104,32 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot                  extractor.GetHexByteString (value);                  process_info.GetExecutableFile().SetFile (value.c_str(), false);              } +            else if (name.compare("cputype") == 0) +            { +                cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); +            } +            else if (name.compare("cpusubtype") == 0) +            { +                sub = Args::StringToUInt32 (value.c_str(), 0, 16); +            } +            else if (name.compare("vendor") == 0) +            { +                vendor = value; +            } +            else if (name.compare("ostype") == 0) +            { +                os_type = value; +            } +        } + +        if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) +        { +            if (vendor == "apple") +            { +                process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub); +                process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor)); +                process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type)); +            }          }          if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) @@ -1957,7 +2149,7 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceIn          const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              return DecodeProcessInfoResponse (response, process_info);          } @@ -1981,7 +2173,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo ()      GetHostInfo ();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse ("qProcessInfo", response, false)) +    if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success)      {          if (response.IsNormalResponse())          { @@ -2141,7 +2333,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat              }          }          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) +        if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)          {              do              { @@ -2151,7 +2343,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat                  process_infos.Append(process_info);                  response.GetStringRef().clear();                  response.SetFilePos(0); -            } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false)); +            } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success);          }          else          { @@ -2172,7 +2364,7 @@ GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name)          const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              if (response.IsNormalResponse())              { @@ -2202,7 +2394,7 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)          const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)          {              if (response.IsNormalResponse())              { @@ -2296,32 +2488,36 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t      }      StringExtractorGDBRemote response; -    return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0; -    return false; +    return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)  == PacketResult::Success;  }  uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname)  {      pid = LLDB_INVALID_PROCESS_ID;      StringExtractorGDBRemote response;      StreamString stream;      stream.PutCString("qLaunchGDBServer;");      std::string hostname; -    if (Host::GetHostname (hostname)) -    { -        // Make the GDB server we launch only accept connections from this host -        stream.Printf("host:%s;", hostname.c_str()); -    } +    if (remote_accept_hostname  && remote_accept_hostname[0]) +        hostname = remote_accept_hostname;      else      { -        // Make the GDB server we launch accept connections from any host since we can't figure out the hostname -        stream.Printf("host:*;"); +        if (Host::GetHostname (hostname)) +        { +            // Make the GDB server we launch only accept connections from this host +            stream.Printf("host:%s;", hostname.c_str()); +        } +        else +        { +            // Make the GDB server we launch accept connections from any host since we can't figure out the hostname +            stream.Printf("host:*;"); +        }      }      const char *packet = stream.GetData();      int packet_len = stream.GetSize(); -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          std::string name;          std::string value; @@ -2347,7 +2543,7 @@ GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid)      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.IsOKResponse())              return true; @@ -2369,7 +2565,7 @@ GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)          packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid);      assert (packet_len + 1 < (int)sizeof(packet));      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.IsOKResponse())          { @@ -2395,7 +2591,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid)      assert (packet_len + 1 < (int)sizeof(packet));      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.IsOKResponse())          { @@ -2409,7 +2605,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid)  bool  GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response)  { -    if (SendPacketAndWaitForResponse("?", 1, response, false)) +    if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success)          return response.IsNormalResponse();      return false;  } @@ -2422,7 +2618,7 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto          char packet[256];          int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid);          assert (packet_len < (int)sizeof(packet)); -        if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +        if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)          {              if (response.IsUnsupportedResponse())                  m_supports_qThreadStopInfo = false; @@ -2463,7 +2659,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type,      assert (packet_len + 1 < (int)sizeof(packet));      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, true)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success)      {          if (response.IsOKResponse())              return 0; @@ -2497,9 +2693,10 @@ GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thr          sequence_mutex_unavailable = false;          StringExtractorGDBRemote response; -        for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); -             response.IsNormalResponse(); -             SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ())) +        PacketResult packet_result; +        for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response); +             packet_result == PacketResult::Success && response.IsNormalResponse(); +             packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response))          {              char ch = response.GetChar();              if (ch == 'l') @@ -2539,7 +2736,7 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr()      if (!IsRunning())      {          StringExtractorGDBRemote response; -        if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false)) +        if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success)          {              if (response.IsNormalResponse())                  return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -2569,7 +2766,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command,           //      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')              return Error("malformed reply"); @@ -2608,7 +2805,7 @@ GDBRemoteCommunicationClient::MakeDirectory (const char *path,      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);      } @@ -2628,7 +2825,7 @@ GDBRemoteCommunicationClient::SetFilePermissions (const char *path,      const char *packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);      } @@ -2679,7 +2876,7 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          return ParseHostIOPacketResponse (response, UINT64_MAX, error);      } @@ -2695,7 +2892,7 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          return ParseHostIOPacketResponse (response, -1, error) == 0;      } @@ -2713,7 +2910,7 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')              return UINT64_MAX; @@ -2733,7 +2930,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')          { @@ -2780,7 +2977,7 @@ GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd,      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')              return 0; @@ -2819,7 +3016,7 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')          { @@ -2861,7 +3058,7 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() == 'F')          { @@ -2902,7 +3099,7 @@ GDBRemoteCommunicationClient::Unlink (const char *path)      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() == 'F')          { @@ -2942,7 +3139,7 @@ GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')              return false; @@ -2966,7 +3163,7 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s      const char* packet = stream.GetData();      int packet_len = stream.GetSize();      StringExtractorGDBRemote response; -    if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) +    if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)      {          if (response.GetChar() != 'F')              return false; @@ -2998,7 +3195,7 @@ GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, String              else                  packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);              assert (packet_len < ((int)sizeof(packet) - 1)); -            return SendPacketAndWaitForResponse(packet, response, false); +            return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;          }      }      return false; @@ -3024,7 +3221,7 @@ GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractor              else                  packet_len = ::snprintf (packet, sizeof(packet), "g");              assert (packet_len < ((int)sizeof(packet) - 1)); -            return SendPacketAndWaitForResponse(packet, response, false); +            return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;          }      }      return false; @@ -3051,7 +3248,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save              StringExtractorGDBRemote response; -            if (SendPacketAndWaitForResponse(packet, response, false)) +            if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)              {                  if (response.IsUnsupportedResponse())                  { @@ -3094,7 +3291,7 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa              StringExtractorGDBRemote response; -            if (SendPacketAndWaitForResponse(packet, response, false)) +            if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)              {                  if (response.IsOKResponse())                  { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 564afbb2911cf..a1e982b3ec4e9 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -47,17 +47,38 @@ public:      bool      HandshakeWithServer (lldb_private::Error *error_ptr); -    size_t +    PacketResult      SendPacketAndWaitForResponse (const char *send_payload,                                    StringExtractorGDBRemote &response,                                    bool send_async); -    size_t +    PacketResult      SendPacketAndWaitForResponse (const char *send_payload,                                    size_t send_length,                                    StringExtractorGDBRemote &response,                                    bool send_async); +    // For packets which specify a range of output to be returned, +    // return all of the output via a series of request packets of the form +    // <prefix>0,<size> +    // <prefix><size>,<size> +    // <prefix><size>*2,<size> +    // <prefix><size>*3,<size> +    // ... +    // until a "$l..." packet is received, indicating the end. +    // (size is in hex; this format is used by a standard gdbserver to +    // return the given portion of the output specified by <prefix>; +    // for example, "qXfer:libraries-svr4:read::fff,1000" means +    // "return a chunk of the xml description file for shared +    // library load addresses, where the chunk starts at offset 0xfff +    // and continues for 0x1000 bytes"). +    // Concatenate the resulting server response packets together and +    // return in response_string.  If any packet fails, the return value +    // indicates that failure and the returned string value is undefined. +    PacketResult +    SendPacketsAndConcatenateResponses (const char *send_payload_prefix, +                                        std::string &response_string); +      lldb::StateType      SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,                                            const char *packet_payload, @@ -94,7 +115,7 @@ public:      GetLaunchSuccess (std::string &error_str);      uint16_t -    LaunchGDBserverAndGetPort (lldb::pid_t &pid); +    LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname);      bool      KillSpawnedProcess (lldb::pid_t pid); @@ -248,6 +269,9 @@ public:      const lldb_private::ArchSpec &      GetProcessArchitecture (); +    void +    GetRemoteQSupported(); +      bool      GetVContSupported (char flavor); @@ -359,6 +383,18 @@ public:      bool      SetCurrentThreadForRun (uint64_t tid); +    bool +    GetQXferLibrariesReadSupported (); + +    bool +    GetQXferLibrariesSVR4ReadSupported (); + +    uint64_t +    GetRemoteMaxPacketSize(); + +    bool +    GetAugmentedLibrariesSVR4ReadSupported (); +      lldb_private::LazyBool      SupportsAllocDeallocMemory () // const      { @@ -458,6 +494,11 @@ public:  protected: +    PacketResult +    SendPacketAndWaitForResponseNoLock (const char *payload, +                                        size_t payload_length, +                                        StringExtractorGDBRemote &response); +      bool      GetCurrentProcessInfo (); @@ -484,7 +525,10 @@ protected:      lldb_private::LazyBool m_prepare_for_reg_writing_reply;      lldb_private::LazyBool m_supports_p;      lldb_private::LazyBool m_supports_QSaveRegisterState; -     +    lldb_private::LazyBool m_supports_qXfer_libraries_read; +    lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; +    lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; +      bool          m_supports_qProcessInfoPID:1,          m_supports_qfProcessInfo:1, @@ -511,6 +555,7 @@ protected:      lldb_private::Mutex m_async_mutex;      lldb_private::Predicate<bool> m_async_packet_predicate;      std::string m_async_packet; +    PacketResult m_async_result;      StringExtractorGDBRemote m_async_response;      int m_async_signal; // We were asked to deliver a signal to the inferior process.      bool m_interrupt_sent; @@ -526,6 +571,7 @@ protected:      std::string m_os_kernel;      std::string m_hostname;      uint32_t m_default_packet_timeout; +    uint64_t m_max_packet_size;  // as returned by qSupported      bool      DecodeProcessInfoResponse (StringExtractorGDBRemote &response,  diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 7cc3a05304d42..df95542d2c0fe 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -25,6 +25,7 @@  #include "lldb/Host/File.h"  #include "lldb/Host/Host.h"  #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Platform.h"  #include "lldb/Target/Process.h"  // Project includes @@ -40,6 +41,7 @@ using namespace lldb_private;  //----------------------------------------------------------------------  GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :      GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), +    m_platform_sp (Platform::GetDefaultPlatform ()),      m_async_thread (LLDB_INVALID_HOST_THREAD),      m_process_launch_info (),      m_process_launch_error (), @@ -52,6 +54,23 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :  {  } +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, +                                                           const lldb::PlatformSP& platform_sp) : +    GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), +    m_platform_sp (platform_sp), +    m_async_thread (LLDB_INVALID_HOST_THREAD), +    m_process_launch_info (), +    m_process_launch_error (), +    m_spawned_pids (), +    m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), +    m_proc_infos (), +    m_proc_infos_index (0), +    m_port_map (), +    m_port_offset(0) +{ +    assert(platform_sp); +} +  //----------------------------------------------------------------------  // Destructor  //---------------------------------------------------------------------- @@ -90,154 +109,249 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,                                                          bool &quit)  {      StringExtractorGDBRemote packet; -    if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec)) +    PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); +    if (packet_result == PacketResult::Success)      {          const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();          switch (packet_type)          { -            case StringExtractorGDBRemote::eServerPacketType_nack: -            case StringExtractorGDBRemote::eServerPacketType_ack: -                break; - -            case StringExtractorGDBRemote::eServerPacketType_invalid: -                error.SetErrorString("invalid packet"); -                quit = true; -                break; - -            case StringExtractorGDBRemote::eServerPacketType_interrupt: -                error.SetErrorString("interrupt received"); -                interrupt = true; -                break; +        case StringExtractorGDBRemote::eServerPacketType_nack: +        case StringExtractorGDBRemote::eServerPacketType_ack: +            break; + +        case StringExtractorGDBRemote::eServerPacketType_invalid: +            error.SetErrorString("invalid packet"); +            quit = true; +            break; + +        case StringExtractorGDBRemote::eServerPacketType_interrupt: +            error.SetErrorString("interrupt received"); +            interrupt = true; +            break; + +        default: +        case StringExtractorGDBRemote::eServerPacketType_unimplemented: +            packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); +            break; -            case StringExtractorGDBRemote::eServerPacketType_unimplemented: -                return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; +        case StringExtractorGDBRemote::eServerPacketType_A: +            packet_result = Handle_A (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_A: -                return Handle_A (packet); +        case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: +            packet_result = Handle_qfProcessInfo (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: -                return Handle_qfProcessInfo (packet); +        case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: +            packet_result = Handle_qsProcessInfo (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: -                return Handle_qsProcessInfo (packet); +        case StringExtractorGDBRemote::eServerPacketType_qC: +            packet_result = Handle_qC (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qC: -                return Handle_qC (packet); +        case StringExtractorGDBRemote::eServerPacketType_qHostInfo: +            packet_result = Handle_qHostInfo (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qHostInfo: -                return Handle_qHostInfo (packet); +        case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: +            packet_result = Handle_qLaunchGDBServer (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: -                return Handle_qLaunchGDBServer (packet); +        case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: +            packet_result = Handle_qKillSpawnedProcess (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: -                return Handle_qKillSpawnedProcess (packet); +        case StringExtractorGDBRemote::eServerPacketType_k: +            packet_result = Handle_k (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: -                return Handle_qLaunchSuccess (packet); +        case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: +            packet_result = Handle_qLaunchSuccess (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qGroupName: -                return Handle_qGroupName (packet); +        case StringExtractorGDBRemote::eServerPacketType_qGroupName: +            packet_result = Handle_qGroupName (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: +            packet_result = Handle_qProcessInfoPID (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: +            packet_result = Handle_qSpeedTest (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qUserName: +            packet_result = Handle_qUserName (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: +            packet_result = Handle_qGetWorkingDir(packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QEnvironment: +            packet_result = Handle_QEnvironment (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: +            packet_result = Handle_QLaunchArch (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: +            packet_result = Handle_QSetDisableASLR (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: +            packet_result = Handle_QSetSTDIN (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: +            packet_result = Handle_QSetSTDOUT (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: +            packet_result = Handle_QSetSTDERR (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: +            packet_result = Handle_QSetWorkingDir (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: +            packet_result = Handle_QStartNoAckMode (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: +            packet_result = Handle_qPlatform_mkdir (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: +            packet_result = Handle_qPlatform_chmod (packet); +            break; + +        case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: +            packet_result = Handle_qPlatform_shell (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: -                return Handle_qProcessInfoPID (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_open: +            packet_result = Handle_vFile_Open (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: -                return Handle_qSpeedTest (packet); - -            case StringExtractorGDBRemote::eServerPacketType_qUserName: -                return Handle_qUserName (packet); - -            case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: -                return Handle_qGetWorkingDir(packet); -     -            case StringExtractorGDBRemote::eServerPacketType_QEnvironment: -                return Handle_QEnvironment (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_close: +            packet_result = Handle_vFile_Close (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: -                return Handle_QLaunchArch (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_pread: +            packet_result = Handle_vFile_pRead (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: -                return Handle_QSetDisableASLR (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: +            packet_result = Handle_vFile_pWrite (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: -                return Handle_QSetSTDIN (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_size: +            packet_result = Handle_vFile_Size (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: -                return Handle_QSetSTDOUT (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_mode: +            packet_result = Handle_vFile_Mode (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: -                return Handle_QSetSTDERR (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_exists: +            packet_result = Handle_vFile_Exists (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: -                return Handle_QSetWorkingDir (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_stat: +            packet_result = Handle_vFile_Stat (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: -                return Handle_QStartNoAckMode (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_md5: +            packet_result = Handle_vFile_MD5 (packet); +            break; -            case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: -                return Handle_qPlatform_mkdir (packet); - -            case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: -                return Handle_qPlatform_chmod (packet); - -            case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: -                return Handle_qPlatform_shell (packet); - -            case StringExtractorGDBRemote::eServerPacketType_vFile_open: -                return Handle_vFile_Open (packet); - -            case StringExtractorGDBRemote::eServerPacketType_vFile_close: -                return Handle_vFile_Close (packet); +        case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: +            packet_result = Handle_vFile_symlink (packet); +            break; +             +        case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: +            packet_result = Handle_vFile_unlink (packet); +            break; +        } +    } +    else +    { +        if (!IsConnected()) +        { +            error.SetErrorString("lost connection"); +            quit = true; +        } +        else +        { +            error.SetErrorString("timeout"); +        } +    } +    return packet_result == PacketResult::Success; +} -            case StringExtractorGDBRemote::eServerPacketType_vFile_pread: -                return Handle_vFile_pRead (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchArguments (const char *const args[], int argc) +{ +    if ((argc < 1) || !args || !args[0] || !args[0][0]) +        return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); -            case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: -                return Handle_vFile_pWrite (packet); +    m_process_launch_info.SetArguments (const_cast<const char**> (args), true); +    return lldb_private::Error (); +} -            case StringExtractorGDBRemote::eServerPacketType_vFile_size: -                return Handle_vFile_Size (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) +{ +    m_process_launch_info.GetFlags ().Set (launch_flags); +    return lldb_private::Error (); +} -            case StringExtractorGDBRemote::eServerPacketType_vFile_mode: -                return Handle_vFile_Mode (packet); +lldb_private::Error +GDBRemoteCommunicationServer::LaunchProcess () +{ +    if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) +        return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); -            case StringExtractorGDBRemote::eServerPacketType_vFile_exists: -                return Handle_vFile_Exists (packet); +    // specify the process monitor if not already set.  This should +    // generally be what happens since we need to reap started +    // processes. +    if (!m_process_launch_info.GetMonitorProcessCallback ()) +        m_process_launch_info.SetMonitorProcessCallback(ReapDebuggedProcess, this, false); -            case StringExtractorGDBRemote::eServerPacketType_vFile_stat: -                return Handle_vFile_Stat (packet); +    lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info); +    if (!error.Success ()) +    { +        fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); +        return error; +    } -            case StringExtractorGDBRemote::eServerPacketType_vFile_md5: -                return Handle_vFile_MD5 (packet); +    printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); -            case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: -                return Handle_vFile_symlink (packet); -                 -            case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: -                return Handle_vFile_unlink (packet); -        } -        return true; -    } -    else +    // add to list of spawned processes.  On an lldb-gdbserver, we +    // would expect there to be only one. +    lldb::pid_t pid; +    if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID )      { -        if (!IsConnected()) -            error.SetErrorString("lost connection"); -        else -            error.SetErrorString("timeout"); +        Mutex::Locker locker (m_spawned_pids_mutex); +        m_spawned_pids.insert(pid);      } -    return false; +    return error;  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)  {      // TODO: Log the packet we aren't handling...      return SendPacketNoLock ("", 0);  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)  {      char packet[16]; @@ -247,7 +361,7 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)  } -size_t +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::SendOKResponse ()  {      return SendPacketNoLock ("OK", 2); @@ -256,10 +370,10 @@ GDBRemoteCommunicationServer::SendOKResponse ()  bool  GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)  { -    return GetAck(); +    return GetAck() == PacketResult::Success;  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)  {      StreamString response; @@ -272,6 +386,14 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet      response.PutCStringAsRawHex8(host_triple.getTriple().c_str());      response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); +    const char* distribution_id = host_arch.GetDistributionId ().AsCString (); +    if (distribution_id) +    { +        response.PutCString("distribution_id:"); +        response.PutCStringAsRawHex8(distribution_id); +        response.PutCString(";"); +    } +      uint32_t cpu = host_arch.GetMachOCPUType();      uint32_t sub = host_arch.GetMachOCPUSubType();      if (cpu != LLDB_INVALID_CPUTYPE) @@ -351,7 +473,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet      }  #endif  // #if defined(__APPLE__) -    return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; +    return SendPacketNoLock (response.GetData(), response.GetSize());  }  static void @@ -377,7 +499,7 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r      }  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)  {      // Packet format: "qProcessInfoPID:%i" where %i is the pid @@ -396,7 +518,7 @@ GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &      return SendErrorResponse (1);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)  {      m_proc_infos_index = 0; @@ -497,7 +619,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa      return SendErrorResponse (3);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)  {      if (m_proc_infos_index < m_proc_infos.GetSize()) @@ -510,7 +632,7 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa      return SendErrorResponse (4);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)  {      // Packet format: "qUserName:%i" where %i is the uid @@ -530,7 +652,7 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)  {      // Packet format: "qGroupName:%i" where %i is the gid @@ -549,7 +671,7 @@ GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packe      return SendErrorResponse (6);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("qSpeedTest:")); @@ -641,7 +763,7 @@ AcceptPortFromInferior (void *arg)  //    return false;  //} -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)  {      // The 'A' packet is the most over designed packet ever here with @@ -708,8 +830,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)      if (success)      { +        // FIXME: remove linux restriction once eLaunchFlagDebug is supported +#if !defined (__linux__)          m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); -        m_process_launch_error = Host::LaunchProcess (m_process_launch_info); +#endif +        m_process_launch_error = LaunchProcess ();          if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)          {              return SendOKResponse (); @@ -718,7 +843,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)      return SendErrorResponse (8);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)  {      lldb::pid_t pid = m_process_launch_info.GetProcessID(); @@ -762,11 +887,30 @@ GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,  }  bool +GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid) +{ +    // reap a process that we were debugging (but not debugserver) +    Mutex::Locker locker (m_spawned_pids_mutex); +    return m_spawned_pids.erase(pid) > 0; +} + +bool +GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton, +                                                   lldb::pid_t pid, +                                                   bool exited, +                                                   int signal,    // Zero for no signal +                                                   int status)    // Exit value of process if signal is zero +{ +    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; +    server->DebuggedProcessReaped (pid); +    return true; +} + +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)  {  #ifdef _WIN32 -    // No unix sockets on windows -    return false; +    return SendErrorResponse(9);  #else      // Spawn a local debugserver as a platform so we can then attach or launch      // a process... @@ -775,7 +919,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote      {          // Sleep and wait a bit for debugserver to start to listen...          ConnectionFileDescriptor file_conn; -        char connect_url[PATH_MAX];          Error error;          std::string hostname;          // TODO: /tmp/ should not be hardcoded. User might want to override /tmp @@ -796,45 +939,23 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote          // Spawn a new thread to accept the port that gets bound after          // binding to port 0 (zero). -        lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; -        const char *unix_socket_name = NULL; -        char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; - -        if (port == 0) -        { -            if (::mkstemp (unix_socket_name_buf) == 0) -            { -                unix_socket_name = unix_socket_name_buf; -                ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); -                accept_thread = Host::ThreadCreate (unix_socket_name, -                                                    AcceptPortFromInferior, -                                                    connect_url, -                                                    &error); -            } -            else -            { -                error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); -            } -        }          if (error.Success())          {              // Spawn a debugserver and try to get the port it listens to.              ProcessLaunchInfo debugserver_launch_info; -            StreamString host_and_port;              if (hostname.empty())                  hostname = "localhost"; -            host_and_port.Printf("%s:%u", hostname.c_str(), port); -            const char *host_and_port_cstr = host_and_port.GetString().c_str();              Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));              if (log) -                log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); +                log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);              debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); -            error = StartDebugserverProcess (host_and_port_cstr, -                                             unix_socket_name, -                                             debugserver_launch_info); +            error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), +                                             port, +                                             debugserver_launch_info, +                                             port);              lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -854,45 +975,17 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote              if (error.Success())              { -                bool success = false; +                char response[256]; +                const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); +                assert (response_len < sizeof(response)); +                PacketResult packet_result = SendPacketNoLock (response, response_len); -                if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) -                { -                    thread_result_t accept_thread_result = NULL; -                    if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) -                    { -                        if (accept_thread_result) -                        { -                            port = (intptr_t)accept_thread_result; -                            char response[256]; -                            const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); -                            assert (response_len < sizeof(response)); -                            //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); -                            success = SendPacketNoLock (response, response_len) > 0; -                        } -                    } -                } -                else -                { -                    char response[256]; -                    const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); -                    assert (response_len < sizeof(response)); -                    //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); -                    success = SendPacketNoLock (response, response_len) > 0; - -                } -                Host::Unlink (unix_socket_name); - -                if (!success) +                if (packet_result != PacketResult::Success)                  {                      if (debugserver_pid != LLDB_INVALID_PROCESS_ID)                          ::kill (debugserver_pid, SIGINT);                  } -                return success; -            } -            else if (accept_thread) -            { -                Host::Unlink (unix_socket_name); +                return packet_result;              }          }      } @@ -901,59 +994,124 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote  }  bool -GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)  { -    // Spawn a local debugserver as a platform so we can then attach or launch -    // a process... - -    if (m_is_platform) +    // make sure we know about this process      { -        packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); +        Mutex::Locker locker (m_spawned_pids_mutex); +        if (m_spawned_pids.find(pid) == m_spawned_pids.end()) +            return false; +    } -        lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); +    // first try a SIGTERM (standard kill) +    Host::Kill (pid, SIGTERM); -        // Scope for locker +    // check if that worked +    for (size_t i=0; i<10; ++i) +    {          {              Mutex::Locker locker (m_spawned_pids_mutex);              if (m_spawned_pids.find(pid) == m_spawned_pids.end()) -                return SendErrorResponse (10); +            { +                // it is now killed +                return true; +            }          } -        Host::Kill (pid, SIGTERM); +        usleep (10000); +    } + +    // check one more time after the final usleep +    { +        Mutex::Locker locker (m_spawned_pids_mutex); +        if (m_spawned_pids.find(pid) == m_spawned_pids.end()) +            return true; +    } + +    // the launched process still lives.  Now try killling it again, +    // this time with an unblockable signal. +    Host::Kill (pid, SIGKILL); -        for (size_t i=0; i<10; ++i) +    for (size_t i=0; i<10; ++i) +    {          { -            // Scope for locker +            Mutex::Locker locker (m_spawned_pids_mutex); +            if (m_spawned_pids.find(pid) == m_spawned_pids.end())              { -                Mutex::Locker locker (m_spawned_pids_mutex); -                if (m_spawned_pids.find(pid) == m_spawned_pids.end()) -                    return SendOKResponse(); +                // it is now killed +                return true;              } -            usleep (10000);          } +        usleep (10000); +    } + +    // check one more time after the final usleep +    // Scope for locker +    { +        Mutex::Locker locker (m_spawned_pids_mutex); +        if (m_spawned_pids.find(pid) == m_spawned_pids.end()) +            return true; +    } + +    // no luck - the process still lives +    return false; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +{ +    packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + +    lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); -        // Scope for locker +    // verify that we know anything about this pid. +    // Scope for locker +    { +        Mutex::Locker locker (m_spawned_pids_mutex); +        if (m_spawned_pids.find(pid) == m_spawned_pids.end())          { -            Mutex::Locker locker (m_spawned_pids_mutex); -            if (m_spawned_pids.find(pid) == m_spawned_pids.end()) -                return SendOKResponse(); +            // not a pid we know about +            return SendErrorResponse (10);          } -        Host::Kill (pid, SIGKILL); +    } + +    // go ahead and attempt to kill the spawned process +    if (KillSpawnedProcess (pid)) +        return SendOKResponse (); +    else +        return SendErrorResponse (11); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) +{ +    // ignore for now if we're lldb_platform +    if (m_is_platform) +        return SendUnimplementedResponse (packet.GetStringRef().c_str()); -        for (size_t i=0; i<10; ++i) +    // shutdown all spawned processes +    std::set<lldb::pid_t> spawned_pids_copy; + +    // copy pids +    { +        Mutex::Locker locker (m_spawned_pids_mutex); +        spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ()); +    } + +    // nuke the spawned processes +    for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it) +    { +        lldb::pid_t spawned_pid = *it; +        if (!KillSpawnedProcess (spawned_pid))          { -            // Scope for locker -            { -                Mutex::Locker locker (m_spawned_pids_mutex); -                if (m_spawned_pids.find(pid) == m_spawned_pids.end()) -                    return SendOKResponse(); -            } -            usleep (10000); +            fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);          }      } -    return SendErrorResponse (11); + +    // TODO figure out how to shut down gracefully at this point +    return SendOKResponse ();  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)  {      if (m_process_launch_error.Success()) @@ -964,7 +1122,7 @@ GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &p      return SendPacketNoLock (response.GetData(), response.GetSize());  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QEnvironment  (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QEnvironment:")); @@ -977,7 +1135,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment  (StringExtractorGDBRemote &pa      return SendErrorResponse (12);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QLaunchArch:")); @@ -992,7 +1150,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack      return SendErrorResponse(13);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QSetDisableASLR:")); @@ -1003,7 +1161,7 @@ GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &      return SendOKResponse ();  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QSetWorkingDir:")); @@ -1027,7 +1185,7 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p      return SendOKResponse ();  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)  {      StreamString response; @@ -1043,8 +1201,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p          else          {              response.PutBytesAsRawHex8(cwd, strlen(cwd)); -            SendPacketNoLock(response.GetData(), response.GetSize()); -            return true; +            return SendPacketNoLock(response.GetData(), response.GetSize());          }      }      else @@ -1053,8 +1210,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p          if (working_dir && working_dir[0])          {              response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); -            SendPacketNoLock(response.GetData(), response.GetSize()); -            return true; +            return SendPacketNoLock(response.GetData(), response.GetSize());          }          else          { @@ -1063,7 +1219,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p      }  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -1080,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet      return SendErrorResponse (15);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QSetSTDOUT:")); @@ -1097,7 +1253,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe      return SendErrorResponse (16);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen ("QSetSTDERR:")); @@ -1114,16 +1270,16 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe      return SendErrorResponse (17);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)  {      // Send response first before changing m_send_acks to we ack this packet -    SendOKResponse (); +    PacketResult packet_result = SendOKResponse ();      m_send_acks = false; -    return true; +    return packet_result;  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("qPlatform_mkdir:")); @@ -1141,7 +1297,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &      return SendErrorResponse(20);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("qPlatform_chmod:")); @@ -1160,7 +1316,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &      return SendErrorResponse(19);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:open:")); @@ -1176,7 +1332,6 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe                  mode_t mode = packet.GetHexMaxU32(false, 0600);                  Error error;                  int fd = ::open (path.c_str(), flags, mode); -                printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>");                  const int save_errno = fd == -1 ? errno : 0;                  StreamString response;                  response.PutChar('F'); @@ -1190,7 +1345,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe      return SendErrorResponse(18);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:close:")); @@ -1215,7 +1370,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack      return SendPacketNoLock(response.GetData(), response.GetSize());  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)  {  #ifdef _WIN32 @@ -1257,7 +1412,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack  #endif  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)  {  #ifdef _WIN32 @@ -1294,7 +1449,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac  #endif  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:size:")); @@ -1316,7 +1471,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe      return SendErrorResponse(22);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:mode:")); @@ -1335,7 +1490,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe      return SendErrorResponse(23);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:exists:")); @@ -1356,7 +1511,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac      return SendErrorResponse(24);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:symlink:")); @@ -1370,7 +1525,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa      return SendPacketNoLock(response.GetData(), response.GetSize());  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:unlink:")); @@ -1382,7 +1537,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac      return SendPacketNoLock(response.GetData(), response.GetSize());  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("qPlatform_shell:")); @@ -1424,13 +1579,13 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &      return SendErrorResponse(24);  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)  {      return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");  } -bool +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)  {      packet.SetFilePos(::strlen("vFile:MD5:")); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 721ea5012b33f..913c6b673cfb5 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -37,6 +37,9 @@ public:      //------------------------------------------------------------------      GDBRemoteCommunicationServer(bool is_platform); +    GDBRemoteCommunicationServer(bool is_platform, +                                 const lldb::PlatformSP& platform_sp);  +      virtual      ~GDBRemoteCommunicationServer(); @@ -138,7 +141,55 @@ public:          m_port_offset = port_offset;      } +    //------------------------------------------------------------------ +    /// Specify the program to launch and its arguments. +    /// +    /// The LaunchProcess () command can be executed to do the lauching. +    /// +    /// @param[in] args +    ///     The command line to launch. +    /// +    /// @param[in] argc +    ///     The number of elements in the args array of cstring pointers. +    /// +    /// @return +    ///     An Error object indicating the success or failure of making +    ///     the setting. +    //------------------------------------------------------------------ +    lldb_private::Error +    SetLaunchArguments (const char *const args[], int argc); + +    //------------------------------------------------------------------ +    /// Specify the launch flags for the process. +    /// +    /// The LaunchProcess () command can be executed to do the lauching. +    /// +    /// @param[in] launch_flags +    ///     The launch flags to use when launching this process. +    /// +    /// @return +    ///     An Error object indicating the success or failure of making +    ///     the setting. +    //------------------------------------------------------------------ +    lldb_private::Error +    SetLaunchFlags (unsigned int launch_flags); + +    //------------------------------------------------------------------ +    /// Launch a process with the current launch settings. +    /// +    /// This method supports running an lldb-gdbserver or similar +    /// server in a situation where the startup code has been provided +    /// with all the information for a child process to be launched. +    /// +    /// @return +    ///     An Error object indicating the success or failure of the +    ///     launch. +    //------------------------------------------------------------------ +    lldb_private::Error +    LaunchProcess (); +  protected: +    lldb::PlatformSP m_platform_sp;      lldb::thread_t m_async_thread;      lldb_private::ProcessLaunchInfo m_process_launch_info;      lldb_private::Error m_process_launch_error; @@ -148,120 +199,123 @@ protected:      uint32_t m_proc_infos_index;      PortMap m_port_map;      uint16_t m_port_offset; -     -    size_t + +    PacketResult      SendUnimplementedResponse (const char *packet); -    size_t +    PacketResult      SendErrorResponse (uint8_t error); -    size_t +    PacketResult      SendOKResponse (); -    bool +    PacketResult      Handle_A (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qHostInfo (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); -    bool +    PacketResult +    Handle_k (StringExtractorGDBRemote &packet); + +    PacketResult      Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qfProcessInfo (StringExtractorGDBRemote &packet); -    bool  +    PacketResult      Handle_qsProcessInfo (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qC (StringExtractorGDBRemote &packet); -    bool  +    PacketResult      Handle_qUserName (StringExtractorGDBRemote &packet); -    bool  +    PacketResult      Handle_qGroupName (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qSpeedTest (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QEnvironment  (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QLaunchArch (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QSetSTDIN (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_QSetSTDERR (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Open (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Close (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_pRead (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_pWrite (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Size (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Mode (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Exists (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_symlink (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_unlink (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_Stat (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_vFile_MD5 (StringExtractorGDBRemote &packet); -    bool +    PacketResult      Handle_qPlatform_shell (StringExtractorGDBRemote &packet);  private: @@ -275,6 +329,19 @@ private:                              int signal,                              int status); +    bool +    DebuggedProcessReaped (lldb::pid_t pid); + +    static bool +    ReapDebuggedProcess (void *callback_baton, +                         lldb::pid_t pid, +                         bool exited, +                         int signal, +                         int status); + +    bool +    KillSpawnedProcess (lldb::pid_t pid); +      //------------------------------------------------------------------      // For GDBRemoteCommunicationServer only      //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c291df786d100..73b9b3e8267e2 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -275,7 +275,7 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo      if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),                                                packet.GetString().size(),                                                response, -                                              false)) +                                              false) == GDBRemoteCommunication::PacketResult::Success)      {          if (response.IsOKResponse())              return true; @@ -298,7 +298,7 @@ GDBRemoteRegisterContext::SyncThreadState(Process *process)      if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),                                                packet.GetString().size(),                                                response, -                                              false)) +                                              false) == GDBRemoteCommunication::PacketResult::Success)      {          if (response.IsOKResponse())              InvalidateAllRegisters(); @@ -363,7 +363,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *                      if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),                                                                packet.GetString().size(),                                                                response, -                                                              false)) +                                                              false) == GDBRemoteCommunication::PacketResult::Success)                      {                          SetAllRegisterValid (false);                          if (response.IsOKResponse()) @@ -519,7 +519,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)                  packet_len = ::snprintf (packet, sizeof(packet), "g");              assert (packet_len < ((int)sizeof(packet) - 1)); -            if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) +            if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)              {                  if (response.IsErrorResponse())                      return false; @@ -591,7 +591,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data              if (gdb_comm.SendPacketAndWaitForResponse (G_packet,                                                         G_packet_len,                                                         response, -                                                       false)) +                                                       false) == GDBRemoteCommunication::PacketResult::Success)              {                  if (response.IsOKResponse())                      return true; @@ -660,7 +660,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data                                  if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),                                                                            packet.GetString().size(),                                                                            response, -                                                                          false)) +                                                                          false) == GDBRemoteCommunication::PacketResult::Success)                                  {                                      if (response.IsOKResponse())                                          ++num_restored; diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7f1fbefc1b7e4..e1989eb1dd142 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -34,7 +34,6 @@  #include "lldb/Core/Debugger.h"  #include "lldb/Core/ConnectionFileDescriptor.h"  #include "lldb/Host/FileSpec.h" -#include "lldb/Core/InputReader.h"  #include "lldb/Core/Module.h"  #include "lldb/Core/ModuleSpec.h"  #include "lldb/Core/PluginManager.h" @@ -95,7 +94,7 @@ using namespace lldb_private;  namespace { -     +      static PropertyDefinition      g_properties[] =      { @@ -187,7 +186,7 @@ get_random_port ()      if (!rand_initialized)      {          time_t seed = time(NULL); - +                  rand_initialized = true;          srand(seed);      } @@ -386,7 +385,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)          const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);          assert (packet_len < (int)sizeof(packet));          StringExtractorGDBRemote response; -        if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) +        if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)          {              response_type = response.GetResponseType();              if (response_type == StringExtractorGDBRemote::eResponse) @@ -537,6 +536,10 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)                  m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);              } +            else +            { +                break;  // ensure exit before reg_num is incremented +            }          }          else          { @@ -645,13 +648,20 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)          // We have a valid process          SetID (pid);          GetThreadList(); -        if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) +        if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)          { -            if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture -               m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); +            if (!m_target.GetArchitecture().IsValid())  +            { +                if (m_gdb_comm.GetProcessArchitecture().IsValid()) +                { +                    m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); +                } +                else +                { +                    m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); +                }              } -              const StateType state = SetThreadStopInfo (m_last_stop_packet);              if (state == eStateStopped)              { @@ -690,7 +700,7 @@ ProcessGDBRemote::WillLaunchOrAttach ()  // Process Control  //----------------------------------------------------------------------  Error -ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_info) +ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)  {      Error error; @@ -728,23 +738,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_      ObjectFile * object_file = exe_module->GetObjectFile();      if (object_file)      { -        char host_port[128]; -        snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); -        char connect_url[128]; -        snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); -          // Make sure we aren't already connected?          if (!m_gdb_comm.IsConnected())          { -            error = StartDebugserverProcess (host_port, launch_info); -            if (error.Fail()) -            { -                if (log) -                    log->Printf("failed to start debugserver process: %s", error.AsCString()); -                return error; -            } - -            error = ConnectToDebugserver (connect_url); +            error = LaunchAndConnectToDebugserver (launch_info);          }          if (error.Success()) @@ -848,10 +845,18 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_                  return error;              } -            if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) +            if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)              { -                if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture -                   m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); +                if (!m_target.GetArchitecture().IsValid())  +                { +                    if (m_gdb_comm.GetProcessArchitecture().IsValid()) +                    { +                        m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); +                    } +                    else +                    { +                        m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); +                    }                  }                  SetPrivateState (SetThreadStopInfo (m_last_stop_packet)); @@ -886,31 +891,35 @@ Error  ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)  {      Error error; -    // Sleep and wait a bit for debugserver to start to listen... -    std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); -    if (conn_ap.get()) +    // Only connect if we have a valid connect URL +     +    if (connect_url && connect_url[0])      { -        const uint32_t max_retry_count = 50; -        uint32_t retry_count = 0; -        while (!m_gdb_comm.IsConnected()) +        std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); +        if (conn_ap.get())          { -            if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) +            const uint32_t max_retry_count = 50; +            uint32_t retry_count = 0; +            while (!m_gdb_comm.IsConnected())              { -                m_gdb_comm.SetConnection (conn_ap.release()); -                break; -            } -            else if (error.WasInterrupted()) -            { -                // If we were interrupted, don't keep retrying. -                break; -            } -             -            retry_count++; -             -            if (retry_count >= max_retry_count) -                break; +                if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) +                { +                    m_gdb_comm.SetConnection (conn_ap.release()); +                    break; +                } +                else if (error.WasInterrupted()) +                { +                    // If we were interrupted, don't keep retrying. +                    break; +                } +                 +                retry_count++; +                 +                if (retry_count >= max_retry_count) +                    break; -            usleep (100000); +                usleep (100000); +            }          }      } @@ -1040,12 +1049,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process          // Make sure we aren't already connected?          if (!m_gdb_comm.IsConnected())          { -            char host_port[128]; -            snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); -            char connect_url[128]; -            snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - -            error = StartDebugserverProcess (host_port, attach_info); +            error = LaunchAndConnectToDebugserver (attach_info);              if (error.Fail())              { @@ -1055,10 +1059,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process                  SetExitStatus (-1, error_string);              } -            else -            { -                error = ConnectToDebugserver (connect_url); -            }          }          if (error.Success()) @@ -1072,29 +1072,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process      return error;  } -size_t -ProcessGDBRemote::AttachInputReaderCallback -( -    void *baton,  -    InputReader *reader,  -    lldb::InputReaderAction notification, -    const char *bytes,  -    size_t bytes_len -) -{ -    if (notification == eInputReaderGotToken) -    { -        ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton; -        if (gdb_process->m_waiting_for_attach) -            gdb_process->m_waiting_for_attach = false; -        reader->SetIsDone(true); -        return 1; -    } -    return 0; -} -  Error -ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info) +ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info)  {      Error error;      // Clear out and clean up from any current state @@ -1105,12 +1084,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait          // Make sure we aren't already connected?          if (!m_gdb_comm.IsConnected())          { -            char host_port[128]; -            snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); -            char connect_url[128]; -            snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); +            error = LaunchAndConnectToDebugserver (attach_info); -            error = StartDebugserverProcess (host_port, attach_info);              if (error.Fail())              {                  const char *error_string = error.AsCString(); @@ -1119,17 +1094,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait                  SetExitStatus (-1, error_string);              } -            else -            { -                error = ConnectToDebugserver (connect_url); -            }          }          if (error.Success())          {              StreamString packet; -            if (wait_for_launch) +            if (attach_info.GetWaitForLaunch())              {                  if (!m_gdb_comm.GetVAttachOrWaitSupported())                  { @@ -1199,7 +1170,11 @@ ProcessGDBRemote::DoResume ()          bool continue_packet_error = false;          if (m_gdb_comm.HasAnyVContSupport ())          { -            if (m_continue_c_tids.size() == num_threads) +            if (m_continue_c_tids.size() == num_threads || +                (m_continue_c_tids.empty() && +                 m_continue_C_tids.empty() && +                 m_continue_s_tids.empty() && +                 m_continue_S_tids.empty()))              {                  // All threads are continuing, just send a "c" packet                  continue_packet.PutCString ("c"); @@ -2026,7 +2001,7 @@ ProcessGDBRemote::DoDestroy ()              bool send_async = true;              const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3); -            if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async)) +            if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success)              {                  char packet_cmd = response.GetChar(0); @@ -2128,7 +2103,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro      const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);      assert (packet_len + 1 < (int)sizeof(packet));      StringExtractorGDBRemote response; -    if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) +    if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success)      {          if (response.IsNormalResponse())          { @@ -2164,7 +2139,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro      packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);      packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());      StringExtractorGDBRemote response; -    if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true)) +    if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success)      {          if (response.IsOKResponse())          { @@ -2546,14 +2521,7 @@ ProcessGDBRemote::DoSignal (int signo)  }  Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url) -{ -    ProcessLaunchInfo launch_info; -    return StartDebugserverProcess(debugserver_url, launch_info); -} - -Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info)    // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") +ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info)  {      Error error;      if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) @@ -2562,141 +2530,55 @@ ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const Pr          static FileSpec g_debugserver_file_spec;          ProcessLaunchInfo debugserver_launch_info; -        char debugserver_path[PATH_MAX]; -        FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile(); - -        // Always check to see if we have an environment override for the path -        // to the debugserver to use and use it if we do. -        const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); -        if (env_debugserver_path) -            debugserver_file_spec.SetFile (env_debugserver_path, false); -        else -            debugserver_file_spec = g_debugserver_file_spec; -        bool debugserver_exists = debugserver_file_spec.Exists(); -        if (!debugserver_exists) -        { -            // The debugserver binary is in the LLDB.framework/Resources -            // directory.  -            if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) -            { -                debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); -                debugserver_exists = debugserver_file_spec.Exists(); -                if (debugserver_exists) -                { -                    g_debugserver_file_spec = debugserver_file_spec; -                } -                else -                { -                    g_debugserver_file_spec.Clear(); -                    debugserver_file_spec.Clear(); -                } -            } -        } - -        if (debugserver_exists) -        { -            debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); - -            m_stdio_communication.Clear(); - -            Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - -            Args &debugserver_args = debugserver_launch_info.GetArguments(); -            char arg_cstr[PATH_MAX]; +        debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); +        debugserver_launch_info.SetUserID(process_info.GetUserID()); -            // Start args with "debugserver /file/path -r --" -            debugserver_args.AppendArgument(debugserver_path); -            debugserver_args.AppendArgument(debugserver_url); -            // use native registers, not the GDB registers -            debugserver_args.AppendArgument("--native-regs");    -            // make debugserver run in its own session so signals generated by  -            // special terminal key sequences (^C) don't affect debugserver -            debugserver_args.AppendArgument("--setsid"); - -            const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); -            if (env_debugserver_log_file) -            { -                ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); -                debugserver_args.AppendArgument(arg_cstr); -            } - -            const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); -            if (env_debugserver_log_flags) -            { -                ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); -                debugserver_args.AppendArgument(arg_cstr); -            } -//            debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); -//            debugserver_args.AppendArgument("--log-flags=0x802e0e"); - -            // We currently send down all arguments, attach pids, or attach  -            // process names in dedicated GDB server packets, so we don't need -            // to pass them as arguments. This is currently because of all the -            // things we need to setup prior to launching: the environment, -            // current working dir, file actions, etc. -#if 0 -            // Now append the program arguments -            if (inferior_argv) -            { -                // Terminate the debugserver args so we can now append the inferior args -                debugserver_args.AppendArgument("--"); - -                for (int i = 0; inferior_argv[i] != NULL; ++i) -                    debugserver_args.AppendArgument (inferior_argv[i]); -            } -            else if (attach_pid != LLDB_INVALID_PROCESS_ID) -            { -                ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); -                debugserver_args.AppendArgument (arg_cstr); -            } -            else if (attach_name && attach_name[0]) -            { -                if (wait_for_launch) -                    debugserver_args.AppendArgument ("--waitfor"); -                else -                    debugserver_args.AppendArgument ("--attach"); -                debugserver_args.AppendArgument (attach_name); -            } +#if defined (__APPLE__) && defined (__arm__) +        // On iOS, still do a local connection using a random port +        const char *hostname = "localhost"; +        uint16_t port = get_random_port (); +#else +        // Set hostname being NULL to do the reverse connect where debugserver +        // will bind to port zero and it will communicate back to us the port +        // that we will connect to +        const char *hostname = NULL; +        uint16_t port = 0;  #endif -             -            ProcessLaunchInfo::FileAction file_action; -             -            // Close STDIN, STDOUT and STDERR. We might need to redirect them -            // to "/dev/null" if we run into any problems. -            file_action.Close (STDIN_FILENO); -            debugserver_launch_info.AppendFileAction (file_action); -            file_action.Close (STDOUT_FILENO); -            debugserver_launch_info.AppendFileAction (file_action); -            file_action.Close (STDERR_FILENO); -            debugserver_launch_info.AppendFileAction (file_action); - -            if (log) -            { -                StreamString strm; -                debugserver_args.Dump (&strm); -                log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); -            } -            debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); -            debugserver_launch_info.SetUserID(process_info.GetUserID()); +        error = m_gdb_comm.StartDebugserverProcess (hostname, +                                                    port, +                                                    debugserver_launch_info, +                                                    port); -            error = Host::LaunchProcess(debugserver_launch_info); +        if (error.Success ()) +            m_debugserver_pid = debugserver_launch_info.GetProcessID(); +        else +            m_debugserver_pid = LLDB_INVALID_PROCESS_ID; -            if (error.Success ()) -                m_debugserver_pid = debugserver_launch_info.GetProcessID(); -            else -                m_debugserver_pid = LLDB_INVALID_PROCESS_ID; +        if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) +            StartAsyncThread (); +         +        if (error.Fail()) +        { +            Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); -            if (error.Fail() || log) -                error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path); +            if (log) +                log->Printf("failed to start debugserver process: %s", error.AsCString()); +            return error; +        } +         +        if (m_gdb_comm.IsConnected()) +        { +            // Finish the connection process by doing the handshake without connecting (send NULL URL) +            ConnectToDebugserver (NULL);          }          else          { -            error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME); +            StreamString connect_url; +            connect_url.Printf("connect://%s:%u", hostname, port); +            error = ConnectToDebugserver (connect_url.GetString().c_str());          } -        if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) -            StartAsyncThread ();      }      return error;  } diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 35244074bab74..9331775bb896d 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -21,7 +21,6 @@  #include "lldb/Core/Broadcaster.h"  #include "lldb/Core/ConstString.h"  #include "lldb/Core/Error.h" -#include "lldb/Core/InputReader.h"  #include "lldb/Core/StreamString.h"  #include "lldb/Core/StringList.h"  #include "lldb/Core/ThreadSafeValue.h" @@ -86,7 +85,7 @@ public:      virtual lldb_private::Error      DoLaunch (lldb_private::Module *exe_module,  -              const lldb_private::ProcessLaunchInfo &launch_info); +              lldb_private::ProcessLaunchInfo &launch_info);      virtual void      DidLaunch (); @@ -111,7 +110,6 @@ public:      virtual lldb_private::Error      DoAttachToProcessWithName (const char *process_name, -                               bool wait_for_launch,                                 const lldb_private::ProcessAttachInfo &attach_info);      virtual void @@ -284,10 +282,7 @@ protected:                        lldb_private::ThreadList &new_thread_list);      lldb_private::Error -    StartDebugserverProcess (const char *debugserver_url); -     -    lldb_private::Error -    StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info); +    LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info);      void      KillDebugserverProcess (); @@ -382,13 +377,6 @@ protected:      GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,                                     std::string &dispatch_queue_name); -    static size_t -    AttachInputReaderCallback (void *baton,  -                               lldb_private::InputReader *reader,  -                               lldb::InputReaderAction notification, -                               const char *bytes,  -                               size_t bytes_len); -      lldb_private::DynamicLoader *      GetDynamicLoader (); diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 4e475c80bdab3..fb524deda8137 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -19,6 +19,7 @@  #include "lldb/Target/Process.h"  #include "lldb/Target/RegisterContext.h"  #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SystemRuntime.h"  #include "lldb/Target/Target.h"  #include "lldb/Target/Unwind.h" @@ -74,10 +75,10 @@ ThreadGDBRemote::GetQueueName ()          ProcessSP process_sp (GetProcess());          if (process_sp)          { -            PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); -            if (platform_sp) +            SystemRuntime *runtime = process_sp->GetSystemRuntime (); +            if (runtime)              { -                m_dispatch_queue_name = platform_sp->GetQueueNameForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); +                m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr);              }              if (m_dispatch_queue_name.length() > 0)              { @@ -96,10 +97,10 @@ ThreadGDBRemote::GetQueueID ()          ProcessSP process_sp (GetProcess());          if (process_sp)          { -            PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); -            if (platform_sp) +            SystemRuntime *runtime = process_sp->GetSystemRuntime (); +            if (runtime)              { -                return platform_sp->GetQueueIDForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); +                return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr);              }          }      }  | 
