Added the ability to get JSON thread stop info with thread ID and stop info only in the normal stop reply packets using the new "jthreads" key value pair.

This allows stepping operations that don't ever do a public stop to get all the info they need without having to send a jThreadsInfo packet since those tend to be large.

This patch will be followed by a patch that will detect when we do a public stop, and when that happens we will send a jThreadsInfo packet at that time to get all expedited registers and memory.

llvm-svn: 242352
This commit is contained in:
Greg Clayton 2015-07-15 22:59:03 +00:00
parent d3ec7c3a51
commit a5801ade5a
3 changed files with 124 additions and 62 deletions

View File

@ -2341,6 +2341,18 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
if (tid != LLDB_INVALID_THREAD_ID)
m_thread_ids.push_back (tid);
}
else if (key.compare("jthreads") == 0)
{
StringExtractor json_extractor;
// Swap "value" over into "name_extractor"
json_extractor.GetStringRef().swap(value);
// Now convert the HEX bytes into a string value
json_extractor.GetHexByteString (value);
// This JSON contains thread IDs and thread stop info for all threads.
// It doesn't contain expedited registers, memory or queue info.
m_threads_info_sp = StructuredData::ParseJSON (value);
}
else if (key.compare("hexname") == 0)
{
StringExtractor name_extractor;

View File

@ -265,7 +265,7 @@ RNBRemote::CreatePacketTable ()
t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_qSymbol , NULL, "qSymbol:", "Notify that host debugger is ready to do symbol lookups"));
t.push_back (Packet (json_query_thread_extended_info,&RNBRemote::HandlePacket_jThreadExtendedInfo , NULL, "jThreadExtendedInfo", "Replies with JSON data of thread extended information."));
t.push_back (Packet (json_query_get_loaded_dynamic_libraries_infos, &RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos, NULL, "jGetLoadedDynamicLibrariesInfos", "Replies with JSON data of all the shared libraries loaded in this process."));
//t.push_back (Packet (json_query_threads_info, &RNBRemote::HandlePacket_jThreadsInfo , NULL, "jThreadsInfo", "Replies with JSON data with information about all threads."));
t.push_back (Packet (json_query_threads_info, &RNBRemote::HandlePacket_jThreadsInfo , NULL, "jThreadsInfo", "Replies with JSON data with information about all threads."));
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 specific 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"));
@ -2304,6 +2304,7 @@ RNBRemote::HandlePacket_QListThreadsInStopReply (const char *p)
// 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;
}
@ -2719,7 +2720,6 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
// 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);
@ -2735,7 +2735,25 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
}
ostrm << ';';
}
// Include JSON info that describes the stop reason for all threads
// so when stepping we don't have to query each thread for its stop
// info. We use the new "jthreads" key whose values is hex ascii JSON
// that contains the thread IDs and only the stop info.
const bool queue_info = false;
const bool registers = false;
const bool memory = false;
JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(queue_info, registers, memory);
if (threads_info_sp)
{
ostrm << std::hex << "jthreads:";
std::ostringstream json_strm;
threads_info_sp->Dump (json_strm);
append_hexified_string (ostrm, json_strm.str());
ostrm << ';';
}
}
if (g_num_reg_entries == 0)
InitializeRegisters ();
@ -4962,16 +4980,14 @@ get_integer_value_for_key_name_from_json (const char *key, const char *json_stri
}
rnb_err_t
RNBRemote::HandlePacket_jThreadsInfo (const char *p)
JSONGenerator::ObjectSP
RNBRemote::GetJSONThreadsInfo(bool queue_info, bool registers, bool memory)
{
JSONGenerator::Array threads_array;
std::ostringstream json;
std::ostringstream reply_strm;
// If we haven't run the process yet, return an error.
JSONGenerator::ArraySP threads_array_sp;
if (m_ctx.HasValidProcessID())
{
threads_array_sp.reset(new JSONGenerator::Array());
nub_process_t pid = m_ctx.ProcessID();
nub_size_t numthreads = DNBProcessGetNumThreads (pid);
@ -5027,6 +5043,8 @@ RNBRemote::HandlePacket_jThreadsInfo (const char *p)
thread_dict_sp->AddStringItem("name", thread_name);
if (queue_info)
{
thread_identifier_info_data_t thread_ident_info;
if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
{
@ -5052,6 +5070,10 @@ RNBRemote::HandlePacket_jThreadsInfo (const char *p)
}
}
}
}
if (registers)
{
DNBRegisterValue reg_value;
if (g_reg_entries != NULL)
@ -5076,7 +5098,10 @@ RNBRemote::HandlePacket_jThreadsInfo (const char *p)
}
thread_dict_sp->AddItem("registers", registers_dict_sp);
}
}
if (memory)
{
// Add expedited stack memory so stack backtracing doesn't need to read anything from the
// frame pointer chain.
StackMemoryMap stack_mmap;
@ -5094,15 +5119,37 @@ RNBRemote::HandlePacket_jThreadsInfo (const char *p)
}
thread_dict_sp->AddItem("memory", memory_array_sp);
}
threads_array.AddItem(thread_dict_sp);
}
threads_array_sp->AddItem(thread_dict_sp);
}
}
return threads_array_sp;
}
rnb_err_t
RNBRemote::HandlePacket_jThreadsInfo (const char *p)
{
JSONGenerator::ObjectSP threads_info_sp;
std::ostringstream json;
std::ostringstream reply_strm;
// If we haven't run the process yet, return an error.
if (m_ctx.HasValidProcessID())
{
const bool queue_info = true;
const bool registers = true;
const bool memory = true;
JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(queue_info, registers, memory);
if (threads_info_sp)
{
std::ostringstream strm;
threads_array.Dump (strm);
threads_info_sp->Dump (strm);
std::string binary_packet = binary_encode_string (strm.str());
if (!binary_packet.empty())
return SendPacket (binary_packet.c_str());
}
}
return SendPacket ("E85");
}

View File

@ -397,6 +397,9 @@ protected:
const DispatchQueueOffsets *
GetDispatchQueueOffsets();
JSONGenerator::ObjectSP
GetJSONThreadsInfo (bool queue_info, bool registers, bool memory);
RNBContext m_ctx; // process context
RNBSocket m_comm; // communication port
std::string m_arch;