Added a new packet to our GDB remote protocol:

QListThreadsInStopReply
	
This GDB remote query command can enable added a "threads" key/value pair to all stop reply packets so that we always get a list of all threads in each stop reply packet. It increases performance if enabled (the reply to the "QListThreadsInStopReply" is "OK") by saving us from sending to command/reply pairs (the "qfThreadInfo" and "qsThreadInfo" packets), and also helps us keep the current process state up to date. 

llvm-svn: 154380
This commit is contained in:
Greg Clayton 2012-04-10 03:22:03 +00:00
parent 0752624970
commit 4463399b0d
5 changed files with 100 additions and 22 deletions

View File

@ -38,6 +38,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform),
m_supports_not_sending_acks (eLazyBoolCalculate),
m_supports_thread_suffix (eLazyBoolCalculate),
m_supports_threads_in_stop_reply (eLazyBoolCalculate),
m_supports_vCont_all (eLazyBoolCalculate),
m_supports_vCont_any (eLazyBoolCalculate),
m_supports_vCont_c (eLazyBoolCalculate),
@ -113,11 +114,29 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
}
}
void
GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()
{
if (m_supports_threads_in_stop_reply == eLazyBoolCalculate)
{
m_supports_threads_in_stop_reply = eLazyBoolNo;
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false))
{
if (response.IsOKResponse())
m_supports_threads_in_stop_reply = eLazyBoolYes;
}
}
}
void
GDBRemoteCommunicationClient::ResetDiscoverableSettings()
{
m_supports_not_sending_acks = eLazyBoolCalculate;
m_supports_thread_suffix = eLazyBoolCalculate;
m_supports_threads_in_stop_reply = eLazyBoolCalculate;
m_supports_vCont_c = eLazyBoolCalculate;
m_supports_vCont_C = eLazyBoolCalculate;
m_supports_vCont_s = eLazyBoolCalculate;

View File

@ -71,6 +71,9 @@ public:
void
QueryNoAckModeSupported ();
void
GetListThreadsInStopReplySupported ();
bool
SendAsyncSignal (int signo);
@ -335,6 +338,7 @@ protected:
//------------------------------------------------------------------
lldb_private::LazyBool m_supports_not_sending_acks;
lldb_private::LazyBool m_supports_thread_suffix;
lldb_private::LazyBool m_supports_threads_in_stop_reply;
lldb_private::LazyBool m_supports_vCont_all;
lldb_private::LazyBool m_supports_vCont_any;
lldb_private::LazyBool m_supports_vCont_c;

View File

@ -704,6 +704,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
m_gdb_comm.ResetDiscoverableSettings();
m_gdb_comm.QueryNoAckModeSupported ();
m_gdb_comm.GetThreadSuffixSupported ();
m_gdb_comm.GetListThreadsInStopReplySupported ();
m_gdb_comm.GetHostInfo ();
m_gdb_comm.GetVContSupported ('c');
return error;
@ -1262,8 +1263,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
{
Mutex::Locker locker(m_thread_ids_mutex);
m_thread_ids.clear();
// A comma separated list of all threads in the current process including
// the thread for this stop reply packet
// A comma separated list of all threads in the current
// process that includes the thread for this stop reply
// packet
size_t comma_pos;
lldb::tid_t tid;
while ((comma_pos = value.find(',')) != std::string::npos)

View File

@ -76,8 +76,9 @@ RNBRemote::RNBRemote () :
m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4),
m_extended_mode(false),
m_noack_mode(false),
m_use_native_regs (false),
m_thread_suffix_supported (false),
m_use_native_regs (false)
m_list_threads_in_stop_reply (false)
{
DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);
CreatePacketTable ();
@ -183,6 +184,7 @@ RNBRemote::CreatePacketTable ()
t.push_back (Packet (set_stdout, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDOUT:", "Set the standard output for a process to be launched with the 'A' packet"));
t.push_back (Packet (set_stderr, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDERR:", "Set the standard error for a process to be launched with the 'A' packet"));
t.push_back (Packet (set_working_dir, &RNBRemote::HandlePacket_QSetWorkingDir , NULL, "QSetWorkingDir:", "Set the working directory for a process to be launched with the 'A' packet"));
t.push_back (Packet (set_list_threads_in_stop_reply,&RNBRemote::HandlePacket_QListThreadsInStopReply , NULL, "QListThreadsInStopReply", "Set if the 'threads' key should be added to the stop reply packets with a list of all thread IDs."));
// 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."));
@ -1128,12 +1130,12 @@ RNBRemote::NotifyThatProcessStopped (void)
}
/* `A arglen,argnum,arg,...'
/* 'A arglen,argnum,arg,...'
Update the inferior context CTX with the program name and arg
list.
The documentation for this packet is underwhelming but my best reading
of this is that it is a series of (len, position #, arg)'s, one for
each argument with "arg" ``hex encoded'' (two 0-9a-f chars?).
each argument with "arg" hex encoded (two 0-9a-f chars?).
Why we need BOTH a "len" and a hex encoded "arg" is beyond me - either
is sufficient to get around the "," position separator escape issue.
@ -1223,7 +1225,7 @@ RNBRemote::HandlePacket_A (const char *p)
return rnb_success;
}
/* `H c t'
/* 'H c t'
Set the thread for subsequent actions; 'c' for step/continue ops,
'g' for other ops. -1 means all threads, 0 means any thread. */
@ -1868,6 +1870,28 @@ RNBRemote::HandlePacket_QSetWorkingDir (const char *p)
return SendPacket ("E60"); // Already had a process, too late to set working dir
}
rnb_err_t
RNBRemote::HandlePacket_QListThreadsInStopReply (const char *p)
{
// If this packet is received, it allows us to send an extra key/value
// pair in the stop reply packets where we will list all of the thread IDs
// separated by commas:
//
// "threads:10a,10b,10c;"
//
// This will get included in the stop reply packet as something like:
//
// "T11thread:10a;00:00000000;01:00010203:threads:10a,10b,10c;"
//
// This can save two packets on each stop: qfThreadInfo/qsThreadInfo and
// speed things up a bit.
//
// Send the OK packet first so the correct checksum is appended...
rnb_err_t result = SendPacket ("OK");
m_list_threads_in_stop_reply = true;
return result;
}
rnb_err_t
RNBRemote::HandlePacket_QSetMaxPayloadSize (const char *p)
@ -2118,6 +2142,33 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
if (thread_ident_info.dispatch_qaddr != 0)
ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';';
}
// If a 'QListThreadsInStopReply' was sent to enable this feature, we
// will send all thread IDs back in the "threads" key whose value is
// a listc of hex thread IDs separated by commas:
// "threads:10a,10b,10c;"
// This will save the debugger from having to send a pair of qfThreadInfo
// and qsThreadInfo packets, but it also might take a lot of room in the
// stop reply packet, so it must be enabled only on systems where there
// are no limits on packet lengths.
if (m_list_threads_in_stop_reply)
{
const nub_size_t numthreads = DNBProcessGetNumThreads (pid);
if (numthreads > 0)
{
ostrm << std::hex << "threads:";
for (nub_size_t i = 0; i < numthreads; ++i)
{
nub_thread_t th = DNBProcessGetThreadAtIndex (pid, i);
if (i > 0)
ostrm << ',';
ostrm << std::hex << th;
}
ostrm << ';';
}
}
if (g_num_reg_entries == 0)
InitializeRegisters ();
@ -2145,7 +2196,7 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
return SendPacket("E51");
}
/* `?'
/* '?'
The stop reply packet - tell gdb what the status of the inferior is.
Often called the questionmark_packet. */
@ -2401,7 +2452,7 @@ RNBRemote::HandlePacket_X (const char *p)
return SendPacket ("OK");
}
/* `g' -- read registers
/* 'g' -- read registers
Get the contents of the registers for the current thread,
send them to gdb.
Should the setting of the Hg packet determine which thread's registers
@ -2449,7 +2500,7 @@ RNBRemote::HandlePacket_g (const char *p)
return SendPacket (ostrm.str ());
}
/* `G XXX...' -- write registers
/* 'G XXX...' -- write registers
How is the thread for these specified, beyond "the current thread"?
Does gdb actually use the Hg packet to set this? */
@ -2809,7 +2860,7 @@ RNBRemote::HandlePacket_v (const char *p)
return HandlePacket_UNIMPLEMENTED(p);
}
/* `T XX' -- status of thread
/* 'T XX' -- status of thread
Check if the specified thread is alive.
The thread number is in hex? */
@ -3082,7 +3133,7 @@ RNBRemote::ExtractThreadIDFromThreadSuffix (const char *p)
}
/* `p XX'
/* 'p XX'
print the contents of register X */
rnb_err_t
@ -3147,7 +3198,7 @@ RNBRemote::HandlePacket_p (const char *p)
return SendPacket (ostrm.str());
}
/* `Pnn=rrrrr'
/* 'Pnn=rrrrr'
Set register number n to value r.
n and r are hex strings. */
@ -3212,7 +3263,7 @@ RNBRemote::HandlePacket_P (const char *p)
return SendPacket ("OK");
}
/* `c [addr]'
/* 'c [addr]'
Continue, optionally from a specified address. */
rnb_err_t
@ -3311,7 +3362,7 @@ RNBRemote::HandlePacket_MemoryRegionInfo (const char *p)
}
/* `C sig [;addr]'
/* 'C sig [;addr]'
Resume with signal sig, optionally at address addr. */
rnb_err_t
@ -3365,7 +3416,7 @@ RNBRemote::HandlePacket_D (const char *p)
return rnb_success;
}
/* `k'
/* 'k'
Kill the inferior process. */
rnb_err_t
@ -3387,7 +3438,7 @@ RNBRemote::HandlePacket_stop_process (const char *p)
return rnb_success;
}
/* `s'
/* 's'
Step the inferior process. */
rnb_err_t
@ -3416,7 +3467,7 @@ RNBRemote::HandlePacket_s (const char *p)
return rnb_success;
}
/* `S sig [;addr]'
/* 'S sig [;addr]'
Step with signal sig, optionally at address addr. */
rnb_err_t

View File

@ -106,6 +106,7 @@ public:
set_stdout, // 'QSetSTDOUT:'
set_stderr, // 'QSetSTDERR:'
set_working_dir, // 'QSetWorkingDir:'
set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:'
memory_region_info, // 'qMemoryRegionInfo:'
allocate_memory, // '_M'
deallocate_memory, // '_m'
@ -177,6 +178,7 @@ public:
rnb_err_t HandlePacket_QEnvironment (const char *p);
rnb_err_t HandlePacket_QEnvironmentHexEncoded (const char *p);
rnb_err_t HandlePacket_QLaunchArch (const char *p);
rnb_err_t HandlePacket_QListThreadsInStopReply (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);
@ -328,15 +330,15 @@ protected:
BreakpointMap m_breakpoints;
BreakpointMap m_watchpoints;
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_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:
bool m_extended_mode; // are we in extended mode?
bool m_noack_mode; // are we in no-ack mode?
bool m_use_native_regs; // Use native registers by querying DNB layer for register definitions?
bool m_thread_suffix_supported; // 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"
bool m_list_threads_in_stop_reply;
};
/* We translate the /usr/include/mach/exception_types.h exception types