[Lldb-commits] [lldb] r240466 - Implement the "qSymbol" packet in order to be able to read queue information in debugserver and return the info in the stop reply packets.

Greg Clayton gclayton at apple.com
Tue Jun 23 14:27:51 PDT 2015


Author: gclayton
Date: Tue Jun 23 16:27:50 2015
New Revision: 240466

URL: http://llvm.org/viewvc/llvm-project?rev=240466&view=rev
Log:
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>


Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
    lldb/trunk/tools/debugserver/source/DNB.cpp
    lldb/trunk/tools/debugserver/source/DNB.h
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.h

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Tue Jun 23 16:27:50 2015
@@ -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:

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Tue Jun 23 16:27:50 2015
@@ -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::GDBRemoteC
     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::ResetDisco
     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::ReadExtFea
     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;
+
+        }
+    }
+}
+

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Tue Jun 23 16:27:50 2015
@@ -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

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Tue Jun 23 16:27:50 2015
@@ -1834,6 +1834,10 @@ ProcessGDBRemote::SetThreadStopInfo (Str
             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 (Str
                 {
                     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 (Str
                 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(con
     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:

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Tue Jun 23 16:27:50 2015
@@ -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;

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp Tue Jun 23 16:27:50 2015
@@ -40,9 +40,11 @@ ThreadGDBRemote::ThreadGDBRemote (Proces
     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());

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h Tue Jun 23 16:27:50 2015
@@ -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.
     //------------------------------------------------------------------

Modified: lldb/trunk/tools/debugserver/source/DNB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.cpp?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.cpp (original)
+++ lldb/trunk/tools/debugserver/source/DNB.cpp Tue Jun 23 16:27:50 2015
@@ -1257,6 +1257,86 @@ DNBProcessMemoryRead (nub_process_t pid,
     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

Modified: lldb/trunk/tools/debugserver/source/DNB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.h (original)
+++ lldb/trunk/tools/debugserver/source/DNB.h Tue Jun 23 16:27:50 2015
@@ -69,6 +69,10 @@ nub_bool_t      DNBProcessInterrupt
 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;

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Tue Jun 23 16:27:50 2015
@@ -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
 }
 
 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
     }
 }
 
+
+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
     {
         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
         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_jThreadExtendedI
     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 (co
     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)
 {

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=240466&r1=240465&r2=240466&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.h Tue Jun 23 16:27:50 2015
@@ -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;





More information about the lldb-commits mailing list