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
This commit is contained in:
Greg Clayton 2011-01-18 19:36:39 +00:00
parent 4dc73fa075
commit c4e411ffc0
17 changed files with 305 additions and 176 deletions

View File

@ -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)
{

View File

@ -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();

View File

@ -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),

View File

@ -99,6 +99,18 @@ public:
m_send_acks = enabled;
}
bool
GetThreadSuffixSupported () const
{
return m_thread_suffix_supported;
}
void
SetThreadSuffixSupported (bool enabled)
{
m_thread_suffix_supported = enabled;
}
bool
SendAsyncSignal (int signo);
@ -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;

View File

@ -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(),

View File

@ -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))

View File

@ -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)
{

View File

@ -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

View File

@ -85,6 +85,13 @@ public:
{
return m_actions.size();
}
void
Clear()
{
m_actions.clear();
m_signal_handled.clear();
}
protected:
std::vector<DNBThreadResumeAction> m_actions;

View File

@ -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

View File

@ -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

View File

@ -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 ()
{

View File

@ -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 *

View File

@ -428,8 +428,6 @@ DNBArchImplI386::NotifyException(MachException::Data& exc)
// Write the new PC back out
SetGPRState ();
}
m_thread->SetCurrentBreakpoint(breakID);
}
return true;
}

View File

@ -355,8 +355,6 @@ DNBArchImplX86_64::NotifyException(MachException::Data& exc)
// Write the new PC back out
SetGPRState ();
}
m_thread->SetCurrentBreakpoint(breakID);
}
return true;
}

View File

@ -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_QStartNoAckMode (const char *p)
{
// Send the OK packet first so the correct checksum is appended...
rnb_err_t result = SendPacket ("OK");
m_noack_mode = true;
return result;
}
rnb_err_t
RNBRemote::HandlePacket_Q (const char *p)
RNBRemote::HandlePacket_QSetLogging (const char *p)
{
if (p == NULL || strlen (p) <= 1)
{
return HandlePacket_ILLFORMED ("No subtype specified in Q packet");
}
/* 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;
}
if (strncmp (p, "QSetLogging:", sizeof ("QSetLogging:") - 1) == 0)
{
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, "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");
}
p += sizeof ("QSetLogging:") - 1;
rnb_err_t result = set_logging (p);
if (result == rnb_success)
return SendPacket ("OK");
}
else
return SendPacket ("E35");
}
rnb_err_t
RNBRemote::HandlePacket_QSetDisableASLR (const char *p)
{
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();
p += sizeof ("QEnvironment:") - 1;
RNBContext& ctx = Context();
ctx.PushEnvironment (p);
return SendPacket ("OK");
}
// 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, &reg_value))
{

View File

@ -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