summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Target/Process.h8
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp87
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h6
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp45
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h3
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp47
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h15
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp80
-rw-r--r--lldb/tools/debugserver/source/DNB.h4
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp238
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h71
11 files changed, 583 insertions, 21 deletions
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 075a3fe4628..db0f0cfa028 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1878,7 +1878,13 @@ public:
void
SendAsyncInterrupt ();
- void
+ //------------------------------------------------------------------
+ // Notify this process class that modules got loaded.
+ //
+ // If subclasses override this method, they must call this version
+ // before doing anything in the subclass version of the function.
+ //------------------------------------------------------------------
+ virtual void
ModulesDidLoad (ModuleList &module_list);
protected:
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.
//------------------------------------------------------------------
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index 4d773221a45..4cde3f87b08 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -1257,6 +1257,86 @@ DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void
return 0;
}
+uint64_t
+DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value)
+{
+ union Integers
+ {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ };
+
+ if (integer_size <= sizeof(uint64_t))
+ {
+ Integers ints;
+ if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size)
+ {
+ switch (integer_size)
+ {
+ case 1: return ints.u8;
+ case 2: return ints.u16;
+ case 3: return ints.u32 & 0xffffffu;
+ case 4: return ints.u32;
+ case 5: return ints.u32 & 0x000000ffffffffffull;
+ case 6: return ints.u32 & 0x0000ffffffffffffull;
+ case 7: return ints.u32 & 0x00ffffffffffffffull;
+ case 8: return ints.u64;
+ }
+ }
+ }
+ return fail_value;
+
+}
+
+nub_addr_t
+DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr)
+{
+ cpu_type_t cputype = DNBProcessGetCPUType (pid);
+ if (cputype)
+ {
+ const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
+ return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
+ }
+ return 0;
+
+}
+
+std::string
+DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr)
+{
+ std::string cstr;
+ char buffer[256];
+ const nub_size_t max_buffer_cstr_length = sizeof(buffer)-1;
+ buffer[max_buffer_cstr_length] = '\0';
+ nub_size_t length = 0;
+ nub_addr_t curr_addr = addr;
+ do
+ {
+ nub_size_t bytes_read = DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
+ if (bytes_read == 0)
+ break;
+ length = strlen(buffer);
+ cstr.append(buffer, length);
+ curr_addr += length;
+ } while (length == max_buffer_cstr_length);
+ return cstr;
+}
+
+std::string
+DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length)
+{
+ std::string cstr;
+ char buffer[fixed_length+1];
+ buffer[fixed_length] = '\0';
+ nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
+ if (bytes_read > 0)
+ cstr.assign(buffer);
+ return cstr;
+}
+
+
//----------------------------------------------------------------------
// Write memory to the address space of process PID. This call will take
// care of setting and restoring permissions and breaking up the memory
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index e57bb08b678..3f032798f23 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -69,6 +69,10 @@ nub_bool_t DNBProcessInterrupt (nub_process_t pid) DNB_EXPORT;
nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT;
nub_bool_t DNBProcessSendEvent (nub_process_t pid, const char *event) DNB_EXPORT;
nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT;
+uint64_t DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value) DNB_EXPORT;
+nub_addr_t DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
+std::string DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
+std::string DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length) DNB_EXPORT;
nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT;
nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT;
nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 2385246a200..1ddf9027427 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -74,14 +74,81 @@
#define INDENT_WITH_TABS(iword_idx) std::setfill('\t') << std::setw((iword_idx)) << ""
// Class to handle communications via gdb remote protocol.
+
+//----------------------------------------------------------------------
+// Decode a single hex character and return the hex value as a number or
+// -1 if "ch" is not a hex character.
+//----------------------------------------------------------------------
+static inline int
+xdigit_to_sint (char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ if (ch >= 'A' && ch <= 'F')
+ return 10 + ch - 'A';
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// Decode a single hex ASCII byte. Return -1 on failure, a value 0-255
+// on success.
+//----------------------------------------------------------------------
+static inline int
+decoded_hex_ascii_char(const char *p)
+{
+ const int hi_nibble = xdigit_to_sint(p[0]);
+ if (hi_nibble == -1)
+ return -1;
+ const int lo_nibble = xdigit_to_sint(p[1]);
+ if (lo_nibble == -1)
+ return -1;
+ return (uint8_t)((hi_nibble << 4) + lo_nibble);
+}
+
+//----------------------------------------------------------------------
+// Decode a hex ASCII string back into a string
+//----------------------------------------------------------------------
+static std::string
+decode_hex_ascii_string(const char *p, uint32_t max_length = UINT32_MAX)
+{
+ std::string arg;
+ if (p)
+ {
+ for (const char *c = p; ((c - p)/2) < max_length; c += 2)
+ {
+ int ch = decoded_hex_ascii_char(c);
+ if (ch == -1)
+ break;
+ else
+ arg.push_back(ch);
+ }
+ }
+ return arg;
+}
+
+uint64_t
+decode_uint64 (const char *p, int base, char **end = nullptr, uint64_t fail_value = 0)
+{
+ nub_addr_t addr = strtoull (p, end, 16);
+ if (addr == 0 && errno != 0)
+ return fail_value;
+ return addr;
+}
+
extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args);
RNBRemote::RNBRemote () :
m_ctx (),
m_comm (),
+ m_arch (),
m_continue_thread(-1),
m_thread(-1),
m_mutex(),
+ m_dispatch_queue_offsets (),
+ m_dispatch_queue_offsets_addr (INVALID_NUB_ADDRESS),
+ m_qSymbol_index (UINT32_MAX),
m_packets_recvd(0),
m_packets(),
m_rx_packets(),
@@ -190,11 +257,11 @@ 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_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported."));
t.push_back (Packet (query_sync_thread_state_supported, &RNBRemote::HandlePacket_qSyncThreadStateSupported,NULL, "qSyncThreadStateSupported", "Replys with OK if the 'QSyncThreadState:' 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_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion, NULL, "qGDBServerVersion", "Replies with multiple 'key:value;' tuples appended to each other."));
- t.push_back (Packet (query_process_info, &RNBRemote::HandlePacket_qProcessInfo, NULL, "qProcessInfo", "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 (json_query_thread_extended_info, &RNBRemote::HandlePacket_jThreadExtendedInfo, NULL, "jThreadExtendedInfo", "Replies with JSON data of thread extended information."));
+ 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_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion , NULL, "qGDBServerVersion", "Replies with multiple 'key:value;' tuples appended to each other."));
+ t.push_back (Packet (query_process_info, &RNBRemote::HandlePacket_qProcessInfo , NULL, "qProcessInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
+ 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 (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"));
@@ -2371,18 +2438,19 @@ RNBRemote::HandlePacket_QSetProcessEvent (const char *p)
}
void
-append_hex_value (std::ostream& ostrm, const uint8_t* buf, size_t buf_size, bool swap)
+append_hex_value (std::ostream& ostrm, const void *buf, size_t buf_size, bool swap)
{
int i;
+ const uint8_t *p = (const uint8_t *)buf;
if (swap)
{
for (i = static_cast<int>(buf_size)-1; i >= 0; i--)
- ostrm << RAWHEX8(buf[i]);
+ ostrm << RAWHEX8(p[i]);
}
else
{
for (i = 0; i < buf_size; i++)
- ostrm << RAWHEX8(buf[i]);
+ ostrm << RAWHEX8(p[i]);
}
}
@@ -2452,6 +2520,45 @@ gdb_regnum_with_fixed_width_hex_register_value (std::ostream& ostrm,
}
}
+
+void
+RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid,
+ nub_addr_t dispatch_qaddr,
+ std::string &queue_name,
+ uint64_t &queue_width,
+ uint64_t &queue_serialnum) const
+{
+ queue_name.clear();
+ queue_width = 0;
+ queue_serialnum = 0;
+
+ if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS && dispatch_qaddr != 0)
+ {
+ nub_addr_t dispatch_queue_addr = DNBProcessMemoryReadPointer (pid, dispatch_qaddr);
+ if (dispatch_queue_addr)
+ {
+ queue_width = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_width, dqo_width_size, 0);
+ queue_serialnum = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_serialnum, dqo_serialnum_size, 0);
+
+ if (dqo_version >= 4)
+ {
+ // libdispatch versions 4+, pointer to dispatch name is in the
+ // queue structure.
+ nub_addr_t pointer_to_label_address = dispatch_queue_addr + dqo_label;
+ nub_addr_t label_addr = DNBProcessMemoryReadPointer (pid, pointer_to_label_address);
+ if (label_addr)
+ queue_name = std::move(DNBProcessMemoryReadCString (pid, label_addr));
+ }
+ else
+ {
+ // libdispatch versions 1-3, dispatch name is a fixed width char array
+ // in the queue structure.
+ queue_name = std::move(DNBProcessMemoryReadCStringFixed(pid, dispatch_queue_addr + dqo_label, dqo_label_size));
+ }
+ }
+ }
+}
+
rnb_err_t
RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
{
@@ -2468,8 +2575,14 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
{
const bool did_exec = tid_stop_info.reason == eStopTypeExec;
if (did_exec)
+ {
RNBRemote::InitializeRegisters(true);
+ // Reset any symbols that need resetting when we exec
+ m_dispatch_queue_offsets_addr = INVALID_NUB_ADDRESS;
+ m_dispatch_queue_offsets.Clear();
+ }
+
std::ostringstream ostrm;
// Output the T packet with the thread
ostrm << 'T';
@@ -2522,9 +2635,32 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid)
if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
{
if (thread_ident_info.dispatch_qaddr != 0)
- ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';';
+ {
+ ostrm << "qaddr:" << std::hex << thread_ident_info.dispatch_qaddr << ';';
+ const DispatchQueueOffsets *dispatch_queue_offsets = GetDispatchQueueOffsets();
+ if (dispatch_queue_offsets)
+ {
+ std::string queue_name;
+ uint64_t queue_width = 0;
+ uint64_t queue_serialnum = 0;
+ dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, queue_name, queue_width, queue_serialnum);
+ if (!queue_name.empty())
+ {
+ ostrm << "qname:";
+ append_hex_value(ostrm, queue_name.data(), queue_name.size(), false);
+ ostrm << ';';
+ }
+ if (queue_width == 1)
+ ostrm << "qkind:serial;";
+ else if (queue_width > 1)
+ ostrm << "qkind:concurrent;";
+
+ if (queue_serialnum > 0)
+ ostrm << "qserial:" << DECIMAL << queue_serialnum << ';';
+ }
+ }
}
-
+
// If a 'QListThreadsInStopReply' was sent to enable this feature, we
// will send all thread IDs back in the "threads" key whose value is
// a list of hex thread IDs separated by commas:
@@ -5003,6 +5139,71 @@ RNBRemote::HandlePacket_jThreadExtendedInfo (const char *p)
return SendPacket ("OK");
}
+
+rnb_err_t
+RNBRemote::HandlePacket_qSymbol (const char *command)
+{
+ const char *p = command;
+ p += strlen ("qSymbol:");
+ const char *sep = strchr(p, ':');
+
+ std::string symbol_name;
+ std::string symbol_value_str;
+ // Extract the symbol value if there is one
+ if (sep > p)
+ symbol_value_str.assign(p, sep - p);
+ p = sep + 1;
+
+ if (*p)
+ {
+ // We have a symbol name
+ symbol_name = std::move(decode_hex_ascii_string(p));
+ if (!symbol_value_str.empty())
+ {
+ nub_addr_t symbol_value = decode_uint64(symbol_value_str.c_str(), 16);
+ if (symbol_name == "dispatch_queue_offsets")
+ m_dispatch_queue_offsets_addr = symbol_value;
+ }
+ ++m_qSymbol_index;
+ }
+ else
+ {
+ // No symbol name, set our symbol index to zero so we can
+ // read any symbols that we need
+ m_qSymbol_index = 0;
+ }
+
+ symbol_name.clear();
+
+ if (m_qSymbol_index == 0)
+ {
+ if (m_dispatch_queue_offsets_addr == INVALID_NUB_ADDRESS)
+ symbol_name = "dispatch_queue_offsets";
+ else
+ ++m_qSymbol_index;
+ }
+
+// // Lookup next symbol when we have one...
+// if (m_qSymbol_index == 1)
+// {
+// }
+
+
+ if (symbol_name.empty())
+ {
+ // Done with symbol lookups
+ return SendPacket ("OK");
+ }
+ else
+ {
+ std::ostringstream reply;
+ reply << "qSymbol:";
+ for (size_t i = 0; i < symbol_name.size(); ++i)
+ reply << RAWHEX8(symbol_name[i]);
+ return SendPacket (reply.str().c_str());
+ }
+}
+
// Note that all numeric values returned by qProcessInfo are hex encoded,
// including the pid and the cpu type.
@@ -5193,6 +5394,23 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
return SendPacket (rep.str());
}
+const RNBRemote::DispatchQueueOffsets *
+RNBRemote::GetDispatchQueueOffsets()
+{
+ if (!m_dispatch_queue_offsets.IsValid() && m_dispatch_queue_offsets_addr != INVALID_NUB_ADDRESS && m_ctx.HasValidProcessID())
+ {
+ nub_process_t pid = m_ctx.ProcessID();
+ nub_size_t bytes_read = DNBProcessMemoryRead(pid, m_dispatch_queue_offsets_addr, sizeof(m_dispatch_queue_offsets), &m_dispatch_queue_offsets);
+ if (bytes_read != sizeof(m_dispatch_queue_offsets))
+ m_dispatch_queue_offsets.Clear();
+ }
+
+ if (m_dispatch_queue_offsets.IsValid())
+ return &m_dispatch_queue_offsets;
+ else
+ return nullptr;
+}
+
void
RNBRemote::EnableCompressionNextSendPacket (compression_types type)
{
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index 1f4883ab9e0..3fcccc2e8f3 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -91,7 +91,7 @@ public:
query_thread_extra_info, // 'qThreadExtraInfo'
query_thread_stop_info, // 'qThreadStopInfo'
query_image_offsets, // 'qOffsets'
- query_symbol_lookup, // 'gSymbols'
+ query_symbol_lookup, // 'qSymbol'
query_launch_success, // 'qLaunchSuccess'
query_register_info, // 'qRegisterInfo'
query_shlib_notify_info_addr, // 'qShlibInfoAddr'
@@ -195,6 +195,7 @@ public:
rnb_err_t HandlePacket_qHostInfo (const char *p);
rnb_err_t HandlePacket_qGDBServerVersion (const char *p);
rnb_err_t HandlePacket_qProcessInfo (const char *p);
+ rnb_err_t HandlePacket_qSymbol (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);
@@ -311,6 +312,68 @@ protected:
}
};
+
+ struct DispatchQueueOffsets
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ uint16_t dqo_flags;
+ uint16_t dqo_flags_size;
+ uint16_t dqo_serialnum;
+ uint16_t dqo_serialnum_size;
+ uint16_t dqo_width;
+ uint16_t dqo_width_size;
+ uint16_t dqo_running;
+ uint16_t dqo_running_size;
+ uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+ uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
+
+ DispatchQueueOffsets ()
+ {
+ Clear();
+ }
+
+ void
+ Clear()
+ {
+ dqo_version = UINT16_MAX;
+ dqo_label = UINT16_MAX;
+ dqo_label_size = UINT16_MAX;
+ dqo_flags = UINT16_MAX;
+ dqo_flags_size = UINT16_MAX;
+ dqo_serialnum = UINT16_MAX;
+ dqo_serialnum_size = UINT16_MAX;
+ dqo_width = UINT16_MAX;
+ dqo_width_size = UINT16_MAX;
+ dqo_running = UINT16_MAX;
+ dqo_running_size = UINT16_MAX;
+ dqo_suspend_cnt = UINT16_MAX;
+ dqo_suspend_cnt_size = UINT16_MAX;
+ dqo_target_queue = UINT16_MAX;
+ dqo_target_queue_size = UINT16_MAX;
+ dqo_priority = UINT16_MAX;
+ dqo_priority_size = UINT16_MAX;
+ }
+
+ bool
+ IsValid () const
+ {
+ return dqo_version != UINT16_MAX;
+ }
+
+ void
+ GetThreadQueueInfo (nub_process_t pid,
+ nub_addr_t dispatch_qaddr,
+ std::string &queue_name,
+ uint64_t &queue_width,
+ uint64_t &queue_serialnum) const;
+ };
+
rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait);
rnb_err_t SendPacket (const std::string &);
std::string CompressString (const std::string &);
@@ -327,12 +390,18 @@ protected:
compression_types
GetCompressionType ();
+ const DispatchQueueOffsets *
+ GetDispatchQueueOffsets();
+
RNBContext m_ctx; // process context
RNBSocket m_comm; // communication port
std::string m_arch;
nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all
nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all
PThreadMutex m_mutex; // Mutex that protects
+ DispatchQueueOffsets m_dispatch_queue_offsets;
+ nub_addr_t m_dispatch_queue_offsets_addr;
+ uint32_t m_qSymbol_index;
uint32_t m_packets_recvd;
Packet::collection m_packets;
std::deque<std::string> m_rx_packets;
OpenPOWER on IntegriCloud