diff options
author | Greg Clayton <gclayton@apple.com> | 2015-06-23 21:27:50 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2015-06-23 21:27:50 +0000 |
commit | 0b90be1c4f151dd3f8eda2a291a68554e67a3742 (patch) | |
tree | d69bddb32f34798f9d99cb97c2c1d0dcd7dbdc1c /lldb/source/Plugins | |
parent | a0d5c5924af5ede48b367723874a0efb7993d041 (diff) | |
download | bcm5719-llvm-0b90be1c4f151dd3f8eda2a291a68554e67a3742.tar.gz bcm5719-llvm-0b90be1c4f151dd3f8eda2a291a68554e67a3742.zip |
Implement the "qSymbol" packet in order to be able to read queue information in debugserver and return the info in the stop reply packets.
A "qSymbol::" is sent when shared libraries have been loaded by hooking into the Process::ModulesDidLoad() function from within ProcessGDBRemote. This function was made virtual so that the ProcessGDBRemote version is called, which then first calls the Process::ModulesDidLoad(), and then it queries for any symbol lookups that the remote GDB server might want to do.
This allows debugserver to request the "dispatch_queue_offsets" symbol so that it can read the queue name, queue kind and queue serial number and include this data as part of the stop reply packet. Previously each thread would have to do 3 memory reads in order to read the queue name.
This is part of reducing the number of packets that are sent between LLDB and the remote GDB server.
<rdar://problem/21494354>
llvm-svn: 240466
Diffstat (limited to 'lldb/source/Plugins')
6 files changed, 194 insertions, 9 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index fe88de4c866..f487ae94192 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -33,6 +33,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Target/Target.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/UnixSignals.h" @@ -98,6 +99,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : m_supports_z4 (true), m_supports_QEnvironment (true), m_supports_QEnvironmentHexEncoded (true), + m_supports_qSymbol (true), m_curr_pid (LLDB_INVALID_PROCESS_ID), m_curr_tid (LLDB_INVALID_THREAD_ID), m_curr_tid_run (LLDB_INVALID_THREAD_ID), @@ -370,6 +372,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; + m_supports_qSymbol = true; m_host_arch.Clear(); m_process_arch.Clear(); @@ -4241,3 +4244,87 @@ GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString ob err.Success( ); return true; } + +// Notify the target that gdb is prepared to serve symbol lookup requests. +// packet: "qSymbol::" +// reply: +// OK The target does not need to look up any (more) symbols. +// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded). +// LLDB may provide the value by sending another qSymbol packet +// in the form of"qSymbol:<sym_value>:<sym_name>". + +void +GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) +{ + if (m_supports_qSymbol) + { + Mutex::Locker locker; + if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) + { + StreamString packet; + packet.PutCString ("qSymbol::"); + while (1) + { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + // We are done serving symbols requests + return; + } + + if (response.IsUnsupportedResponse()) + { + // qSymbol is not supported by the current GDB server we are connected to + m_supports_qSymbol = false; + return; + } + else + { + llvm::StringRef response_str(response.GetStringRef()); + if (response_str.startswith("qSymbol:")) + { + response.SetFilePos(strlen("qSymbol:")); + std::string symbol_name; + if (response.GetHexByteString(symbol_name)) + { + if (symbol_name.empty()) + return; + + addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; + lldb_private::SymbolContextList sc_list; + if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) + { + if (sc.symbol) + symbol_load_addr = sc.symbol->GetAddress().GetLoadAddress(&process->GetTarget()); + } + } + // This is the normal path where our symbol lookup was successful and we want + // to send a packet with the new symbol value and see if another lookup needs to be + // done. + + // Change "packet" to contain the requested symbol value and name + packet.Clear(); + packet.PutCString("qSymbol:"); + if (symbol_load_addr != LLDB_INVALID_ADDRESS) + packet.Printf("%" PRIx64, symbol_load_addr); + packet.PutCString(":"); + packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); + continue; // go back to the while loop and send "packet" and wait for another response + } + } + } + } + } + // If we make it here, the symbol request packet response wasn't valid or + // our symbol lookup failed so we must abort + return; + + } + } +} + diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 3e5d954c8af..07a3bd93321 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -556,6 +556,9 @@ public: std::string & out, lldb_private::Error & err); + void + ServeSymbolLookups(lldb_private::Process *process); + protected: PacketResult @@ -620,7 +623,8 @@ protected: m_supports_z3:1, m_supports_z4:1, m_supports_QEnvironment:1, - m_supports_QEnvironmentHexEncoded:1; + m_supports_QEnvironmentHexEncoded:1, + m_supports_qSymbol:1; lldb::pid_t m_curr_pid; lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index d41bdc70681..c1ad2e69754 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1834,6 +1834,10 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) uint32_t exc_type = 0; std::vector<addr_t> exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; + bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid + std::string queue_name; + QueueKind queue_kind = eQueueKindUnknown; + uint64_t queue_serial = 0; ThreadSP thread_sp; ThreadGDBRemote *gdb_thread = NULL; @@ -1914,6 +1918,29 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) { thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16); } + else if (name.compare("qname") == 0) + { + queue_vars_valid = true; + StringExtractor name_extractor; + // Swap "value" over into "name_extractor" + name_extractor.GetStringRef().swap(value); + // Now convert the HEX bytes into a string value + name_extractor.GetHexByteString (value); + queue_name.swap (value); + } + else if (name.compare("qkind") == 0) + { + queue_vars_valid = true; + if (value == "serial") + queue_kind = eQueueKindSerial; + else if (value == "concurrent") + queue_kind = eQueueKindConcurrent; + } + else if (name.compare("qserial") == 0) + { + queue_vars_valid = true; + queue_serial = StringConvert::ToUInt64 (value.c_str(), 0, 0); + } else if (name.compare("reason") == 0) { reason.swap(value); @@ -1976,6 +2003,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) thread_sp->SetStopInfo (StopInfoSP()); gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); + if (queue_vars_valid) + gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial); + else + gdb_thread->ClearQueueInfo(); + gdb_thread->SetName (thread_name.empty() ? NULL : thread_name.c_str()); if (exc_type != 0) { @@ -4236,6 +4268,19 @@ ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb return Error("Unknown error happened during sending the load address packet"); } + +void +ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list) +{ + // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything + Process::ModulesDidLoad (module_list); + + // After loading shared libraries, we can ask our remote GDB server if + // it needs any symbols. + m_gdb_comm.ServeSymbolLookups(this); +} + + class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed { public: diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 174d9e7501f..16e47dfcba6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -244,6 +244,9 @@ public: Error GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override; + void + ModulesDidLoad (ModuleList &module_list) override; + protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index e4108edc03f..e58121b1978 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -40,9 +40,11 @@ ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) : Thread(process, tid), m_thread_name (), m_dispatch_queue_name (), - m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS) + m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS), + m_queue_kind(eQueueKindUnknown), + m_queue_serial(0) { - ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", + ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this, process.GetID(), GetID()); @@ -66,10 +68,36 @@ ThreadGDBRemote::GetName () return m_thread_name.c_str(); } +void +ThreadGDBRemote::ClearQueueInfo () +{ + m_dispatch_queue_name.clear(); + m_queue_kind = eQueueKindUnknown; + m_queue_serial = 0; +} + +void +ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial) +{ + m_dispatch_queue_name = queue_name; + m_queue_kind = queue_kind; + m_queue_serial = queue_serial; +} + const char * ThreadGDBRemote::GetQueueName () { + // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) + { + if (m_dispatch_queue_name.empty()) + return nullptr; + else + return m_dispatch_queue_name.c_str(); + } // Always re-fetch the dispatch queue name since it can change if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) @@ -79,13 +107,12 @@ ThreadGDBRemote::GetQueueName () { SystemRuntime *runtime = process_sp->GetSystemRuntime (); if (runtime) - { m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr); - } - if (m_dispatch_queue_name.length() > 0) - { + else + m_dispatch_queue_name.clear(); + + if (!m_dispatch_queue_name.empty()) return m_dispatch_queue_name.c_str(); - } } } return NULL; @@ -94,6 +121,12 @@ ThreadGDBRemote::GetQueueName () queue_id_t ThreadGDBRemote::GetQueueID () { + // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...) + // with valid information that was gleaned from the stop reply packet. In this case we trust + // that the info is valid in m_dispatch_queue_name without refetching it + if (CachedQueueInfoIsValid()) + return m_queue_serial; + if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) { ProcessSP process_sp (GetProcess()); diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 8bff54456dc..175433a3e20 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -91,6 +91,12 @@ public: m_thread_dispatch_qaddr = thread_dispatch_qaddr; } + void + ClearQueueInfo (); + + void + SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial); + StructuredData::ObjectSP FetchThreadExtendedInfo () override; @@ -101,13 +107,20 @@ protected: bool PrivateSetRegisterValue (uint32_t reg, StringExtractor &response); - + + bool + CachedQueueInfoIsValid() const + { + return m_queue_kind != lldb::eQueueKindUnknown; + } //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ std::string m_thread_name; std::string m_dispatch_queue_name; lldb::addr_t m_thread_dispatch_qaddr; + lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread + uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ |