diff options
author | Greg Clayton <gclayton@apple.com> | 2011-01-18 19:36:39 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2011-01-18 19:36:39 +0000 |
commit | c4e411ffc09a77abe9957f83827fc1745d7e0408 (patch) | |
tree | 78a1107cecd93fdb0cda97b735d5ff23751f2c4a | |
parent | 4dc73fa075db86bc6a07d755d972e9f8ad7336cc (diff) | |
download | bcm5719-llvm-c4e411ffc09a77abe9957f83827fc1745d7e0408.tar.gz bcm5719-llvm-c4e411ffc09a77abe9957f83827fc1745d7e0408.zip |
Thread safety changes in debugserver and also in the process GDB remote plugin.
I added support for asking if the GDB remote server supports thread suffixes
for packets that should be thread specific (register read/write packets) because
the way the GDB remote protocol does it right now is to have a notion of a
current thread for register and memory reads/writes (set via the "$Hg%x" packet)
and a current thread for running ("$Hc%x"). Now we ask the remote GDB server
if it supports adding the thread ID to the register packets and we enable
that feature in LLDB if supported. This stops us from having to send a bunch
of packets that update the current thread ID to some value which is prone to
error, or extra packets.
llvm-svn: 123762
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 |