diff options
17 files changed, 301 insertions, 172 deletions
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 13d5ab9c96b..c435136e2e6 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Expression/ASTResultSynthesizer.h" @@ -365,6 +366,12 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString()); return false; } + +#if 0 + // jingham: look here + StreamFile logfile ("/tmp/exprs.txt", "a"); + logfile.Printf("0x%16.16llx: thread = 0x%4.4x, expr = '%s'\n", m_jit_addr, exe_ctx.thread ? exe_ctx.thread->GetID() : -1, m_expr_text.c_str()); +#endif if (log) { diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index f682e360778..d3ede6b4a34 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangExpressionParser.h" #include "lldb/Expression/ClangUtilityFunction.h" @@ -124,6 +125,15 @@ ClangUtilityFunction::Install (Stream &error_stream, Error jit_error = parser.MakeJIT (m_jit_begin, m_jit_end, exe_ctx); +#if 0 + // jingham: look here + StreamFile logfile ("/tmp/exprs.txt", "a"); + logfile.Printf ("0x%16.16llx: func = %s, source =\n%s\n", + m_jit_begin, + m_function_name.c_str(), + m_function_text.c_str()); +#endif + m_expr_decl_map->DidParse(); m_expr_decl_map.reset(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 5925812f7f3..1a7b27b40f9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -34,6 +34,7 @@ using namespace lldb_private; GDBRemoteCommunication::GDBRemoteCommunication() : Communication("gdb-remote.packets"), m_send_acks (true), + m_thread_suffix_supported (false), m_rx_packet_listener ("gdbremote.rx_packet"), m_sequence_mutex (Mutex::eMutexTypeRecursive), m_is_running (false), diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 7bc795dcf7a..c0d8685db39 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -100,6 +100,18 @@ public: } bool + GetThreadSuffixSupported () const + { + return m_thread_suffix_supported; + } + + void + SetThreadSuffixSupported (bool enabled) + { + m_thread_suffix_supported = enabled; + } + + bool SendAsyncSignal (int signo); bool @@ -244,7 +256,8 @@ protected: //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunication can see and modify these //------------------------------------------------------------------ - bool m_send_acks; + bool m_send_acks:1, + m_thread_suffix_supported:1; lldb_private::Listener m_rx_packet_listener; lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time lldb_private::Predicate<bool> m_is_running; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index eaf91eb98b1..2c00b9a8431 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -217,15 +217,19 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) { - if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); + if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) { - char packet[32]; + char packet[64]; StringExtractorGDBRemote response; - int packet_len; + int packet_len = 0; if (m_read_all_at_once) { // Get all registers in one packet - packet_len = ::snprintf (packet, sizeof(packet), "g"); + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x;", m_thread.GetID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < (sizeof(packet) - 1)); if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false)) { @@ -237,7 +241,10 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) else { // Get each register individually - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4x;", reg, m_thread.GetID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); assert (packet_len < (sizeof(packet) - 1)); if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false)) PrivateSetRegisterValue (reg, response); @@ -319,7 +326,8 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) { - if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); + if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) { uint32_t offset, end_offset; StreamString packet; @@ -336,6 +344,9 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, eByteOrderHost, eByteOrderHost); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4x;", m_thread.GetID()); + // Invalidate all register values InvalidateIfNeeded (true); @@ -361,6 +372,9 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, eByteOrderHost, eByteOrderHost); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4x;", m_thread.GetID()); + // Invalidate just this register m_reg_valid[reg] = false; if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), @@ -391,16 +405,31 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) { - if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + char packet[32]; + const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); + if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) { - if (gdb_comm.SendPacketAndWaitForResponse("g", response, 1, false)) + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x", m_thread.GetID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < (sizeof(packet) - 1)); + + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 1, false)) { if (response.IsErrorPacket()) return false; - + response.GetStringRef().insert(0, 1, 'G'); - data_sp.reset (new DataBufferHeap(response.GetStringRef().c_str(), - response.GetStringRef().size())); + if (thread_suffix_supported) + { + char thread_id_cstr[64]; + ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4x;", m_thread.GetID()); + response.GetStringRef().append (thread_id_cstr); + } + data_sp.reset (new DataBufferHeap (response.GetStringRef().c_str(), + response.GetStringRef().size())); return true; } } @@ -419,7 +448,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) { - if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) + const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); + if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID())) { if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(), data_sp->GetByteSize(), diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 80580f8dddc..26aa4564281 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -554,6 +554,13 @@ ProcessGDBRemote::ConnectToDebugserver (const char *host_port) if (response.IsOKPacket()) m_gdb_comm.SetAckMode (false); } + + if (m_gdb_comm.SendPacketAndWaitForResponse("QThreadSuffixSupported", response, 1, false)) + { + if (response.IsOKPacket()) + m_gdb_comm.SetThreadSuffixSupported (true); + } + } return error; } @@ -2021,7 +2028,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid) return true; char packet[32]; - const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid); + const int packet_len = ::snprintf (packet, sizeof(packet), "Hc%x", tid); assert (packet_len + 1 < sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false)) diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index a4004ea9ee2..e5056326b1c 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -340,6 +340,7 @@ ThreadList::ShouldReportRun (Event *event_ptr) void ThreadList::Clear() { + Mutex::Locker locker(m_threads_mutex); m_stop_id = 0; m_threads.clear(); m_selected_tid = LLDB_INVALID_THREAD_ID; @@ -504,6 +505,7 @@ ThreadList::WillResume () void ThreadList::DidResume () { + Mutex::Locker locker(m_threads_mutex); collection::iterator pos, end = m_threads.end(); for (pos = m_threads.begin(); pos != end; ++pos) { diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h index ed67b926c2a..bb65f707f7d 100644 --- a/lldb/source/Utility/StringExtractor.h +++ b/lldb/source/Utility/StringExtractor.h @@ -113,6 +113,14 @@ public: size_t GetHexByteString (std::string &str); + const char * + Peek () + { + if (m_index < m_packet.size()) + return m_packet.c_str() + m_index; + return NULL; + } + protected: //------------------------------------------------------------------ // For StringExtractor only diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.h b/lldb/tools/debugserver/source/DNBThreadResumeActions.h index f3fb8de6a82..81c7c43b722 100644 --- a/lldb/tools/debugserver/source/DNBThreadResumeActions.h +++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.h @@ -85,6 +85,13 @@ public: { return m_actions.size(); } + + void + Clear() + { + m_actions.clear(); + m_signal_handled.clear(); + } protected: std::vector<DNBThreadResumeAction> m_actions; diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp index 10f86f91225..05298168037 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp @@ -101,6 +101,7 @@ MachProcess::MachProcess() : m_stdio_thread (0), m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE), m_stdout_data (), + m_thread_actions (), m_thread_list (), m_exception_messages (), m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE), @@ -314,7 +315,8 @@ MachProcess::Resume (const DNBThreadResumeActions& thread_actions) if (CanResume(state)) { - PrivateResume(thread_actions); + m_thread_actions = thread_actions; + PrivateResume(); return true; } else if (state == eStateRunning) @@ -337,7 +339,8 @@ MachProcess::Kill (const struct timespec *timeout_abstime) DNBError err; err.SetErrorToErrno(); DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", err.Error(), err.AsString()); - PrivateResume (DNBThreadResumeActions (eStateRunning, 0)); + m_thread_actions = DNBThreadResumeActions (eStateRunning, 0); + PrivateResume (); return true; } @@ -392,7 +395,8 @@ MachProcess::DoSIGSTOP (bool clear_bps_and_wps, uint32_t *thread_idx_ptr) // No threads were stopped with a SIGSTOP, we need to run and halt the // process with a signal DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state)); - PrivateResume (DNBThreadResumeActions (eStateRunning, 0)); + m_thread_actions = DNBThreadResumeActions (eStateRunning, 0); + PrivateResume (); // Reset the event that says we were indeed running m_events.ResetEvents(eEventProcessRunningStateChanged); @@ -428,20 +432,19 @@ MachProcess::Detach() DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state)); { - DNBThreadResumeActions thread_actions; + m_thread_actions.Clear(); DNBThreadResumeAction thread_action; thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx); thread_action.state = eStateRunning; thread_action.signal = -1; thread_action.addr = INVALID_NUB_ADDRESS; - thread_actions.Append (thread_action); - - thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0); + m_thread_actions.Append (thread_action); + m_thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0); PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); - ReplyToAllExceptions (thread_actions); + ReplyToAllExceptions (); } @@ -597,7 +600,7 @@ MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf) void -MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions) +MachProcess::ReplyToAllExceptions () { PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); if (m_exception_messages.empty() == false) @@ -610,13 +613,13 @@ MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions) DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %d...", std::distance(begin, pos)); int thread_reply_signal = 0; - const DNBThreadResumeAction *action = thread_actions.GetActionForThread (pos->state.thread_port, false); + const DNBThreadResumeAction *action = m_thread_actions.GetActionForThread (pos->state.thread_port, false); if (action) { thread_reply_signal = action->signal; if (thread_reply_signal) - thread_actions.SetSignalHandledForThread (pos->state.thread_port); + m_thread_actions.SetSignalHandledForThread (pos->state.thread_port); } DNBError err (pos->Reply(this, thread_reply_signal)); @@ -630,20 +633,20 @@ MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions) } } void -MachProcess::PrivateResume (const DNBThreadResumeActions& thread_actions) +MachProcess::PrivateResume () { PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); - ReplyToAllExceptions (thread_actions); + ReplyToAllExceptions (); // bool stepOverBreakInstruction = step; // Let the thread prepare to resume and see if any threads want us to // step over a breakpoint instruction (ProcessWillResume will modify // the value of stepOverBreakInstruction). - m_thread_list.ProcessWillResume (this, thread_actions); + m_thread_list.ProcessWillResume (this, m_thread_actions); // Set our state accordingly - if (thread_actions.NumActionsWithState(eStateStepping)) + if (m_thread_actions.NumActionsWithState(eStateStepping)) SetState (eStateStepping); else SetState (eStateRunning); @@ -1100,7 +1103,7 @@ MachProcess::ExceptionMessageBundleComplete() else { // Resume without checking our current state. - PrivateResume (DNBThreadResumeActions (eStateRunning, 0)); + PrivateResume (); } } else diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h index 04ad02eb634..8866187b56a 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -17,6 +17,7 @@ #include "DNBDefs.h" #include "DNBBreakpoint.h" #include "DNBError.h" +#include "DNBThreadResumeActions.h" //#include "MachDYLD.h" #include "MachException.h" #include "MachVMMemory.h" @@ -219,8 +220,8 @@ private: eMachProcessFlagsUsingSBS = (1 << 1) }; void Clear (); - void ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions); - void PrivateResume (const DNBThreadResumeActions& thread_actions); + void ReplyToAllExceptions (); + void PrivateResume (); nub_size_t RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const; uint32_t Flags () const { return m_flags; } @@ -239,6 +240,7 @@ private: pthread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio std::string m_stdout_data; + DNBThreadResumeActions m_thread_actions; // The thread actions for the current MachProcess::Resume() call MachException::Message::collection m_exception_messages; // A collection of exception messages caught when listening to the exception port PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp index 7890c069a77..003a58b79d6 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp @@ -339,6 +339,12 @@ MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action) m_stop_exception.Clear(); } +nub_break_t +MachThread::CurrentBreakpoint() +{ + return m_process->Breakpoints().FindIDByAddress(GetPC()); +} + bool MachThread::ShouldStop(bool &step_more) { @@ -394,14 +400,18 @@ MachThread::ShouldStop(bool &step_more) bool MachThread::IsStepping() { +#if ENABLE_AUTO_STEPPING_OVER_BP // Return true if this thread is currently being stepped. // MachThread::ThreadWillResume currently determines this by looking if we // have been asked to single step, or if we are at a breakpoint instruction // and have been asked to resume. In the latter case we need to disable the // breakpoint we are at, single step, re-enable and continue. nub_state_t state = GetState(); - return (state == eStateStepping) || - (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint())); + return ((state == eStateStepping) || + (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint()))); +#else + return GetState() == eStateStepping; +#endif } @@ -430,6 +440,7 @@ MachThread::ThreadDidStop() // Update the basic information for a thread MachThread::GetBasicInfo(m_tid, &m_basicInfo); +#if ENABLE_AUTO_STEPPING_OVER_BP // See if we were at a breakpoint when we last resumed that we disabled, // re-enable it. nub_break_t breakID = CurrentBreakpoint(); @@ -469,10 +480,12 @@ MachThread::ThreadDidStop() SetState(eStateStopped); } } - - - SetCurrentBreakpoint(INVALID_NUB_BREAK_ID); - +#else + if (m_basicInfo.suspend_count > 0) + SetState(eStateSuspended); + else + SetState(eStateStopped); +#endif return true; } @@ -496,30 +509,27 @@ MachThread::NotifyException(MachException::Data& exc) if (!handled) { handled = true; - nub_addr_t pc = GetPC(); - nub_break_t breakID = m_process->Breakpoints().FindIDByAddress(pc); - SetCurrentBreakpoint(breakID); - switch (exc.exc_type) - { - case EXC_BAD_ACCESS: - break; - case EXC_BAD_INSTRUCTION: - break; - case EXC_ARITHMETIC: - break; - case EXC_EMULATION: - break; - case EXC_SOFTWARE: - break; - case EXC_BREAKPOINT: - break; - case EXC_SYSCALL: - break; - case EXC_MACH_SYSCALL: - break; - case EXC_RPC_ALERT: - break; - } +// switch (exc.exc_type) +// { +// case EXC_BAD_ACCESS: +// break; +// case EXC_BAD_INSTRUCTION: +// break; +// case EXC_ARITHMETIC: +// break; +// case EXC_EMULATION: +// break; +// case EXC_SOFTWARE: +// break; +// case EXC_BREAKPOINT: +// break; +// case EXC_SYSCALL: +// break; +// case EXC_MACH_SYSCALL: +// break; +// case EXC_RPC_ALERT: +// break; +// } } return handled; } @@ -658,27 +668,6 @@ MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp) return false; } - -void -MachThread::NotifyBreakpointChanged (const DNBBreakpoint *bp) -{ - nub_break_t breakID = bp->GetID(); - if (bp->IsEnabled()) - { - if (bp->Address() == GetPC()) - { - SetCurrentBreakpoint(breakID); - } - } - else - { - if (CurrentBreakpoint() == breakID) - { - SetCurrentBreakpoint(INVALID_NUB_BREAK_ID); - } - } -} - bool MachThread::GetIdentifierInfo () { diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h index 0b2a8bf1ff9..e7e18fe262c 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h @@ -60,8 +60,7 @@ public: bool SetPC(uint64_t value); // Set program counter uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer - nub_break_t CurrentBreakpoint() const { return m_breakID; } - void SetCurrentBreakpoint(nub_break_t breakID) { m_breakID = breakID; } + nub_break_t CurrentBreakpoint(); uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *breakpoint); uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *watchpoint); bool DisableHardwareBreakpoint (const DNBBreakpoint *breakpoint); @@ -88,7 +87,9 @@ public: bool SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ); nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - void NotifyBreakpointChanged (const DNBBreakpoint *bp); + void NotifyBreakpointChanged (const DNBBreakpoint *bp) + { + } bool IsUserReady(); struct thread_basic_info * diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index 1222b809904..411e91426e1 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -428,8 +428,6 @@ DNBArchImplI386::NotifyException(MachException::Data& exc) // Write the new PC back out SetGPRState (); } - - m_thread->SetCurrentBreakpoint(breakID); } return true; } diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp index fde3be6ab5d..ce0e9c2c579 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp @@ -355,8 +355,6 @@ DNBArchImplX86_64::NotifyException(MachException::Data& exc) // Write the new PC back out SetGPRState (); } - - m_thread->SetCurrentBreakpoint(breakID); } return true; } diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 7fa05073d72..7ce808dbab4 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -76,6 +76,7 @@ RNBRemote::RNBRemote (bool use_native_regs, const char *arch) : m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4), m_extended_mode(false), m_noack_mode(false), + m_thread_suffix_supported (false), m_use_native_regs (use_native_regs) { DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__); @@ -170,12 +171,13 @@ RNBRemote::CreatePacketTable () t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported.")); t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); // t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups")); - t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_Q , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets")); - t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_Q , NULL, "QSetLogging:", "Request that the " DEBUGSERVER_PROGRAM_NAME " set its logging mode bits")); - t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle")); - t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle")); - t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_Q , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment")); - t.push_back (Packet (set_disable_aslr, &RNBRemote::HandlePacket_Q , NULL, "QSetDisableASLR:", "Set wether to disable ASLR when launching the process with the set argv ('A') packet")); + t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets")); + t.push_back (Packet (prefix_reg_packets_with_tid, &RNBRemote::HandlePacket_QThreadSuffixSupported , NULL, "QThreadSuffixSupported", "Check if thread specifc packets (register packets 'g', 'G', 'p', and 'P') support having the thread ID appended to the end of the command")); + t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_QSetLogging , NULL, "QSetLogging:", "Check if register packets ('g', 'G', 'p', and 'P' support having the thread ID prefix")); + t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle")); + t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_QSetMaxPayloadSize , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle")); + t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_QEnvironment , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment")); + t.push_back (Packet (set_disable_aslr, &RNBRemote::HandlePacket_QSetDisableASLR , NULL, "QSetDisableASLR:", "Set wether to disable ASLR when launching the process with the set argv ('A') packet")); // t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior")); t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process.")); t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process.")); @@ -1702,104 +1704,105 @@ set_logging (const char *p) return rnb_success; } - +rnb_err_t +RNBRemote::HandlePacket_QThreadSuffixSupported (const char *p) +{ + m_thread_suffix_supported = true; + return SendPacket ("OK"); +} rnb_err_t -RNBRemote::HandlePacket_Q (const char *p) +RNBRemote::HandlePacket_QStartNoAckMode (const char *p) { - if (p == NULL || strlen (p) <= 1) - { - return HandlePacket_ILLFORMED ("No subtype specified in Q packet"); - } + // Send the OK packet first so the correct checksum is appended... + rnb_err_t result = SendPacket ("OK"); + m_noack_mode = true; + return result; +} - /* Switch to no-ack protocol mode after the "OK" packet is sent - and the ack for that comes back from gdb. */ - if (strcmp (p, "QStartNoAckMode") == 0) - { - rnb_err_t result = SendPacket ("OK"); - m_noack_mode = true; - return result; - } +rnb_err_t +RNBRemote::HandlePacket_QSetLogging (const char *p) +{ + p += sizeof ("QSetLogging:") - 1; + rnb_err_t result = set_logging (p); + if (result == rnb_success) + return SendPacket ("OK"); + else + return SendPacket ("E35"); +} - if (strncmp (p, "QSetLogging:", sizeof ("QSetLogging:") - 1) == 0) +rnb_err_t +RNBRemote::HandlePacket_QSetDisableASLR (const char *p) +{ + extern int g_disable_aslr; + p += sizeof ("QSetDisableASLR:") - 1; + switch (*p) { - p += sizeof ("QSetLogging:") - 1; - rnb_err_t result = set_logging (p); - if (result == rnb_success) - return SendPacket ("OK"); - else - return SendPacket ("E35"); + case '0': g_disable_aslr = 0; break; + case '1': g_disable_aslr = 1; break; + default: + return SendPacket ("E56"); } + return SendPacket ("OK"); +} - if (strncmp (p, "QSetDisableASLR:", sizeof ("QSetDisableASLR:") - 1) == 0) - { - extern int g_disable_aslr; - p += sizeof ("QSetDisableASLR:") - 1; - switch (*p) - { - case '0': g_disable_aslr = 0; break; - case '1': g_disable_aslr = 1; break; - default: - return SendPacket ("E56"); - } - return SendPacket ("OK"); - } +rnb_err_t +RNBRemote::HandlePacket_QSetMaxPayloadSize (const char *p) +{ /* The number of characters in a packet payload that gdb is prepared to accept. The packet-start char, packet-end char, 2 checksum chars and terminating null character are not included in this size. */ - if (strncmp (p, "QSetMaxPayloadSize:", sizeof ("QSetMaxPayloadSize:") - 1) == 0) + p += sizeof ("QSetMaxPayloadSize:") - 1; + errno = 0; + uint32_t size = strtoul (p, NULL, 16); + if (errno != 0 && size == 0) { - p += sizeof ("QSetMaxPayloadSize:") - 1; - errno = 0; - uint32_t size = strtoul (p, NULL, 16); - if (errno != 0 && size == 0) - { - return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPayloadSize packet"); - } - m_max_payload_size = size; - return SendPacket ("OK"); + return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPayloadSize packet"); } + m_max_payload_size = size; + return SendPacket ("OK"); +} +rnb_err_t +RNBRemote::HandlePacket_QSetMaxPacketSize (const char *p) +{ /* This tells us the largest packet that gdb can handle. i.e. the size of gdb's packet-reading buffer. QSetMaxPayloadSize is preferred because it is less ambiguous. */ - - if (strncmp (p, "QSetMaxPacketSize:", sizeof ("QSetMaxPacketSize:") - 1) == 0) + p += sizeof ("QSetMaxPacketSize:") - 1; + errno = 0; + uint32_t size = strtoul (p, NULL, 16); + if (errno != 0 && size == 0) { - p += sizeof ("QSetMaxPacketSize:") - 1; - errno = 0; - uint32_t size = strtoul (p, NULL, 16); - if (errno != 0 && size == 0) - { - return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPacketSize packet"); - } - m_max_payload_size = size - 5; - return SendPacket ("OK"); + return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPacketSize packet"); } + m_max_payload_size = size - 5; + return SendPacket ("OK"); +} + + + +rnb_err_t +RNBRemote::HandlePacket_QEnvironment (const char *p) +{ /* This sets the environment for the target program. The packet is of the form: QEnvironment:VARIABLE=VALUE */ - if (strncmp (p, "QEnvironment:", sizeof ("QEnvironment:") - 1) == 0) - { - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"", - (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p); + DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p); - p += sizeof ("QEnvironment:") - 1; - RNBContext& ctx = Context(); - - ctx.PushEnvironment (p); - return SendPacket ("OK"); - } + p += sizeof ("QEnvironment:") - 1; + RNBContext& ctx = Context(); - // Unrecognized Q packet - return SendPacket (""); + ctx.PushEnvironment (p); + return SendPacket ("OK"); } void @@ -2245,7 +2248,9 @@ RNBRemote::HandlePacket_g (const char *p) InitializeRegisters (); nub_process_t pid = m_ctx.ProcessID (); - nub_thread_t tid = GetCurrentThread(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p + 1); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED ("No thread specified in p packet"); if (m_use_native_regs) { @@ -2291,7 +2296,9 @@ RNBRemote::HandlePacket_G (const char *p) packet.SetFilePos(1); // Skip the 'G' nub_process_t pid = m_ctx.ProcessID(); - nub_thread_t tid = GetCurrentThread(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED ("No thread specified in p packet"); if (m_use_native_regs) { @@ -2870,6 +2877,30 @@ RNBRemote::HandlePacket_z (const char *p) return HandlePacket_UNIMPLEMENTED(p); } +// Extract the thread number from the thread suffix that might be appended to +// thread specific packets. This will only be enabled if m_thread_suffix_supported +// is true. +nub_thread_t +RNBRemote::ExtractThreadIDFromThreadSuffix (const char *p) +{ + if (m_thread_suffix_supported) + { + nub_thread_t tid = INVALID_NUB_THREAD; + if (p) + { + const char *tid_cstr = strstr (p, "thread:"); + if (tid_cstr) + { + tid_cstr += strlen ("thread:"); + tid = strtoul(tid_cstr, NULL, 16); + } + DNBLogThreadedIf (LOG_RNB_PACKETS, "RNBRemote::ExtractThreadIDFromThreadSuffix(%s) got thread 0x%4.4x", p, tid); + } + } + return GetCurrentThread(); + +} + /* `p XX' print the contents of register X */ @@ -2889,12 +2920,17 @@ RNBRemote::HandlePacket_p (const char *p) } nub_process_t pid = m_ctx.ProcessID(); errno = 0; - uint32_t reg = strtoul (p + 1, NULL, 16); + char *tid_cstr = NULL; + uint32_t reg = strtoul (p + 1, &tid_cstr, 16); if (errno != 0 && reg == 0) { - return HandlePacket_ILLFORMED ("Could not parse thread number in p packet"); + return HandlePacket_ILLFORMED ("Could not parse register number in p packet"); } + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (tid_cstr); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED ("No thread specified in p packet"); + const register_map_entry_t *reg_entry; if (reg < g_num_reg_entries) @@ -2925,7 +2961,6 @@ RNBRemote::HandlePacket_p (const char *p) } else { - nub_thread_t tid = GetCurrentThread(); register_value_in_hex_fixed_width (ostrm, pid, tid, reg_entry); } return SendPacket (ostrm.str()); @@ -2985,8 +3020,9 @@ RNBRemote::HandlePacket_P (const char *p) reg_value.info = reg_entry->nub_info; packet.GetHexBytes (reg_value.value.v_sint8, reg_entry->gdb_size, 0xcc); - nub_thread_t tid; - tid = GetCurrentThread (); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED ("No thread specified in p packet"); if (!DNBThreadSetRegisterValueByID (pid, tid, reg_entry->nub_info.set, reg_entry->nub_info.reg, ®_value)) { diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index fab42bc9693..82febf7d226 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -93,6 +93,7 @@ public: query_host_info, // 'qHostInfo' pass_signals_to_inferior, // 'QPassSignals' start_noack_mode, // 'QStartNoAckMode' + prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID set_logging_mode, // 'QSetLogging:' set_max_packet_size, // 'QSetMaxPacketSize:' set_max_payload_size, // 'QSetMaxPayloadSize:' @@ -156,7 +157,14 @@ public: rnb_err_t HandlePacket_qThreadExtraInfo (const char *p); rnb_err_t HandlePacket_qThreadStopInfo (const char *p); rnb_err_t HandlePacket_qHostInfo (const char *p); - rnb_err_t HandlePacket_Q (const char *p); + rnb_err_t HandlePacket_QStartNoAckMode (const char *p); + rnb_err_t HandlePacket_QThreadSuffixSupported (const char *p); + rnb_err_t HandlePacket_QSetLogging (const char *p); + rnb_err_t HandlePacket_QSetDisableASLR (const char *p); + rnb_err_t HandlePacket_QSetMaxPayloadSize (const char *p); + rnb_err_t HandlePacket_QSetMaxPacketSize (const char *p); + rnb_err_t HandlePacket_QEnvironment (const char *p); + rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p); rnb_err_t HandlePacket_last_signal (const char *p); rnb_err_t HandlePacket_m (const char *p); rnb_err_t HandlePacket_M (const char *p); @@ -237,6 +245,9 @@ protected: void CreatePacketTable (); rnb_err_t GetPacketPayload (std::string &); + nub_thread_t + ExtractThreadIDFromThreadSuffix (const char *p); + // gdb can send multiple Z/z packets for the same address and // these calls must be ref counted. struct Breakpoint @@ -286,7 +297,13 @@ protected: uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb bool m_extended_mode:1, // are we in extended mode? m_noack_mode:1, // are we in no-ack mode? - m_use_native_regs:1; // Use native registers by querying DNB layer for register definitions? + m_noack_mode_just_enabled:1, // Did we just enable this and need to compute one more checksum? + m_use_native_regs:1, // Use native registers by querying DNB layer for register definitions? + m_thread_suffix_supported:1; // Set to true if the 'p', 'P', 'g', and 'G' packets should be prefixed with the thread ID and colon: + // "$pRR;thread:TTTT;" instead of "$pRR" + // "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV" + // "$g;thread:TTTT" instead of "$g" + // "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV" }; /* We translate the /usr/include/mach/exception_types.h exception types |