diff options
author | emaste <emaste@FreeBSD.org> | 2013-12-03 18:51:59 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-12-03 18:51:59 +0000 |
commit | 0f31a1ef7ecf609d469ee5b34b3f0cb24ae3492d (patch) | |
tree | b2051e4e4856cc58ac7e2d20242b870b4f355ca1 /source/Plugins/Process | |
parent | c727fe695d28799acb499e9961f11ec07d4f9fe2 (diff) | |
download | FreeBSD-src-0f31a1ef7ecf609d469ee5b34b3f0cb24ae3492d.zip FreeBSD-src-0f31a1ef7ecf609d469ee5b34b3f0cb24ae3492d.tar.gz |
Import lldb as of SVN r196259 (git 3be86e5)
(A number of files not required for the FreeBSD build have been removed.)
Sponsored by: DARPA, AFRL
Diffstat (limited to 'source/Plugins/Process')
20 files changed, 1667 insertions, 623 deletions
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 3833fa6..ac53579 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -465,13 +465,12 @@ WriteFPROperation::Execute(ProcessMonitor *monitor) class ResumeOperation : public Operation { public: - ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) : - m_tid(tid), m_signo(signo), m_result(result) { } + ResumeOperation(uint32_t signo, bool &result) : + m_signo(signo), m_result(result) { } void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; uint32_t m_signo; bool &m_result; }; @@ -479,17 +478,18 @@ private: void ResumeOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); int data = 0; if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) data = m_signo; - if (PTRACE(PT_CONTINUE, m_tid, (caddr_t)1, data)) + if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) - log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno)); + log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", pid, strerror(errno)); m_result = false; } else @@ -502,13 +502,12 @@ ResumeOperation::Execute(ProcessMonitor *monitor) class SingleStepOperation : public Operation { public: - SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result) - : m_tid(tid), m_signo(signo), m_result(result) { } + SingleStepOperation(uint32_t signo, bool &result) + : m_signo(signo), m_result(result) { } void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; uint32_t m_signo; bool &m_result; }; @@ -516,12 +515,13 @@ private: void SingleStepOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); int data = 0; if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) data = m_signo; - if (PTRACE(PT_STEP, m_tid, NULL, data)) + if (PTRACE(PT_STEP, pid, NULL, data)) m_result = false; else m_result = true; @@ -585,7 +585,7 @@ EventMessageOperation::Execute(ProcessMonitor *monitor) m_result = false; else { if (plwp.pl_flags & PL_FLAG_FORKED) { - m_message = (unsigned long *)plwp.pl_child_pid; + *m_message = plwp.pl_child_pid; m_result = true; } else m_result = false; @@ -953,7 +953,7 @@ ProcessMonitor::Launch(LaunchArgs *args) } goto FINISH; } - assert(WIFSTOPPED(status) && wpid == pid && + assert(WIFSTOPPED(status) && wpid == (::pid_t)pid && "Could not sync with inferior process."); #ifdef notyet @@ -1338,8 +1338,6 @@ ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info) void ProcessMonitor::ServeOperation(OperationArgs *args) { - int status; - ProcessMonitor *monitor = args->m_monitor; // We are finised with the arguments and are ready to go. Sync with the @@ -1467,15 +1465,15 @@ ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) } bool -ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) +ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) { bool result; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) - log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid, + log->Printf ("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", __FUNCTION__, GetPID(), m_process->GetUnixSignals().GetSignalAsCString (signo)); - ResumeOperation op(tid, signo, result); + ResumeOperation op(signo, result); DoOperation(&op); if (log) log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false"); @@ -1483,10 +1481,10 @@ ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) } bool -ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo) +ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) { bool result; - SingleStepOperation op(tid, signo, result); + SingleStepOperation op(signo, result); DoOperation(&op); return result; } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 4a9b483..44219c4 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -175,15 +175,15 @@ public: bool GetEventMessage(lldb::tid_t tid, unsigned long *message); - /// Resumes the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + /// Resumes the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. bool - Resume(lldb::tid_t tid, uint32_t signo); + Resume(lldb::tid_t unused, uint32_t signo); - /// Single steps the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + /// Single steps the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. bool - SingleStep(lldb::tid_t tid, uint32_t signo); + SingleStep(lldb::tid_t unused, uint32_t signo); /// Sends the inferior process a PTRACE_KILL signal. The inferior will /// still exists and can be interrogated. Once resumed it will exit as diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index 98e0bce..f833c9b 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -377,8 +377,6 @@ RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBuff success = WriteFPR(); if (success) { - success = true; - if (GetFPRType() == eXSAVE) { ByteOrder byte_order = GetByteOrder(); diff --git a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h index 1bab88c..86abdba 100644 --- a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h +++ b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h @@ -94,14 +94,14 @@ g_register_infos_x86_64[] = // General purpose registers. GCC, DWARF, Generic, GDB DEFINE_GPR(rax, NULL, gcc_dwarf_rax_x86_64, gcc_dwarf_rax_x86_64, LLDB_INVALID_REGNUM, gdb_rax_x86_64), DEFINE_GPR(rbx, NULL, gcc_dwarf_rbx_x86_64, gcc_dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, gdb_rbx_x86_64), - DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, gdb_rcx_x86_64), - DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, gdb_rdx_x86_64), - DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, gdb_rdi_x86_64), - DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, gdb_rsi_x86_64), + DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, gdb_rcx_x86_64), + DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, gdb_rdx_x86_64), + DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, gdb_rdi_x86_64), + DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, gdb_rsi_x86_64), DEFINE_GPR(rbp, "fp", gcc_dwarf_rbp_x86_64, gcc_dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, gdb_rbp_x86_64), DEFINE_GPR(rsp, "sp", gcc_dwarf_rsp_x86_64, gcc_dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, gdb_rsp_x86_64), - DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_INVALID_REGNUM, gdb_r8_x86_64), - DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_INVALID_REGNUM, gdb_r9_x86_64), + DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_x86_64), + DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_x86_64), DEFINE_GPR(r10, NULL, gcc_dwarf_r10_x86_64, gcc_dwarf_r10_x86_64, LLDB_INVALID_REGNUM, gdb_r10_x86_64), DEFINE_GPR(r11, NULL, gcc_dwarf_r11_x86_64, gcc_dwarf_r11_x86_64, LLDB_INVALID_REGNUM, gdb_r11_x86_64), DEFINE_GPR(r12, NULL, gcc_dwarf_r12_x86_64, gcc_dwarf_r12_x86_64, LLDB_INVALID_REGNUM, gdb_r12_x86_64), diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp new file mode 100644 index 0000000..5211362 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -0,0 +1,95 @@ +//===-- HistoryThread.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" + +#include "Plugins/Process/Utility/HistoryUnwind.h" +#include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/Process/Utility/RegisterContextHistory.h" + +#include "lldb/Core/Log.h" +#include "lldb/Target/StackFrameList.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + +HistoryThread::HistoryThread (lldb_private::Process &process, + lldb::tid_t tid, + std::vector<lldb::addr_t> pcs, + uint32_t stop_id, + bool stop_id_is_valid) : + Thread (process, LLDB_INVALID_THREAD_ID), + m_framelist_mutex(), + m_framelist(), + m_pcs (pcs), + m_stop_id (stop_id), + m_stop_id_is_valid (stop_id_is_valid), + m_extended_unwind_token (LLDB_INVALID_ADDRESS), + m_queue_name (), + m_thread_name (), + m_originating_unique_thread_id (tid), + m_queue_id (LLDB_INVALID_QUEUE_ID) +{ + m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid)); + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p HistoryThread::HistoryThread", this); +} + +HistoryThread::~HistoryThread () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", this, GetID()); + DestroyThread(); +} + +lldb::RegisterContextSP +HistoryThread::GetRegisterContext () +{ + RegisterContextSP rctx ; + if (m_pcs.size() > 0) + { + rctx.reset (new RegisterContextHistory (*this, 0, GetProcess()->GetAddressByteSize(), m_pcs[0])); + } + return rctx; + +} + +lldb::RegisterContextSP +HistoryThread::CreateRegisterContextForFrame (StackFrame *frame) +{ + return m_unwinder_ap->CreateRegisterContextForFrame (frame); +} + +lldb::StackFrameListSP +HistoryThread::GetStackFrameList () +{ + Mutex::Locker (m_framelist_mutex); + if (m_framelist.get() == NULL) + { + m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true)); + } + + return m_framelist; +} + +uint32_t +HistoryThread::GetExtendedBacktraceOriginatingIndexID () +{ + if (m_originating_unique_thread_id != LLDB_INVALID_THREAD_ID) + { + if (GetProcess()->HasAssignedIndexIDToThread (m_originating_unique_thread_id)) + { + return GetProcess()->AssignIndexIDToThread (m_originating_unique_thread_id); + } + } + return LLDB_INVALID_THREAD_ID; +} diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h new file mode 100644 index 0000000..01fdd16 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -0,0 +1,114 @@ +//===-- HistoryThread.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_HistoryThread_h_ +#define liblldb_HistoryThread_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/UserID.h" +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/StackFrameList.h" +#include "lldb/Target/Thread.h" + +namespace lldb_private { + +class HistoryThread : public lldb_private::Thread +{ +public: + HistoryThread (lldb_private::Process &process, lldb::tid_t tid, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid); + + virtual ~HistoryThread (); + + virtual lldb::RegisterContextSP + GetRegisterContext (); + + virtual lldb::RegisterContextSP + CreateRegisterContextForFrame (StackFrame *frame); + + virtual void + RefreshStateAfterStop() { } + + bool + CalculateStopInfo () { return false; } + + void + SetExtendedBacktraceToken (uint64_t token) + { + m_extended_unwind_token = token; + } + + uint64_t + GetExtendedBacktraceToken () + { + return m_extended_unwind_token; + } + + const char * + GetQueueName () + { + return m_queue_name.c_str(); + } + + void + SetQueueName (const char *name) + { + m_queue_name = name; + } + + lldb::queue_id_t + GetQueueID () + { + return m_queue_id; + } + + void + SetQueueID (lldb::queue_id_t queue) + { + m_queue_id = queue; + } + + const char * + GetThreadName () + { + return m_thread_name.c_str(); + } + + uint32_t + GetExtendedBacktraceOriginatingIndexID (); + + void + SetThreadName (const char *name) + { + m_thread_name = name; + } + +protected: + virtual lldb::StackFrameListSP + GetStackFrameList (); + + mutable Mutex m_framelist_mutex; + lldb::StackFrameListSP m_framelist; + std::vector<lldb::addr_t> m_pcs; + uint32_t m_stop_id; + bool m_stop_id_is_valid; + + uint64_t m_extended_unwind_token; + std::string m_queue_name; + std::string m_thread_name; + lldb::tid_t m_originating_unique_thread_id; + lldb::queue_id_t m_queue_id; +}; + +} // namespace lldb_private + +#endif // liblldb_HistoryThread_h_ diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp new file mode 100644 index 0000000..86665fd --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -0,0 +1,79 @@ +//===-- HistoryUnwind.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" + +#include "Plugins/Process/Utility/RegisterContextHistory.h" +#include "Plugins/Process/Utility/HistoryUnwind.h" + +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +HistoryUnwind::HistoryUnwind (Thread &thread, + std::vector<lldb::addr_t> pcs, + uint32_t stop_id, + bool stop_id_is_valid) : + Unwind (thread), + m_pcs (pcs), + m_stop_id (stop_id), + m_stop_id_is_valid (stop_id_is_valid) +{ +} + +HistoryUnwind::~HistoryUnwind () +{ +} + +void +HistoryUnwind::DoClear () +{ + Mutex::Locker locker(m_unwind_mutex); + m_pcs.clear(); + m_stop_id_is_valid = false; +} + +lldb::RegisterContextSP +HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame) +{ + RegisterContextSP rctx; + if (frame) + { + addr_t pc = frame->GetFrameCodeAddress().GetLoadAddress (&frame->GetThread()->GetProcess()->GetTarget()); + if (pc != LLDB_INVALID_ADDRESS) + { + rctx.reset (new RegisterContextHistory (*frame->GetThread().get(), frame->GetConcreteFrameIndex(), + frame->GetThread()->GetProcess()->GetAddressByteSize(), pc)); + } + } + return rctx; +} + +bool +HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc) +{ + Mutex::Locker (m_unwind_mutex); + if (frame_idx < m_pcs.size()) + { + cfa = frame_idx; + pc = m_pcs[frame_idx]; + return true; + } + return false; +} + +uint32_t +HistoryUnwind::DoGetFrameCount () +{ + return m_pcs.size(); +} diff --git a/source/Plugins/Process/Utility/HistoryUnwind.h b/source/Plugins/Process/Utility/HistoryUnwind.h new file mode 100644 index 0000000..0661b80 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryUnwind.h @@ -0,0 +1,51 @@ +//===-- HistoryUnwind.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_HistoryUnwind_h_ +#define liblldb_HistoryUnwind_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Target/Unwind.h" + +namespace lldb_private { + +class HistoryUnwind : public lldb_private::Unwind +{ +public: + HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid); + + virtual ~HistoryUnwind (); + +protected: + void + DoClear(); + + lldb::RegisterContextSP + DoCreateRegisterContextForFrame (StackFrame *frame); + + bool + DoGetFrameInfoAtIndex (uint32_t frame_idx, + lldb::addr_t& cfa, + lldb::addr_t& pc); + uint32_t + DoGetFrameCount (); + +private: + + std::vector<lldb::addr_t> m_pcs; + uint32_t m_stop_id; + bool m_stop_id_is_valid; +}; + +} // namespace lldb_private + +#endif // liblldb_HistoryUnwind_h_ diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 8b22d64..6d1b04f 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -59,11 +59,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, { const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; const bool use_inline_block_range = false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); addr_t prot_arg, flags_arg = 0; if (prot == eMmapProtNone) @@ -88,19 +90,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, { ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset }; ThreadPlanCallFunction *call_function_thread_plan = new ThreadPlanCallFunction (*thread, mmap_range.GetBaseAddress(), clang_void_ptr_type, - stop_other_threads, - unwind_on_error, - ignore_breakpoints, - &addr, - &length, - &prot_arg, - &flags_arg, - &fd, - &offset); + args, + options); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { @@ -115,12 +111,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); ExecutionResults result = process->RunThreadPlan (exe_ctx, - call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, + call_plan_sp, + options, error_strm); if (result == eExecutionCompleted) { @@ -169,56 +161,52 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, SymbolContext sc; if (sc_list.GetContextAtIndex(0, sc)) { - const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; - const bool use_inline_block_range = false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; + const bool use_inline_block_range = false; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); - AddressRange munmap_range; - if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) - { - lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + AddressRange munmap_range; + if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) + { + lldb::addr_t args[] = { addr, length }; + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, munmap_range.GetBaseAddress(), ClangASTType(), - stop_other_threads, - unwind_on_error, - ignore_breakpoints, - &addr, - &length)); - if (call_plan_sp) - { - StreamFile 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); + args, + options)); + if (call_plan_sp) + { + StreamFile 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); - StackFrame *frame = thread->GetStackFrameAtIndex (0).get(); - if (frame) - { - ExecutionContext exe_ctx; - frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, - call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, - error_strm); - if (result == eExecutionCompleted) - { - return true; - } - } - } - } - } - } + StackFrame *frame = thread->GetStackFrameAtIndex (0).get(); + if (frame) + { + ExecutionContext exe_ctx; + frame->CalculateExecutionContext (exe_ctx); + ExecutionResults result = process->RunThreadPlan (exe_ctx, + call_plan_sp, + options, + error_strm); + if (result == eExecutionCompleted) + { + return true; + } + } + } + } + } + } - return false; + return false; } bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { @@ -226,11 +214,13 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t if (thread == NULL || address == NULL) return false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -238,9 +228,8 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t = new ThreadPlanCallFunction (*thread, *address, clang_void_ptr_type, - stop_other_threads, - unwind_on_error, - ignore_breakpoints); + llvm::ArrayRef<addr_t>(), + options); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { @@ -256,11 +245,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t frame->CalculateExecutionContext (exe_ctx); ExecutionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, + options, error_strm); if (result == eExecutionCompleted) { diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/source/Plugins/Process/Utility/RegisterContextHistory.cpp new file mode 100644 index 0000000..b7adb20 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -0,0 +1,138 @@ +//===-- RegisterContextHistory.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "lldb/lldb-private.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/DWARFExpression.h" +#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/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/DynamicLoader.h" + +#include "RegisterContextHistory.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextHistory::RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, addr_t pc_value) : +RegisterContext (thread, concrete_frame_idx), + m_pc_value (pc_value) +{ + m_reg_set0.name = "General Purpose Registers"; + m_reg_set0.short_name = "GPR"; + m_reg_set0.num_registers = 1; + m_reg_set0.registers = new uint32_t(0); + + m_pc_reg_info.name = "pc"; + m_pc_reg_info.alt_name = "pc"; + m_pc_reg_info.byte_offset = 0; + m_pc_reg_info.byte_size = address_byte_size; + m_pc_reg_info.encoding = eEncodingUint; + m_pc_reg_info.format = eFormatPointer; + m_pc_reg_info.invalidate_regs = NULL; + m_pc_reg_info.value_regs = NULL; + m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM; +} + +RegisterContextHistory::~RegisterContextHistory () +{ + delete m_reg_set0.registers; + delete m_pc_reg_info.invalidate_regs; + delete m_pc_reg_info.value_regs; +} + +void +RegisterContextHistory::InvalidateAllRegisters () {} + +size_t +RegisterContextHistory::GetRegisterCount () +{ + return 1; +} + +const lldb_private::RegisterInfo * +RegisterContextHistory::GetRegisterInfoAtIndex (size_t reg) +{ + if (reg) + return NULL; + return &m_pc_reg_info; +} + +size_t +RegisterContextHistory::GetRegisterSetCount () +{ + return 1; +} + +const lldb_private::RegisterSet * +RegisterContextHistory::GetRegisterSet (size_t reg_set) +{ + if (reg_set) + return NULL; + return &m_reg_set0; +} + +bool +RegisterContextHistory::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) +{ + if (!reg_info) + return false; + uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric]; + if (reg_number == LLDB_REGNUM_GENERIC_PC) + { + value.SetUInt(m_pc_value, reg_info->byte_size); + return true; + } + return false; +} + +bool +RegisterContextHistory::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) +{ + return false; +} + +bool +RegisterContextHistory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + return false; +} + +uint32_t +RegisterContextHistory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +{ + if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) + return 0; + return LLDB_INVALID_REGNUM; +} diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.h b/source/Plugins/Process/Utility/RegisterContextHistory.h new file mode 100644 index 0000000..58e1608 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -0,0 +1,79 @@ +//===-- RegisterContextHistory.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterContextHistory_h_ +#define lldb_RegisterContextHistory_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Symbol/SymbolContext.h" + +namespace lldb_private { + +class RegisterContextHistory : public lldb_private::RegisterContext +{ +public: + typedef std::shared_ptr<RegisterContextHistory> SharedPtr; + + RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, lldb::addr_t pc_value); + + /// + // pure virtual functions from the base class that we must implement + /// + + virtual + ~RegisterContextHistory (); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t reg_set); + + virtual bool + ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + +private: + //------------------------------------------------------------------ + // For RegisterContextLLDB only + //------------------------------------------------------------------ + + lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only) + lldb_private::RegisterInfo m_pc_reg_info; + + lldb::addr_t m_pc_value; + + DISALLOW_COPY_AND_ASSIGN (RegisterContextHistory); +}; +} // namespace lldb_private + +#endif // lldb_RegisterContextHistory_h_ diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index acb3154..93641ed 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -363,71 +363,6 @@ enum { NT_FREEBSD_PROCSTAT_AUXV = 16 }; -/// Note Structure found in ELF core dumps. -/// This is PT_NOTE type program/segments in the core file. -struct ELFNote -{ - elf::elf_word n_namesz; - elf::elf_word n_descsz; - elf::elf_word n_type; - - std::string n_name; - - ELFNote() : n_namesz(0), n_descsz(0), n_type(0) - { - } - - /// Parse an ELFNote entry from the given DataExtractor starting at position - /// \p offset. - /// - /// @param[in] data - /// The DataExtractor to read from. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFRel entry was successfully read and false otherwise. - bool - Parse(const DataExtractor &data, lldb::offset_t *offset) - { - // Read all fields. - if (data.GetU32(offset, &n_namesz, 3) == NULL) - return false; - - // The name field is required to be nul-terminated, and n_namesz - // includes the terminating nul in observed implementations (contrary - // to the ELF-64 spec). A special case is needed for cores generated - // by some older Linux versions, which write a note named "CORE" - // without a nul terminator and n_namesz = 4. - if (n_namesz == 4) - { - char buf[4]; - if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4) - return false; - if (strncmp (buf, "CORE", 4) == 0) - { - n_name = "CORE"; - *offset += 4; - return true; - } - } - - const char *cstr = data.GetCStr(offset, llvm::RoundUpToAlignment(n_namesz, 4)); - if (cstr == NULL) - { - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf("Failed to parse note name lacking nul terminator"); - - return false; - } - n_name = cstr; - return true; - } -}; - // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2ac7d20..2690992 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_supports_QSaveRegisterState (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -110,17 +111,35 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() bool GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) { + ResetDiscoverableSettings(); + // Start the read thread after we send the handshake ack since if we // fail to send the handshake ack, there is no reason to continue... if (SendAck()) - return true; - - if (error_ptr) - error_ptr->SetErrorString("failed to send the handshake ack"); + { + // 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 + // a live connection to a remote GDB server... + if (QueryNoAckModeSupported()) + { + return true; + } + else + { + if (error_ptr) + error_ptr->SetErrorString("failed to get reply to handshake packet"); + } + } + else + { + if (error_ptr) + error_ptr->SetErrorString("failed to send the handshake ack"); + } return false; } -void +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported () { if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -136,8 +155,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_send_acks = false; m_supports_not_sending_acks = eLazyBoolYes; } + return true; } } + return false; } void @@ -208,6 +229,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; @@ -987,19 +1009,43 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) } int -GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) -{ - if (argv && argv[0]) +GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) +{ + // Since we don't get the send argv0 separate from the executable path, we need to + // make sure to use the actual exectuable path found in the launch_info... + std::vector<const char *> argv; + FileSpec exe_file = launch_info.GetExecutableFile(); + std::string exe_path; + const char *arg = NULL; + const Args &launch_args = launch_info.GetArguments(); + if (exe_file) + exe_path = exe_file.GetPath(); + else + { + arg = launch_args.GetArgumentAtIndex(0); + if (arg) + exe_path = arg; + } + if (!exe_path.empty()) + { + argv.push_back(exe_path.c_str()); + for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) + { + if (arg) + argv.push_back(arg); + } + } + if (!argv.empty()) { StreamString packet; packet.PutChar('A'); - const char *arg; - for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i) + for (size_t i = 0, n = argv.size(); i < n; ++i) { + arg = argv[i]; const int arg_len = strlen(arg); if (i > 0) packet.PutChar(','); - packet.Printf("%i,%i,", arg_len * 2, i); + packet.Printf("%i,%i,", arg_len * 2, (int)i); packet.PutBytesAsRawHex8 (arg, arg_len); } @@ -1783,6 +1829,22 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) return -1; } +bool +GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) + { + if (response.IsUnsupportedResponse()) + return false; + if (response.IsErrorResponse()) + return false; + response.GetHexByteString (cwd); + return !cwd.empty(); + } + return false; +} + int GDBRemoteCommunicationClient::SetWorkingDir (char const *path) { @@ -2244,7 +2306,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; StreamString stream; - stream.PutCString("qLaunchGDBServer:port:0;"); + stream.PutCString("qLaunchGDBServer;"); std::string hostname; if (Host::GetHostname (hostname)) { @@ -2495,7 +2557,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish { lldb_private::StreamString stream; - stream.PutCString("qPlatform_RunCommand:"); + stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); stream.PutHex32(timeout_sec); @@ -2534,24 +2596,44 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // return Error("unable to send packet"); } -uint32_t -GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, - mode_t mode) +Error +GDBRemoteCommunicationClient::MakeDirectory (const char *path, + uint32_t file_permissions) { lldb_private::StreamString stream; - stream.PutCString("qPlatform_IO_MkDir:"); - stream.PutHex32(mode); + stream.PutCString("qPlatform_mkdir:"); + stream.PutHex32(file_permissions); stream.PutChar(','); - stream.PutBytesAsRawHex8(path.c_str(), path.size()); + stream.PutBytesAsRawHex8(path, strlen(path)); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - return response.GetHexMaxU32(false, UINT32_MAX); + return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } - return UINT32_MAX; + return Error(); + +} +Error +GDBRemoteCommunicationClient::SetFilePermissions (const char *path, + uint32_t file_permissions) +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_chmod:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutBytesAsRawHex8(path, strlen(path)); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); + } + return Error(); + } static uint64_t @@ -2641,13 +2723,13 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp return UINT64_MAX; } -uint32_t -GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +Error +GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions) { + Error error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); - std::string path (file_spec.GetPath()); - stream.PutCStringAsRawHex8(path.c_str()); + stream.PutCStringAsRawHex8(path); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -2656,29 +2738,34 @@ GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& f if (response.GetChar() != 'F') { error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); - return 0; } - const uint32_t mode = response.GetS32(-1); - if (mode == -1) + else { - if (response.GetChar() == ',') + const uint32_t mode = response.GetS32(-1); + if (mode == -1) { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } else error.SetErrorToGenericError(); } + else + { + file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } } - else - error.Clear(); - return mode & (S_IRWXU|S_IRWXG|S_IRWXO); } else { error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); } - return 0; + return error; } uint64_t @@ -2760,6 +2847,90 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, return 0; } +Error +GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:symlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(dst); + stream.PutChar(','); + stream.PutCStringAsRawHex8(src); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("symlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:symlink packet"); + } + return error; +} + +Error +GDBRemoteCommunicationClient::Unlink (const char *path) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:unlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(path); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("unlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:unlink packet"); + } + return error; +} + // Extension of host I/O packets to get whether a file exists. bool GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) @@ -2809,3 +2980,134 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } return false; } + +bool +GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; + +} + + +bool +GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + // Get all registers in one packet + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; +} +bool +GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) +{ + save_id = 0; // Set to invalid save ID + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + m_supports_QSaveRegisterState = eLazyBoolYes; + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); + else + ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling it again + m_supports_QSaveRegisterState = eLazyBoolNo; + } + + const uint32_t response_save_id = response.GetU32(0); + if (response_save_id != 0) + { + save_id = response_save_id; + return true; + } + } + } + } + return false; +} + +bool +GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) +{ + // We use the "m_supports_QSaveRegisterState" variable here becuase the + // QSaveRegisterState and QRestoreRegisterState packets must both be supported in + // order to be useful + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); + else + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsOKResponse()) + { + return true; + } + else if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling this packet or + // QSaveRegisterState again... + m_supports_QSaveRegisterState = eLazyBoolNo; + } + } + } + } + return false; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d5535bb..564afbb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -38,7 +38,6 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationClient(bool is_platform); - virtual ~GDBRemoteCommunicationClient(); //------------------------------------------------------------------ @@ -65,10 +64,16 @@ public: size_t packet_length, StringExtractorGDBRemote &response); - virtual bool + bool GetThreadSuffixSupported (); - void + // This packet is usually sent first and the boolean return value + // indicates if the packet was send and any response was received + // even in the response is UNIMPLEMENTED. If the packet failed to + // get a response, then false is returned. This quickly tells us + // if we were able to connect and communicte with the remote GDB + // server + bool QueryNoAckModeSupported (); void @@ -109,7 +114,7 @@ public: /// response was received. //------------------------------------------------------------------ int - SendArgumentsPacket (char const *argv[]); + SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the @@ -185,7 +190,10 @@ public: //------------------------------------------------------------------ /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet. + /// be launched with the 'A' packet for non platform based + /// connections. If this packet is sent to a GDB server that + /// implements the platform, it will change the current working + /// directory for the platform process. /// /// @param[in] path /// The path to a directory to use when launching our processs @@ -196,6 +204,19 @@ public: int SetWorkingDir (char const *path); + //------------------------------------------------------------------ + /// Gets the current working directory of a remote platform GDB + /// server. + /// + /// @param[out] cwd + /// The current working directory on the remote platform. + /// + /// @return + /// Boolean for success + //------------------------------------------------------------------ + bool + GetWorkingDir (std::string &cwd); + lldb::addr_t AllocateMemory (size_t size, uint32_t permissions); @@ -356,45 +377,54 @@ public: return m_interrupt_sent; } - virtual lldb::user_id_t + lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, mode_t mode, lldb_private::Error &error); - virtual bool + bool CloseFile (lldb::user_id_t fd, lldb_private::Error &error); - virtual lldb::user_id_t + lldb::user_id_t GetFileSize (const lldb_private::FileSpec& file_spec); - virtual uint32_t - GetFilePermissions(const lldb_private::FileSpec& file_spec, - lldb_private::Error &error); + lldb_private::Error + GetFilePermissions(const char *path, uint32_t &file_permissions); + + lldb_private::Error + SetFilePermissions(const char *path, uint32_t file_permissions); - virtual uint64_t + uint64_t ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, lldb_private::Error &error); - virtual uint64_t + uint64_t WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, lldb_private::Error &error); - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode); + lldb_private::Error + CreateSymlink (const char *src, + const char *dst); - virtual bool + lldb_private::Error + Unlink (const char *path); + + lldb_private::Error + MakeDirectory (const char *path, + uint32_t mode); + + bool GetFileExists (const lldb_private::FileSpec& file_spec); - virtual lldb_private::Error + lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -402,7 +432,7 @@ public: std::string *command_output, // Pass NULL if you don't want the command output uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - virtual bool + bool CalculateMD5 (const lldb_private::FileSpec& file_spec, uint64_t &high, uint64_t &low); @@ -411,6 +441,21 @@ public: HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, StringExtractorGDBRemote &inputStringExtractor); + bool + ReadRegister(lldb::tid_t tid, + uint32_t reg_num, + StringExtractorGDBRemote &response); + + bool + ReadAllRegisters (lldb::tid_t tid, + StringExtractorGDBRemote &response); + + bool + SaveRegisterState (lldb::tid_t tid, uint32_t &save_id); + + bool + RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + protected: bool @@ -438,6 +483,7 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_supports_QSaveRegisterState; bool m_supports_qProcessInfoPID:1, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index df036cd..7cc3a05 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -47,27 +47,9 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_proc_infos (), m_proc_infos_index (0), - m_lo_port_num (0), - m_hi_port_num (0), - m_next_port (0), - m_use_port_range (false) + m_port_map (), + m_port_offset(0) { - // We seldom need to override the port number that the debugserver process - // starts with. We just pass in 0 to let the system choose a random port. - // In rare situation where the need arises, use two environment variables - // to override. - uint16_t lo_port_num = 0; - uint16_t hi_port_num = 0; - const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT"); - if (lo_port_c_str) - lo_port_num = ::atoi(lo_port_c_str); - const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT"); - if (hi_port_c_str) - hi_port_num = ::atoi(hi_port_c_str); - if (lo_port_num && hi_port_num && lo_port_num < hi_port_num) - { - SetPortRange(lo_port_num, hi_port_num); - } } //---------------------------------------------------------------------- @@ -166,6 +148,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_qUserName: return Handle_qUserName (packet); + case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: + return Handle_qGetWorkingDir(packet); + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: return Handle_QEnvironment (packet); @@ -190,38 +175,47 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: return Handle_QStartNoAckMode (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir: - return Handle_qPlatform_IO_MkDir (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: + return Handle_qPlatform_mkdir (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand: - return Handle_qPlatform_RunCommand (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: + return Handle_qPlatform_chmod (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Open: + 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: + case StringExtractorGDBRemote::eServerPacketType_vFile_close: return Handle_vFile_Close (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pRead: + case StringExtractorGDBRemote::eServerPacketType_vFile_pread: return Handle_vFile_pRead (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite: + case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: return Handle_vFile_pWrite (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Size: + case StringExtractorGDBRemote::eServerPacketType_vFile_size: return Handle_vFile_Size (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Mode: + case StringExtractorGDBRemote::eServerPacketType_vFile_mode: return Handle_vFile_Mode (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Exists: + case StringExtractorGDBRemote::eServerPacketType_vFile_exists: return Handle_vFile_Exists (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Stat: + case StringExtractorGDBRemote::eServerPacketType_vFile_stat: return Handle_vFile_Stat (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_MD5: + case StringExtractorGDBRemote::eServerPacketType_vFile_md5: return Handle_vFile_MD5 (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: + return Handle_vFile_symlink (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: + return Handle_vFile_unlink (packet); } return true; } @@ -329,12 +323,33 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#if defined(__APPLE__) + +#if defined(__arm__) + // For iOS devices, we are connected through a USB Mux so we never pretend + // to actually have a hostname as far as the remote lldb that is connecting + // to this lldb-platform is concerned + response.PutCString ("hostname:"); + response.PutCStringAsRawHex8("localhost"); + response.PutChar(';'); +#else // #if defined(__arm__) + if (Host::GetHostname (s)) + { + response.PutCString ("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } + +#endif // #if defined(__arm__) + +#else // #if defined(__APPLE__) if (Host::GetHostname (s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#endif // #if defined(__APPLE__) return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; } @@ -731,6 +746,7 @@ bool GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid) { Mutex::Locker locker (m_spawned_pids_mutex); + FreePortForProcess(pid); return m_spawned_pids.erase(pid) > 0; } bool @@ -764,105 +780,119 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp // with the TMPDIR environnement variable - char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; - if (::mkstemp (unix_socket_name) == -1) + packet.SetFilePos(::strlen ("qLaunchGDBServer;")); + std::string name; + std::string value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) { - error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); + if (name.compare ("host") == 0) + hostname.swap(value); + else if (name.compare ("port") == 0) + port = Args::StringToUInt32(value.c_str(), 0, 0); } - else - { - packet.SetFilePos(::strlen ("qLaunchGDBServer:")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = Args::StringToUInt32(value.c_str(), 0, 0); - } - if (port == UINT16_MAX) - port = GetAndUpdateNextPort(); + if (port == UINT16_MAX) + port = GetNextAvailablePort(); - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); - // 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; + // 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 (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 (IS_VALID_LLDB_HOST_THREAD(accept_thread)) + 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); + + debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); + + error = StartDebugserverProcess (host_and_port_cstr, + unix_socket_name, + debugserver_launch_info); + + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + + + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { - // 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); - error = StartDebugserverProcess (host_and_port_cstr, - unix_socket_name, - debugserver_launch_info); - - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - { - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); - } - Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false); - } + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); + if (port > 0) + AssociatePortWithProcess(port, debugserver_pid); + } + else + { + if (port > 0) + FreePort (port); + } - if (error.Success()) - { - bool success = false; + if (error.Success()) + { + bool success = false; - if (accept_thread) + if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) + { + thread_result_t accept_thread_result = NULL; + if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) { - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) + if (accept_thread_result) { - 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); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - } + 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); - 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; - } - ::unlink (unix_socket_name); + } + Host::Unlink (unix_socket_name); - if (!success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return success; + if (!success) + { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } + return success; + } + else if (accept_thread) + { + Host::Unlink (unix_socket_name); } } } @@ -896,7 +926,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } usleep (10000); } @@ -905,7 +935,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } Host::Kill (pid, SIGKILL); @@ -915,12 +945,12 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } usleep (10000); } } - return SendErrorResponse (10); + return SendErrorResponse (11); } bool @@ -944,7 +974,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); return SendOKResponse (); } - return SendErrorResponse (11); + return SendErrorResponse (12); } bool @@ -959,7 +989,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack m_process_launch_info.SetArchitecture(arch_spec); return SendOKResponse(); } - return SendErrorResponse(12); + return SendErrorResponse(13); } bool @@ -979,11 +1009,61 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p packet.SetFilePos(::strlen ("QSetWorkingDir:")); std::string path; packet.GetHexByteString(path); - m_process_launch_info.SwapWorkingDirectory (path); + if (m_is_platform) + { +#ifdef _WIN32 + // Not implemented on Windows + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented"); +#else + // If this packet is sent to a platform, then change the current working directory + if (::chdir(path.c_str()) != 0) + return SendErrorResponse(errno); +#endif + } + else + { + m_process_launch_info.SwapWorkingDirectory (path); + } return SendOKResponse (); } bool +GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) +{ + StreamString response; + + if (m_is_platform) + { + // If this packet is sent to a platform, then change the current working directory + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + { + return SendErrorResponse(errno); + } + else + { + response.PutBytesAsRawHex8(cwd, strlen(cwd)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + } + else + { + const char *working_dir = m_process_launch_info.GetWorkingDirectory(); + if (working_dir && working_dir[0]) + { + response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + else + { + return SendErrorResponse(14); + } + } +} + +bool GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -997,7 +1077,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (13); + return SendErrorResponse (15); } bool @@ -1014,7 +1094,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (14); + return SendErrorResponse (16); } bool @@ -1031,7 +1111,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (15); + return SendErrorResponse (17); } bool @@ -1044,19 +1124,40 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote & } bool -GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_IO_MkDir:")); + packet.SetFilePos(::strlen("qPlatform_mkdir:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() != ',') - return false; - std::string path; - packet.GetHexByteString(path); - uint32_t retcode = Host::MakeDirectory(path.c_str(),mode); - StreamString response; - response.PutHex32(retcode); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (packet.GetChar() == ',') + { + std::string path; + packet.GetHexByteString(path); + Error error = Host::MakeDirectory(path.c_str(),mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); + } + return SendErrorResponse(20); +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_chmod:")); + + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') + { + std::string path; + packet.GetHexByteString(path); + Error error = Host::SetFilePermissions (path.c_str(), mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); + } + return SendErrorResponse(19); } bool @@ -1065,24 +1166,28 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:open:")); std::string path; packet.GetHexByteStringTerminatedBy(path,','); - if (path.size() == 0) - return false; - if (packet.GetChar() != ',') - return false; - uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() != ',') - return false; - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - Error error; - int fd = ::open (path.c_str(), flags, mode); - const int save_errno = fd == -1 ? errno : 0; - StreamString response; - response.PutChar('F'); - response.Printf("%i", fd); - if (save_errno) - response.Printf(",%i", save_errno); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (!path.empty()) + { + if (packet.GetChar() == ',') + { + uint32_t flags = packet.GetHexMaxU32(false, 0); + if (packet.GetChar() == ',') + { + 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'); + response.Printf("%i", fd); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + } + } + return SendErrorResponse(18); } bool @@ -1107,8 +1212,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack response.Printf("%i", err); if (save_errno) response.Printf(",%i", save_errno); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } bool @@ -1116,37 +1220,40 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack { #ifdef _WIN32 // Not implemented on Windows - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented"); #else StreamGDBRemote response; packet.SetFilePos(::strlen("vFile:pread:")); int fd = packet.GetS32(-1); - if (packet.GetChar() != ',') - return false; - uint64_t count = packet.GetU64(UINT64_MAX); - if (packet.GetChar() != ',') - return false; - uint64_t offset = packet.GetU64(UINT32_MAX); - if (count == UINT64_MAX) - { - response.Printf("F-1:%i", EINVAL); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; - } - std::string buffer(count, 0); - const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); - const int save_errno = bytes_read == -1 ? errno : 0; - response.PutChar('F'); - response.Printf("%zi", bytes_read); - if (save_errno) - response.Printf(",%i", save_errno); - else + if (packet.GetChar() == ',') { - response.PutChar(';'); - response.PutEscapedBytes(&buffer[0], bytes_read); + uint64_t count = packet.GetU64(UINT64_MAX); + if (packet.GetChar() == ',') + { + uint64_t offset = packet.GetU64(UINT32_MAX); + if (count == UINT64_MAX) + { + response.Printf("F-1:%i", EINVAL); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + + std::string buffer(count, 0); + const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); + const int save_errno = bytes_read == -1 ? errno : 0; + response.PutChar('F'); + response.Printf("%zi", bytes_read); + if (save_errno) + response.Printf(",%i", save_errno); + else + { + response.PutChar(';'); + response.PutEscapedBytes(&buffer[0], bytes_read); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(21); + #endif } @@ -1154,8 +1261,7 @@ bool GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // Not implemented on Windows - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented"); #else packet.SetFilePos(::strlen("vFile:pwrite:")); @@ -1163,27 +1269,28 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac response.PutChar('F'); int fd = packet.GetU32(UINT32_MAX); - if (packet.GetChar() != ',') - return false; - off_t offset = packet.GetU64(UINT32_MAX); - if (packet.GetChar() != ',') - return false; - std::string buffer; - if (packet.GetEscapedBinaryData(buffer)) - { - const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); - const int save_errno = bytes_written == -1 ? errno : 0; - response.Printf("%zi", bytes_written); - if (save_errno) - response.Printf(",%i", save_errno); - } - else + if (packet.GetChar() == ',') { - response.Printf ("-1,%i", EINVAL); + off_t offset = packet.GetU64(UINT32_MAX); + if (packet.GetChar() == ',') + { + std::string buffer; + if (packet.GetEscapedBinaryData(buffer)) + { + const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); + const int save_errno = bytes_written == -1 ? errno : 0; + response.Printf("%zi", bytes_written); + if (save_errno) + response.Printf(",%i", save_errno); + } + else + { + response.Printf ("-1,%i", EINVAL); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(27); #endif } @@ -1193,19 +1300,20 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:size:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutHex64(retcode); - if (retcode == UINT64_MAX) + if (!path.empty()) { - response.PutChar(','); - response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() + lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutHex64(retcode); + if (retcode == UINT64_MAX) + { + response.PutChar(','); + response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() + } + return SendPacketNoLock(response.GetData(), response.GetSize()); } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(22); } bool @@ -1214,16 +1322,17 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:mode:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - Error error; - const uint32_t mode = File::GetPermissions(path.c_str(), error); - StreamString response; - response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (!path.empty()) + { + Error error; + const uint32_t mode = File::GetPermissions(path.c_str(), error); + StreamString response; + response.Printf("F%u", mode); + if (mode == 0 || error.Fail()) + response.Printf(",%i", (int)error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + return SendErrorResponse(23); } bool @@ -1232,87 +1341,118 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac packet.SetFilePos(::strlen("vFile:exists:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + if (!path.empty()) + { + bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutChar(','); + if (retcode) + response.PutChar('1'); + else + response.PutChar('0'); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + return SendErrorResponse(24); +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:symlink:")); + std::string dst, src; + packet.GetHexByteStringTerminatedBy(dst, ','); + packet.GetChar(); // Skip ',' char + packet.GetHexByteString(src); + Error error = Host::Symlink(src.c_str(), dst.c_str()); StreamString response; - response.PutChar('F'); - response.PutChar(','); - if (retcode) - response.PutChar('1'); - else - response.PutChar('0'); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); } bool -GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_RunCommand:")); + packet.SetFilePos(::strlen("vFile:unlink:")); + std::string path; + packet.GetHexByteString(path); + Error error = Host::Unlink(path.c_str()); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_shell:")); std::string path; std::string working_dir; packet.GetHexByteStringTerminatedBy(path,','); - if (path.size() == 0) - return false; - if (packet.GetChar() != ',') - return false; - // FIXME: add timeout to qPlatform_RunCommand packet - // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; - if (packet.GetChar() == ',') - packet.GetHexByteString(working_dir); - int status, signo; - std::string output; - Error err = Host::RunShellCommand(path.c_str(), - working_dir.empty() ? NULL : working_dir.c_str(), - &status, &signo, &output, timeout); - StreamGDBRemote response; - if (err.Fail()) + if (!path.empty()) { - response.PutCString("F,"); - response.PutHex32(UINT32_MAX); - } - else - { - response.PutCString("F,"); - response.PutHex32(status); - response.PutChar(','); - response.PutHex32(signo); - response.PutChar(','); - response.PutEscapedBytes(output.c_str(), output.size()); + if (packet.GetChar() == ',') + { + // FIXME: add timeout to qPlatform_shell packet + // uint32_t timeout = packet.GetHexMaxU32(false, 32); + uint32_t timeout = 10; + if (packet.GetChar() == ',') + packet.GetHexByteString(working_dir); + int status, signo; + std::string output; + Error err = Host::RunShellCommand(path.c_str(), + working_dir.empty() ? NULL : working_dir.c_str(), + &status, &signo, &output, timeout); + StreamGDBRemote response; + if (err.Fail()) + { + response.PutCString("F,"); + response.PutHex32(UINT32_MAX); + } + else + { + response.PutCString("F,"); + response.PutHex32(status); + response.PutChar(','); + response.PutHex32(signo); + response.PutChar(','); + response.PutEscapedBytes(output.c_str(), output.size()); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(24); } bool GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented"); } bool GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("vFile:exists:")); + packet.SetFilePos(::strlen("vFile:MD5:")); std::string path; packet.GetHexByteString(path); - if (path.size() == 0) - return false; - uint64_t a,b; - StreamGDBRemote response; - if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + if (!path.empty()) { - response.PutCString("F,"); - response.PutCString("x"); - } - else - { - response.PutCString("F,"); - response.PutHex64(a); - response.PutHex64(b); + uint64_t a,b; + StreamGDBRemote response; + if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + { + response.PutCString("F,"); + response.PutCString("x"); + } + else + { + response.PutCString("F,"); + response.PutHex64(a); + response.PutHex64(b); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(25); } + diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 64f6f8d..721ea50 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -26,6 +26,8 @@ class StringExtractorGDBRemote; class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: + typedef std::map<uint16_t, lldb::pid_t> PortMap; + enum { eBroadcastBitRunPacketSent = kLoUserBroadcastBit @@ -58,30 +60,85 @@ public: // Set both ports to zero to let the platform automatically bind to // a port chosen by the OS. void - SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num) + SetPortMap (PortMap &&port_map) { - m_lo_port_num = lo_port_num; - m_hi_port_num = hi_port_num; - m_next_port = m_lo_port_num; - m_use_port_range = true; + m_port_map = port_map; } - // If we are using a port range, get and update the next port to be used variable. - // Otherwise, just return 0. + //---------------------------------------------------------------------- + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return UINT16_MAX + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + //---------------------------------------------------------------------- uint16_t - GetAndUpdateNextPort () + GetNextAvailablePort () { - if (!m_use_port_range) - return 0; - uint16_t val = m_next_port; - if (++m_next_port > m_hi_port_num) - m_next_port = m_lo_port_num; - return val; + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any limitations + + for (auto &pair : m_port_map) + { + if (pair.second == LLDB_INVALID_PROCESS_ID) + { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; + } + } + return UINT16_MAX; } -protected: - //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap; + bool + AssociatePortWithProcess (uint16_t port, lldb::pid_t pid) + { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) + { + pos->second = pid; + return true; + } + return false; + } + + bool + FreePort (uint16_t port) + { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) + { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; + } + + bool + FreePortForProcess (lldb::pid_t pid) + { + if (!m_port_map.empty()) + { + for (auto &pair : m_port_map) + { + if (pair.second == pid) + { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } + } + } + return false; + } + void + SetPortOffset (uint16_t port_offset) + { + m_port_offset = port_offset; + } + +protected: lldb::thread_t m_async_thread; lldb_private::ProcessLaunchInfo m_process_launch_info; lldb_private::Error m_process_launch_error; @@ -89,11 +146,8 @@ protected: lldb_private::Mutex m_spawned_pids_mutex; lldb_private::ProcessInstanceInfoList m_proc_infos; uint32_t m_proc_infos_index; - uint16_t m_lo_port_num; - uint16_t m_hi_port_num; - //PortToPIDMap m_port_to_pid_map; - uint16_t m_next_port; - bool m_use_port_range; + PortMap m_port_map; + uint16_t m_port_offset; size_t @@ -121,7 +175,10 @@ protected: Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet); + Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); + + bool + Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); bool Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); @@ -155,6 +212,9 @@ protected: bool Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + + bool + Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); bool Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); @@ -188,6 +248,12 @@ protected: bool Handle_vFile_Exists (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_symlink (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_unlink (StringExtractorGDBRemote &packet); bool Handle_vFile_Stat (StringExtractorGDBRemote &packet); @@ -196,7 +262,7 @@ protected: Handle_vFile_MD5 (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet); + Handle_qPlatform_shell (StringExtractorGDBRemote &packet); private: bool diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c4e468f..c291df7 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -153,20 +153,13 @@ bool GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (gdb_comm.GetThreadSuffixSupported()) - packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) + StringExtractorGDBRemote response; + if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response)) return PrivateSetRegisterValue (reg, response); - return false; } + bool GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) { @@ -185,93 +178,51 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (!GetRegisterIsValid(reg)) { - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register.")) + if (m_read_all_at_once) { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) + StringExtractorGDBRemote response; + if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) + return false; + if (response.IsNormalResponse()) + if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) + SetAllRegisterValid (true); + } + else if (reg_info->value_regs) + { + // Process this composite register request by delegating to the constituent + // primordial registers. + + // Index of the primordial register. + bool success = true; + for (uint32_t idx = 0; success; ++idx) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; - if (m_read_all_at_once) - { - // Get all registers in one packet - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) - { - if (response.IsNormalResponse()) - if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) - SetAllRegisterValid (true); - } - } - else if (reg_info->value_regs) - { - // Process this composite register request by delegating to the constituent - // primordial registers. - - // Index of the primordial register. - bool success = true; - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t prim_reg = reg_info->value_regs[idx]; - if (prim_reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial regsiter as our constituent. - // Grab the corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); - if (prim_reg_info == NULL) - success = false; - else - { - // Read the containing register if it hasn't already been read - if (!GetRegisterIsValid(prim_reg)) - success = GetPrimordialRegister(prim_reg_info, gdb_comm); - } - } - - if (success) - { - // If we reach this point, all primordial register requests have succeeded. - // Validate this composite register. - SetRegisterIsValid (reg_info, true); - } - } + const uint32_t prim_reg = reg_info->value_regs[idx]; + if (prim_reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial regsiter as our constituent. + // Grab the corresponding register info. + const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + if (prim_reg_info == NULL) + success = false; else { - // Get each register individually - GetPrimordialRegister(reg_info, gdb_comm); + // Read the containing register if it hasn't already been read + if (!GetRegisterIsValid(prim_reg)) + success = GetPrimordialRegister(prim_reg_info, gdb_comm); } } + + if (success) + { + // If we reach this point, all primordial register requests have succeeded. + // Validate this composite register. + SetRegisterIsValid (reg_info, true); + } } else { -#if LLDB_CONFIGURATION_DEBUG - StreamString strm; - gdb_comm.DumpHistory(strm); - Host::SetCrashDescription (strm.GetData()); - assert (!"Didn't get sequence mutex for read register."); -#else - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData()); - } - else - { - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name); - } - } -#endif + // Get each register individually + GetPrimordialRegister(reg_info, gdb_comm); } // Make sure we got a valid register value after reading it @@ -488,6 +439,54 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * return false; } +bool +GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) +{ + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + uint32_t save_id = 0; + if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) + { + reg_checkpoint.SetID(save_id); + reg_checkpoint.GetData().reset(); + return true; + } + else + { + reg_checkpoint.SetID(0); // Invalid save ID is zero + return ReadAllRegisterValues(reg_checkpoint.GetData()); + } +} + +bool +GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) +{ + uint32_t save_id = reg_checkpoint.GetID(); + if (save_id != 0) + { + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); + } + else + { + return WriteAllRegisterValues(reg_checkpoint.GetData()); + } +} bool GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 7a49d69..38f29bb 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -91,6 +91,12 @@ public: virtual bool WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + virtual bool + ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); + + virtual bool + WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); + virtual uint32_t ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index aff9c7b..7f1fbef 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -820,7 +820,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ } const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10); - int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector()); + int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info); if (arg_packet_err == 0) { std::string error_str; @@ -926,15 +926,13 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) // then we aren't actually connected to anything, so try and do the // handshake with the remote GDB server and make sure that goes // alright. - if (!m_gdb_comm.HandshakeWithServer (NULL)) + if (!m_gdb_comm.HandshakeWithServer (&error)) { m_gdb_comm.Disconnect(); if (error.Success()) error.SetErrorString("not connected to remote gdb server"); return error; } - m_gdb_comm.ResetDiscoverableSettings(); - m_gdb_comm.QueryNoAckModeSupported (); m_gdb_comm.GetThreadSuffixSupported (); m_gdb_comm.GetListThreadsInStopReplySupported (); m_gdb_comm.GetHostInfo (); @@ -1158,6 +1156,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait } +bool +ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr) +{ + m_gdb_comm.Disconnect(); + return Process::SetExitStatus (exit_status, cstr); +} + void ProcessGDBRemote::DidAttach () { @@ -2787,6 +2792,7 @@ ProcessGDBRemote::MonitorDebugserverProcess void ProcessGDBRemote::KillDebugserverProcess () { + m_gdb_comm.Disconnect(); if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { Host::Kill (m_debugserver_pid, SIGINT); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index b18ac5b..3524407 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -222,6 +222,13 @@ public: { return m_gdb_comm; } + + //---------------------------------------------------------------------- + // Override SetExitStatus so we can disconnect from the remote GDB server + //---------------------------------------------------------------------- + virtual bool + SetExitStatus (int exit_status, const char *cstr); + protected: friend class ThreadGDBRemote; |