[Lldb-commits] [lldb] r274718 - Add support to debugserver for some new ways to interact with dyld

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Wed Jul 6 18:09:24 PDT 2016


Author: jmolenda
Date: Wed Jul  6 20:09:23 2016
New Revision: 274718

URL: http://llvm.org/viewvc/llvm-project?rev=274718&view=rev
Log:
Add support to debugserver for some new ways to interact with dyld
to find the solibs loaded in a process.  Support two new ways of
sending the jGetLoadedDynamicLibrariesInfos packet to debugserver
and add a new jGetSharedCacheInfo packet.  Update the documentation
for these packets as well.  The changes to lldb to use these will
be a separate commit.

<rdar://problem/25251243> 


Modified:
    lldb/trunk/docs/lldb-gdb-remote.txt
    lldb/trunk/tools/debugserver/source/DNB.cpp
    lldb/trunk/tools/debugserver/source/DNB.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.mm
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.h

Modified: lldb/trunk/docs/lldb-gdb-remote.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/lldb-gdb-remote.txt?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt (original)
+++ lldb/trunk/docs/lldb-gdb-remote.txt Wed Jul  6 20:09:23 2016
@@ -1508,6 +1508,28 @@ for this region.
 //  This packet asks the remote debug stub to send the details about libraries
 //  being added/removed from the process as a performance optimization.
 //
+//  There are three ways this packet can be used.  All three return a dictionary of
+//  binary images formatted the same way.
+//
+//  On MacOS X 10.11, iOS 9, tvOS 9, watchOS 2 and earlier, the packet is used like
+//       jGetLoadedDynamicLibrariesInfos:{"image_count":1,"image_list_address":140734800075128}
+//  where the image_list_address is an array of {void* load_addr, void* mod_date, void* pathname}
+//  in the inferior process memory (and image_count is the number of elements in this array).
+//  lldb is using information from the dyld_all_image_infos structure to make these requests to
+//  debugserver.  This use is not supported on macOS 10.12, iOS 10, tvOS 10, watchOS 3 or newer.
+//
+//  On macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer, there are two calls.  One requests information
+//  on all shared libraries:
+//       jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}
+//  And the second requests information about a list of shared libraries, given their load addresses:
+//       jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]}
+//
+//  The second call is both a performance optimization (instead of having lldb read the mach-o header/load commands
+//  out of memory with generic read packets) but also adds additional information in the form of the 
+//  filename of the shared libraries (which is not available in the mach-o header/load commands.)
+//  
+//  An example using the Mac OS X 10.11 style call:
+//
 //  LLDB SENDS: jGetLoadedDynamicLibrariesInfos:{"image_count":1,"image_list_address":140734800075128}
 //  STUB REPLIES: ${"images":[{"load_address":4294967296,"mod_date":0,"pathname":"/tmp/a.out","uuid":"02CF262C-ED6F-3965-9E14-63538B465CFF","mach_header":{"magic":4277009103,"cputype":16777223,"cpusubtype":18446744071562067971,"filetype":2},"segments":{"name":"__PAGEZERO","vmaddr":0,"vmsize":4294967296,"fileoff":0,"filesize":0,"maxprot":0},{"name":"__TEXT","vmaddr":4294967296,"vmsize":4096,"fileoff":0,"filesize":4096,"maxprot":7},{"name":"__LINKEDIT","vmaddr":4294971392,"vmsize":4096,"fileoff":4096,"filesize":152,"maxprot":7}}]}#00
 //
@@ -1562,26 +1584,12 @@ for this region.
 // quite a bit to provide all the information that the DynamicLoaderMacOSX
 // would need to work correctly on this platform.
 //
-// On Mac OS X / iOS, when libraries are added or removed, a stub
-// function is called which lldb puts a breakpoint on.  The arguments
-// to the stub function include the number of libraries being added
-// or removed and the address where the list of libraries can be
-// found.  The information at this address is the load address of the
-// library, the filename, and the mod date of the library if available.
-// DynamicLoaderMacOSX then parses the load commands in the Mach-O header
-// at the load address before it can decide what action to take.
-//
-// The purpose of this packet is to eliminate all of the memory reads needed
-// to read the Mach-O header and load commands for these libraries.
-// On a typical GUI app, there can be a couple hundred shared libraries 
-// which results in megabytes of read packets.  That same information can
-// be returned in a couple hundred kilobytes in JSON format from the remote
-// debugserver.
-//
-//
 // PRIORITY TO IMPLEMENT
-//  Low.  If this packet is absent, lldb will read the Mach-O headers/load
-//  commands out of memory.
+//  On Mac OS X 10.11, iOS 9, tvOS 9, watchOS 2 and older: Low.  If this packet is absent, 
+//  lldb will read the Mach-O headers/load commands out of memory.
+//  On macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer: High.  If this packet is absent,
+//  lldb will not know anything about shared libraries in the inferior, or where the main
+//  executable loaded.
 //----------------------------------------------------------------------
 
 //----------------------------------------------------------------------
@@ -1649,6 +1657,26 @@ the previous FP and PC), and follow the
 iOS now don't require us to read any memory!
 
 //----------------------------------------------------------------------
+// "jGetSharedCacheInfo"
+//
+// BRIEF
+//  This packet asks the remote debug stub to send the details about the inferior's
+//  shared cache. The shared cache is a collection of common libraries/frameworks that
+//  are mapped into every process at the same address on Darwin systems, and can be
+//  identified by a load address and UUID.
+//
+//
+//  LLDB SENDS: jGetSharedCacheInfo:{}
+//  STUB REPLIES: ${"shared_cache_base_address":140735683125248,"shared_cache_uuid":"DDB8D70C-C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false]}#00
+//
+// PRIORITY TO IMPLEMENT
+//  Low.  When both lldb and the inferior process are running on the same computer, and lldb
+//  and the inferior process have the same shared cache, lldb may (as an optimization) read
+//  the shared cache out of its own memory instead of using gdb-remote read packets to read
+//  them from the inferior process.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
 // "qQueryGDBServer"
 //
 // BRIEF

Modified: lldb/trunk/tools/debugserver/source/DNB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.cpp?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.cpp (original)
+++ lldb/trunk/tools/debugserver/source/DNB.cpp Wed Jul  6 20:09:23 2016
@@ -1083,6 +1083,39 @@ DNBGetLoadedDynamicLibrariesInfos (nub_p
     return JSONGenerator::ObjectSP();
 }
 
+JSONGenerator::ObjectSP 
+DNBGetAllLoadedLibrariesInfos (nub_process_t pid)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+    {
+        return procSP->GetAllLoadedLibrariesInfos (pid);
+    }
+    return JSONGenerator::ObjectSP();
+}
+
+JSONGenerator::ObjectSP 
+DNBGetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+    {
+        return procSP->GetLibrariesInfoForAddresses (pid, macho_addresses);
+    }
+    return JSONGenerator::ObjectSP();
+}
+
+JSONGenerator::ObjectSP 
+DNBGetSharedCacheInfo (nub_process_t pid)
+{
+    MachProcessSP procSP;
+    if (GetProcessSP (pid, procSP))
+    {
+        return procSP->GetSharedCacheInfo (pid);
+    }
+    return JSONGenerator::ObjectSP();
+}
+
 
 
 const char *

Modified: lldb/trunk/tools/debugserver/source/DNB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.h?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.h (original)
+++ lldb/trunk/tools/debugserver/source/DNB.h Wed Jul  6 20:09:23 2016
@@ -144,6 +144,10 @@ nub_addr_t      DNBGetPThreadT
 nub_addr_t      DNBGetDispatchQueueT            (nub_process_t pid, nub_thread_t tid);
 nub_addr_t      DNBGetTSDAddressForThread       (nub_process_t pid, nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
 JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count);
+JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos (nub_process_t pid);
+JSONGenerator::ObjectSP DNBGetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses);
+JSONGenerator::ObjectSP DNBGetSharedCacheInfo (nub_process_t pid);
+
 //
 //----------------------------------------------------------------------
 // Breakpoint functions

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h Wed Jul  6 20:09:23 2016
@@ -15,8 +15,10 @@
 #define __MachProcess_h__
 
 #include <mach/mach.h>
+#include <mach-o/loader.h>
 #include <sys/signal.h>
 #include <pthread.h>
+#include <uuid/uuid.h>
 #include <vector>
 #include <CoreFoundation/CoreFoundation.h>
 
@@ -46,6 +48,43 @@ public:
     MachProcess ();
     ~MachProcess ();
 
+    // A structure that can hold everything debugserver needs to know from
+    // a binary's Mach-O header / load commands.
+
+    struct mach_o_segment
+    {
+        std::string name;
+        uint64_t vmaddr;
+        uint64_t vmsize;
+        uint64_t fileoff;
+        uint64_t filesize;
+        uint64_t maxprot;
+        uint64_t initprot;
+        uint64_t nsects;
+        uint64_t flags;
+    };
+
+    struct mach_o_information
+    {
+        struct mach_header_64 mach_header;
+        std::vector<struct mach_o_segment> segments;
+        uuid_t uuid;
+    };
+
+    struct binary_image_information
+    {
+        std::string filename;
+        uint64_t    load_address;
+        uint64_t    mod_date;      // may not be available - 0 if so
+        struct mach_o_information macho_info;
+
+        binary_image_information () : 
+            filename (),
+            load_address (INVALID_NUB_ADDRESS),
+            mod_date (0)
+            { }
+    };
+
     //----------------------------------------------------------------------
     // Child process control
     //----------------------------------------------------------------------
@@ -193,7 +232,15 @@ public:
     nub_addr_t              GetPThreadT (nub_thread_t tid);
     nub_addr_t              GetDispatchQueueT (nub_thread_t tid);
     nub_addr_t              GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
+
+
+    bool                    GetMachOInformationFromMemory (nub_addr_t mach_o_header_addr, int wordsize, struct mach_o_information &inf);
+    JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON (const std::vector<struct binary_image_information> &image_infos);
+    void                    GetAllLoadedBinariesViaDYLDSPI (std::vector<struct binary_image_information> &image_infos);
     JSONGenerator::ObjectSP GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count);
+    JSONGenerator::ObjectSP GetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses);
+    JSONGenerator::ObjectSP GetAllLoadedLibrariesInfos (nub_process_t pid);
+    JSONGenerator::ObjectSP GetSharedCacheInfo (nub_process_t pid);
 
     nub_size_t              GetNumThreads () const;
     nub_thread_t            GetThreadAtIndex (nub_size_t thread_idx) const;
@@ -358,6 +405,11 @@ private:
                                                              // as the sole reason for the process being stopped, we can auto resume
                                                              // the process.
     bool                        m_did_exec;
+
+    void * (*m_dyld_process_info_create) (task_t task, uint64_t timestamp, kern_return_t* kernelError);
+    void   (*m_dyld_process_info_for_each_image) (void* info, void (^callback)(uint64_t machHeaderAddress, const uuid_t uuid, const char* path));
+    void   (*m_dyld_process_info_release) (void* info);
+    void   (*m_dyld_process_info_get_cache) (void* info, void* cacheInfo);
 };
 
 

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.mm
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.mm?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.mm (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.mm Wed Jul  6 20:09:23 2016
@@ -12,8 +12,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "DNB.h"
+#include <dlfcn.h>
 #include <inttypes.h>
 #include <mach/mach.h>
+#include <mach/task.h>
 #include <signal.h>
 #include <spawn.h>
 #include <sys/fcntl.h>
@@ -417,8 +419,17 @@ MachProcess::MachProcess() :
     m_image_infos_baton(NULL),
     m_sent_interrupt_signo (0),
     m_auto_resume_signo (0),
-    m_did_exec (false)
-{
+    m_did_exec (false),
+    m_dyld_process_info_create (nullptr),
+    m_dyld_process_info_for_each_image (nullptr),
+    m_dyld_process_info_release (nullptr),
+    m_dyld_process_info_get_cache (nullptr)
+{
+    m_dyld_process_info_create = (void * (*) (task_t task, uint64_t timestamp, kern_return_t* kernelError)) dlsym (RTLD_DEFAULT, "_dyld_process_info_create");
+    m_dyld_process_info_for_each_image = (void (*)(void *info, void (^)(uint64_t machHeaderAddress, const uuid_t uuid, const char* path))) dlsym (RTLD_DEFAULT, "_dyld_process_info_for_each_image");
+    m_dyld_process_info_release = (void (*) (void* info)) dlsym (RTLD_DEFAULT, "_dyld_process_info_release");
+    m_dyld_process_info_get_cache = (void (*) (void* info, void* cacheInfo)) dlsym (RTLD_DEFAULT, "_dyld_process_info_get_cache");
+
     DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
 }
 
@@ -520,8 +531,177 @@ MachProcess::GetTSDAddressForThread (nub
     return m_thread_list.GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
 }
 
+// Given an address, read the mach-o header and load commands out of memory to fill in
+// the mach_o_information "inf" object.
+//
+// Returns false if there was an error in reading this mach-o file header/load commands.
+
+bool
+MachProcess::GetMachOInformationFromMemory (nub_addr_t mach_o_header_addr, int wordsize, struct mach_o_information &inf)
+{
+    uint64_t load_cmds_p;
+    if (wordsize == 4)
+    {
+        struct mach_header header;
+        if (ReadMemory (mach_o_header_addr, sizeof (struct mach_header), &header) != sizeof (struct mach_header))
+        {
+            return false;
+        }
+        load_cmds_p = mach_o_header_addr + sizeof (struct mach_header);
+        inf.mach_header.magic = header.magic;
+        inf.mach_header.cputype = header.cputype;
+        // high byte of cpusubtype is used for "capability bits", v. CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h
+        inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff;
+        inf.mach_header.filetype = header.filetype;
+        inf.mach_header.ncmds = header.ncmds;
+        inf.mach_header.sizeofcmds = header.sizeofcmds;
+        inf.mach_header.flags = header.flags;
+    }
+    else
+    {
+        struct mach_header_64 header;
+        if (ReadMemory (mach_o_header_addr, sizeof (struct mach_header_64), &header) != sizeof (struct mach_header_64))
+        {
+            return false;
+        }
+        load_cmds_p = mach_o_header_addr + sizeof (struct mach_header_64);
+        inf.mach_header.magic = header.magic;
+        inf.mach_header.cputype = header.cputype;
+        // high byte of cpusubtype is used for "capability bits", v. CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h
+        inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff;
+        inf.mach_header.filetype = header.filetype;
+        inf.mach_header.ncmds = header.ncmds;
+        inf.mach_header.sizeofcmds = header.sizeofcmds;
+        inf.mach_header.flags = header.flags;
+    }
+    for (uint32_t j = 0; j < inf.mach_header.ncmds; j++)
+    {
+        struct load_command lc;
+        if (ReadMemory (load_cmds_p, sizeof (struct load_command), &lc) != sizeof (struct load_command))
+        {
+            return false;
+        }
+        if (lc.cmd == LC_SEGMENT)
+        {
+            struct segment_command seg;
+            if (ReadMemory (load_cmds_p, sizeof (struct segment_command), &seg) != sizeof (struct segment_command))
+            {
+                return false;
+            }
+            struct mach_o_segment this_seg;
+            char name[17];
+            ::memset (name, 0, sizeof (name));
+            memcpy (name, seg.segname, sizeof (seg.segname));
+            this_seg.name = name;
+            this_seg.vmaddr = seg.vmaddr;
+            this_seg.vmsize = seg.vmsize;
+            this_seg.fileoff = seg.fileoff;
+            this_seg.filesize = seg.filesize;
+            this_seg.maxprot = seg.maxprot;
+            this_seg.initprot = seg.initprot;
+            this_seg.nsects = seg.nsects;
+            this_seg.flags = seg.flags;
+            inf.segments.push_back(this_seg);
+        }
+        if (lc.cmd == LC_SEGMENT_64)
+        {
+            struct segment_command_64 seg;
+            if (ReadMemory (load_cmds_p, sizeof (struct segment_command_64), &seg) != sizeof (struct segment_command_64))
+            {
+                return false;
+            }
+            struct mach_o_segment this_seg;
+            char name[17];
+            ::memset (name, 0, sizeof (name));
+            memcpy (name, seg.segname, sizeof (seg.segname));
+            this_seg.name = name;
+            this_seg.vmaddr = seg.vmaddr;
+            this_seg.vmsize = seg.vmsize;
+            this_seg.fileoff = seg.fileoff;
+            this_seg.filesize = seg.filesize;
+            this_seg.maxprot = seg.maxprot;
+            this_seg.initprot = seg.initprot;
+            this_seg.nsects = seg.nsects;
+            this_seg.flags = seg.flags;
+            inf.segments.push_back(this_seg);
+        }
+        if (lc.cmd == LC_UUID)
+        {
+            struct uuid_command uuidcmd;
+            if (ReadMemory (load_cmds_p, sizeof (struct uuid_command), &uuidcmd) == sizeof (struct uuid_command))
+                uuid_copy (inf.uuid, uuidcmd.uuid);
+        }
+        load_cmds_p += lc.cmdsize;
+    }
+    return true;
+}
+
+// Given completely filled in array of binary_image_information structures, create a JSONGenerator object
+// with all the details we want to send to lldb.
+JSONGenerator::ObjectSP
+MachProcess::FormatDynamicLibrariesIntoJSON (const std::vector<struct binary_image_information> &image_infos)
+{
 
+    JSONGenerator::ArraySP image_infos_array_sp (new JSONGenerator::Array());
 
+    const size_t image_count = image_infos.size();
+
+    for (size_t i = 0; i < image_count; i++)
+    {
+        JSONGenerator::DictionarySP image_info_dict_sp (new JSONGenerator::Dictionary());
+        image_info_dict_sp->AddIntegerItem ("load_address", image_infos[i].load_address);
+        image_info_dict_sp->AddIntegerItem ("mod_date", image_infos[i].mod_date);
+        image_info_dict_sp->AddStringItem ("pathname", image_infos[i].filename);
+
+        uuid_string_t uuidstr;
+        uuid_unparse_upper (image_infos[i].macho_info.uuid, uuidstr);
+        image_info_dict_sp->AddStringItem ("uuid", uuidstr);
+
+        JSONGenerator::DictionarySP mach_header_dict_sp (new JSONGenerator::Dictionary());
+        mach_header_dict_sp->AddIntegerItem ("magic", image_infos[i].macho_info.mach_header.magic);
+        mach_header_dict_sp->AddIntegerItem ("cputype", (uint32_t) image_infos[i].macho_info.mach_header.cputype);
+        mach_header_dict_sp->AddIntegerItem ("cpusubtype", (uint32_t) image_infos[i].macho_info.mach_header.cpusubtype);
+        mach_header_dict_sp->AddIntegerItem ("filetype", image_infos[i].macho_info.mach_header.filetype);
+
+//          DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
+//            mach_header_dict_sp->AddIntegerItem ("ncmds", image_infos[i].macho_info.mach_header.ncmds);
+//            mach_header_dict_sp->AddIntegerItem ("sizeofcmds", image_infos[i].macho_info.mach_header.sizeofcmds);
+//            mach_header_dict_sp->AddIntegerItem ("flags", image_infos[i].macho_info.mach_header.flags);
+        image_info_dict_sp->AddItem ("mach_header", mach_header_dict_sp);
+
+        JSONGenerator::ArraySP segments_sp (new JSONGenerator::Array());
+        for (size_t j = 0; j < image_infos[i].macho_info.segments.size(); j++)
+        {
+            JSONGenerator::DictionarySP segment_sp (new JSONGenerator::Dictionary());
+            segment_sp->AddStringItem ("name", image_infos[i].macho_info.segments[j].name);
+            segment_sp->AddIntegerItem ("vmaddr", image_infos[i].macho_info.segments[j].vmaddr);
+            segment_sp->AddIntegerItem ("vmsize", image_infos[i].macho_info.segments[j].vmsize);
+            segment_sp->AddIntegerItem ("fileoff", image_infos[i].macho_info.segments[j].fileoff);
+            segment_sp->AddIntegerItem ("filesize", image_infos[i].macho_info.segments[j].filesize);
+            segment_sp->AddIntegerItem ("maxprot", image_infos[i].macho_info.segments[j].maxprot);
+
+//              DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
+//                segment_sp->AddIntegerItem ("initprot", image_infos[i].macho_info.segments[j].initprot);
+//                segment_sp->AddIntegerItem ("nsects", image_infos[i].macho_info.segments[j].nsects);
+//                segment_sp->AddIntegerItem ("flags", image_infos[i].macho_info.segments[j].flags);
+            segments_sp->AddItem (segment_sp);
+        }
+        image_info_dict_sp->AddItem ("segments", segments_sp);
+
+        image_infos_array_sp->AddItem (image_info_dict_sp);
+    }
+
+    JSONGenerator::DictionarySP reply_sp (new JSONGenerator::Dictionary());;
+    reply_sp->AddItem ("images", image_infos_array_sp);
+
+    return reply_sp;
+}
+
+// Get the shared library information using the old (pre-macOS 10.12, pre-iOS 10, pre-tvOS 10, pre-watchOS 3)
+// code path.  We'll be given the address of an array of structures in the form
+// {void* load_addr, void* mod_date, void* pathname} 
+//
+// In macOS 10.12 etc and newer, we'll use SPI calls into dyld to gather this information.
 JSONGenerator::ObjectSP
 MachProcess::GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count)
 {
@@ -536,29 +716,7 @@ MachProcess::GetLoadedDynamicLibrariesIn
         if (processInfo.kp_proc.p_flag & P_LP64)
             pointer_size = 8;
 
-        struct segment
-        {
-            std::string name;
-            uint64_t vmaddr;
-            uint64_t vmsize;
-            uint64_t fileoff;
-            uint64_t filesize;
-            uint64_t maxprot;
-            uint64_t initprot;
-            uint64_t nsects;
-            uint64_t flags;
-        };
-        
-        struct image_info 
-        {
-            uint64_t load_address;
-            std::string pathname;
-            uint64_t mod_date;
-            struct mach_header_64 mach_header;
-            std::vector<struct segment> segments;
-            uuid_t uuid;
-        };
-        std::vector<image_info> image_infos;
+        std::vector<struct binary_image_information> image_infos;
         size_t image_infos_size = image_count * 3 * pointer_size;
 
         uint8_t *image_info_buf = (uint8_t *) malloc (image_infos_size);
@@ -577,7 +735,7 @@ MachProcess::GetLoadedDynamicLibrariesIn
 
         for (size_t i = 0; i <  image_count; i++)
         {
-            struct image_info info;
+            struct binary_image_information info;
             nub_addr_t pathname_address;
             if (pointer_size == 4)
             {
@@ -604,13 +762,13 @@ MachProcess::GetLoadedDynamicLibrariesIn
                 pathname_address = pathname_address_64;
             }
             char strbuf[17];
-            info.pathname = "";
+            info.filename = "";
             uint64_t pathname_ptr = pathname_address;
             bool still_reading = true;
             while (still_reading && ReadMemory (pathname_ptr, sizeof (strbuf) - 1, strbuf) == sizeof (strbuf) - 1)
             {
                 strbuf[sizeof(strbuf) - 1] = '\0';
-                info.pathname += strbuf;
+                info.filename += strbuf;
                 pathname_ptr += sizeof (strbuf) - 1;
                 // Stop if we found nul byte indicating the end of the string
                 for (size_t i = 0; i < sizeof(strbuf) - 1; i++)
@@ -622,7 +780,7 @@ MachProcess::GetLoadedDynamicLibrariesIn
                     }
                 }
             }
-            uuid_clear (info.uuid);
+            uuid_clear (info.macho_info.uuid);
             image_infos.push_back (info);
         }
         if (image_infos.size() == 0)
@@ -630,157 +788,161 @@ MachProcess::GetLoadedDynamicLibrariesIn
             return reply_sp;
         }
 
+        free (image_info_buf);
 
         ////  Second, read the mach header / load commands for all the dylibs
 
-
         for (size_t i = 0; i < image_count; i++)
         {
-            uint64_t load_cmds_p;
-            if (pointer_size == 4)
-            {
-                struct mach_header header;
-                if (ReadMemory (image_infos[i].load_address, sizeof (struct mach_header), &header) != sizeof (struct mach_header))
-                {
-                    return reply_sp;
-                }
-                load_cmds_p = image_infos[i].load_address + sizeof (struct mach_header);
-                image_infos[i].mach_header.magic = header.magic;
-                image_infos[i].mach_header.cputype = header.cputype;
-                image_infos[i].mach_header.cpusubtype = header.cpusubtype;
-                image_infos[i].mach_header.filetype = header.filetype;
-                image_infos[i].mach_header.ncmds = header.ncmds;
-                image_infos[i].mach_header.sizeofcmds = header.sizeofcmds;
-                image_infos[i].mach_header.flags = header.flags;
-            }
-            else
-            {
-                struct mach_header_64 header;
-                if (ReadMemory (image_infos[i].load_address, sizeof (struct mach_header_64), &header) != sizeof (struct mach_header_64))
-                {
-                    return reply_sp;
-                }
-                load_cmds_p = image_infos[i].load_address + sizeof (struct mach_header_64);
-                image_infos[i].mach_header.magic = header.magic;
-                image_infos[i].mach_header.cputype = header.cputype;
-                image_infos[i].mach_header.cpusubtype = header.cpusubtype;
-                image_infos[i].mach_header.filetype = header.filetype;
-                image_infos[i].mach_header.ncmds = header.ncmds;
-                image_infos[i].mach_header.sizeofcmds = header.sizeofcmds;
-                image_infos[i].mach_header.flags = header.flags;
-            }
-            for (uint32_t j = 0; j < image_infos[i].mach_header.ncmds; j++)
+            if (!GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info))
             {
-                struct load_command lc;
-                if (ReadMemory (load_cmds_p, sizeof (struct load_command), &lc) != sizeof (struct load_command))
-                {
-                    return reply_sp;
-                }
-                if (lc.cmd == LC_SEGMENT)
-                {
-                    struct segment_command seg;
-                    if (ReadMemory (load_cmds_p, sizeof (struct segment_command), &seg) != sizeof (struct segment_command))
-                    {
-                        return reply_sp;
-                    }
-                    struct segment this_seg;
-                    char name[17];
-                    ::memset (name, 0, sizeof (name));
-                    memcpy (name, seg.segname, sizeof (seg.segname));
-                    this_seg.name = name;
-                    this_seg.vmaddr = seg.vmaddr;
-                    this_seg.vmsize = seg.vmsize;
-                    this_seg.fileoff = seg.fileoff;
-                    this_seg.filesize = seg.filesize;
-                    this_seg.maxprot = seg.maxprot;
-                    this_seg.initprot = seg.initprot;
-                    this_seg.nsects = seg.nsects;
-                    this_seg.flags = seg.flags;
-                    image_infos[i].segments.push_back(this_seg);
-                }
-                if (lc.cmd == LC_SEGMENT_64)
-                {
-                    struct segment_command_64 seg;
-                    if (ReadMemory (load_cmds_p, sizeof (struct segment_command_64), &seg) != sizeof (struct segment_command_64))
-                    {
-                        return reply_sp;
-                    }
-                    struct segment this_seg;
-                    char name[17];
-                    ::memset (name, 0, sizeof (name));
-                    memcpy (name, seg.segname, sizeof (seg.segname));
-                    this_seg.name = name;
-                    this_seg.vmaddr = seg.vmaddr;
-                    this_seg.vmsize = seg.vmsize;
-                    this_seg.fileoff = seg.fileoff;
-                    this_seg.filesize = seg.filesize;
-                    this_seg.maxprot = seg.maxprot;
-                    this_seg.initprot = seg.initprot;
-                    this_seg.nsects = seg.nsects;
-                    this_seg.flags = seg.flags;
-                    image_infos[i].segments.push_back(this_seg);
-                }
-                if (lc.cmd == LC_UUID)
-                {
-                    struct uuid_command uuidcmd;
-                    if (ReadMemory (load_cmds_p, sizeof (struct uuid_command), &uuidcmd) == sizeof (struct uuid_command))
-                        uuid_copy (image_infos[i].uuid, uuidcmd.uuid);
-                }
-                load_cmds_p += lc.cmdsize;
+                return reply_sp;
             }
         }
 
 
-        ////  Thrid, format all of the above in the JSONGenerator object.
+        ////  Third, format all of the above in the JSONGenerator object.
 
 
-        JSONGenerator::ArraySP image_infos_array_sp (new JSONGenerator::Array());
+        return FormatDynamicLibrariesIntoJSON (image_infos);
+    }
+
+    return reply_sp;
+}
+
+// From dyld SPI header dyld_process_info.h
+typedef void* dyld_process_info;
+struct dyld_process_cache_info 
+{
+    uuid_t      cacheUUID;              // UUID of cache used by process
+    uint64_t    cacheBaseAddress;       // load address of dyld shared cache
+    bool        noCache;                // process is running without a dyld cache
+    bool        privateCache;           // process is using a private copy of its dyld cache
+};
+
+
+// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer to get
+// the load address, uuid, and filenames of all the libraries.
+// This only fills in those three fields in the 'struct binary_image_information' - call
+// GetMachOInformationFromMemory to fill in the mach-o header/load command details.
+void
+MachProcess::GetAllLoadedBinariesViaDYLDSPI (std::vector<struct binary_image_information> &image_infos)
+{
+    kern_return_t kern_ret;
+    if (m_dyld_process_info_create)
+    {
+        dyld_process_info info = m_dyld_process_info_create (m_task.TaskPort(), 0, &kern_ret);
+        if (info)
+        {
+            m_dyld_process_info_for_each_image (info, ^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) {
+                struct binary_image_information image;
+                image.filename = path;
+                uuid_copy (image.macho_info.uuid, uuid);
+                image.load_address = mach_header_addr;
+                image_infos.push_back (image);
+            });
+            m_dyld_process_info_release (info);
+        }
+    }
+}
+
+// Fetch information about all shared libraries using the dyld SPIs that exist in
+// macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer.
+JSONGenerator::ObjectSP 
+MachProcess::GetAllLoadedLibrariesInfos (nub_process_t pid)
+{
+    JSONGenerator::DictionarySP reply_sp;
+
+    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
+    struct kinfo_proc processInfo;
+    size_t bufsize = sizeof(processInfo);
+    if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0)
+    {
+        uint32_t pointer_size = 4;
+        if (processInfo.kp_proc.p_flag & P_LP64)
+            pointer_size = 8;
+
+        std::vector<struct binary_image_information> image_infos;
+        GetAllLoadedBinariesViaDYLDSPI (image_infos);
+        const size_t image_count = image_infos.size();
         for (size_t i = 0; i < image_count; i++)
         {
-            JSONGenerator::DictionarySP image_info_dict_sp (new JSONGenerator::Dictionary());
-            image_info_dict_sp->AddIntegerItem ("load_address", image_infos[i].load_address);
-            image_info_dict_sp->AddIntegerItem ("mod_date", image_infos[i].mod_date);
-            image_info_dict_sp->AddStringItem ("pathname", image_infos[i].pathname);
+            GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info);
+        }
+        return FormatDynamicLibrariesIntoJSON (image_infos);
+    }
+    return reply_sp;
+}
 
-            uuid_string_t uuidstr;
-            uuid_unparse_upper (image_infos[i].uuid, uuidstr);
-            image_info_dict_sp->AddStringItem ("uuid", uuidstr);
+// Fetch information about the shared libraries at the given load addresses using the
+// dyld SPIs that exist in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer.
+JSONGenerator::ObjectSP 
+MachProcess::GetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses)
+{
+    JSONGenerator::DictionarySP reply_sp;
 
-            JSONGenerator::DictionarySP mach_header_dict_sp (new JSONGenerator::Dictionary());
-            mach_header_dict_sp->AddIntegerItem ("magic", image_infos[i].mach_header.magic);
-            mach_header_dict_sp->AddIntegerItem ("cputype", image_infos[i].mach_header.cputype);
-            mach_header_dict_sp->AddIntegerItem ("cpusubtype", image_infos[i].mach_header.cpusubtype);
-            mach_header_dict_sp->AddIntegerItem ("filetype", image_infos[i].mach_header.filetype);
+    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
+    struct kinfo_proc processInfo;
+    size_t bufsize = sizeof(processInfo);
+    if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0)
+    {
+        uint32_t pointer_size = 4;
+        if (processInfo.kp_proc.p_flag & P_LP64)
+            pointer_size = 8;
 
-//          DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
-//            mach_header_dict_sp->AddIntegerItem ("ncmds", image_infos[i].mach_header.ncmds);
-//            mach_header_dict_sp->AddIntegerItem ("sizeofcmds", image_infos[i].mach_header.sizeofcmds);
-//            mach_header_dict_sp->AddIntegerItem ("flags", image_infos[i].mach_header.flags);
-            image_info_dict_sp->AddItem ("mach_header", mach_header_dict_sp);
+        std::vector<struct binary_image_information> all_image_infos;
+        GetAllLoadedBinariesViaDYLDSPI (all_image_infos);
 
-            JSONGenerator::ArraySP segments_sp (new JSONGenerator::Array());
-            for (size_t j = 0; j < image_infos[i].segments.size(); j++)
+        std::vector<struct binary_image_information> image_infos;
+        const size_t macho_addresses_count = macho_addresses.size();
+        const size_t all_image_infos_count = all_image_infos.size();
+        for (size_t i = 0; i < macho_addresses_count; i++)
+        {
+            for (size_t j = 0; j < all_image_infos_count; j++)
             {
-                JSONGenerator::DictionarySP segment_sp (new JSONGenerator::Dictionary());
-                segment_sp->AddStringItem ("name", image_infos[i].segments[j].name);
-                segment_sp->AddIntegerItem ("vmaddr", image_infos[i].segments[j].vmaddr);
-                segment_sp->AddIntegerItem ("vmsize", image_infos[i].segments[j].vmsize);
-                segment_sp->AddIntegerItem ("fileoff", image_infos[i].segments[j].fileoff);
-                segment_sp->AddIntegerItem ("filesize", image_infos[i].segments[j].filesize);
-                segment_sp->AddIntegerItem ("maxprot", image_infos[i].segments[j].maxprot);
-
-//              DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
-//                segment_sp->AddIntegerItem ("initprot", image_infos[i].segments[j].initprot);
-//                segment_sp->AddIntegerItem ("nsects", image_infos[i].segments[j].nsects);
-//                segment_sp->AddIntegerItem ("flags", image_infos[i].segments[j].flags);
-                segments_sp->AddItem (segment_sp);
+                if (all_image_infos[j].load_address == macho_addresses[i])
+                {
+                    image_infos.push_back (all_image_infos[j]);
+                }
             }
-            image_info_dict_sp->AddItem ("segments", segments_sp);
+        }
+
+        const size_t image_infos_count = image_infos.size();
+        for (size_t i = 0; i < image_infos_count; i++)
+        {
+            GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info);
+        }
+        return FormatDynamicLibrariesIntoJSON (image_infos);
+    }
+    return reply_sp;
+}
+
+// From dyld's internal podyld_process_info.h:
+
+JSONGenerator::ObjectSP
+MachProcess::GetSharedCacheInfo (nub_process_t pid)
+{
+    JSONGenerator::DictionarySP reply_sp (new JSONGenerator::Dictionary());;
+    kern_return_t kern_ret;
+    if (m_dyld_process_info_create && m_dyld_process_info_get_cache)
+    {
+        dyld_process_info info = m_dyld_process_info_create (m_task.TaskPort(), 0, &kern_ret);
+        if (info)
+        {
+            struct dyld_process_cache_info shared_cache_info;
+            m_dyld_process_info_get_cache (info, &shared_cache_info);
+            
+            reply_sp->AddIntegerItem ("shared_cache_base_address", shared_cache_info.cacheBaseAddress);
+
+            uuid_string_t uuidstr;
+            uuid_unparse_upper (shared_cache_info.cacheUUID, uuidstr);
+            reply_sp->AddStringItem ("shared_cache_uuid", uuidstr);
+            
+            reply_sp->AddBooleanItem ("no_shared_cache", shared_cache_info.noCache);
+            reply_sp->AddBooleanItem ("shared_cache_private_cache", shared_cache_info.privateCache);
 
-            image_infos_array_sp->AddItem (image_info_dict_sp);
+            m_dyld_process_info_release (info);
         }
-        reply_sp.reset (new JSONGenerator::Dictionary());
-        reply_sp->AddItem ("images", image_infos_array_sp);
     }
     return reply_sp;
 }

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Wed Jul  6 20:09:23 2016
@@ -284,6 +284,7 @@ RNBRemote::CreatePacketTable  ()
     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_get_shared_cache_info,          &RNBRemote::HandlePacket_jGetSharedCacheInfo,     NULL, "jGetSharedCacheInfo", "Replies with JSON data about the location and uuid of the shared cache in the inferior process."));
     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"));
@@ -5061,6 +5062,122 @@ get_integer_value_for_key_name_from_json
 
 }
 
+// A helper function that retrieves a boolean value from
+// a one-level-deep JSON dictionary of key-value pairs.  e.g.
+// jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}]
+
+// Returns true if it was able to find the key name, and sets the 'value'
+// argument to the value found.
+
+bool
+get_boolean_value_for_key_name_from_json (const char *key, const char *json_string, bool &value)
+{
+    std::string key_with_quotes = "\"";
+    key_with_quotes += key;
+    key_with_quotes += "\"";
+    const char *c = strstr (json_string, key_with_quotes.c_str());
+    if (c)
+    {
+        c += key_with_quotes.size();
+
+        while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+            c++;
+
+        if (*c == ':')
+        {
+            c++;
+
+            while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+                c++;
+
+            if (strncmp (c, "true", 4) == 0)
+            {
+                value = true;
+                return true;
+            } else if (strncmp (c, "false", 5) == 0)
+            {
+                value = false;
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// A helper function that reads an array of uint64_t's from
+// a one-level-deep JSON dictionary of key-value pairs.  e.g.
+// jGetLoadedDynamicLibrariesInfos:{"solib_addrs":[31345823,7768020384,7310483024]}]
+
+// Returns true if it was able to find the key name, false if it did not.
+// "ints" will have all integers found in the array appended to it.
+
+bool
+get_array_of_ints_value_for_key_name_from_json (const char *key, const char *json_string, std::vector<uint64_t> &ints)
+{
+    std::string key_with_quotes = "\"";
+    key_with_quotes += key;
+    key_with_quotes += "\"";
+    const char *c = strstr (json_string, key_with_quotes.c_str());
+    if (c)
+    {
+        c += key_with_quotes.size();
+
+        while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+            c++;
+
+        if (*c == ':')
+        {
+            c++;
+
+            while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+                c++;
+
+            if (*c == '[')
+            {
+                c++;
+                while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+                    c++;
+                while (1)
+                {
+                    if (!isdigit (*c))
+                    {
+                        return true;
+                    }
+
+                    errno = 0;
+                    char *endptr;
+                    uint64_t value = strtoul (c, &endptr, 10);
+                    if (errno == 0)
+                    {
+                        ints.push_back (value);
+                    }
+                    else
+                    {
+                        break;
+                    }
+                    if (endptr == c || endptr == nullptr || *endptr == '\0')
+                    {
+                        break;
+                    }
+                    c = endptr;
+
+                    while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+                        c++;
+                    if (*c == ',')
+                        c++;
+                    while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+                        c++;
+                    if (*c == ']')
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
 JSONGenerator::ObjectSP
 RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only)
 {
@@ -5488,6 +5605,20 @@ RNBRemote::HandlePacket_jThreadExtendedI
     return SendPacket ("OK");
 }
 
+//  This packet may be called in one of three ways:
+//
+//  jGetLoadedDynamicLibrariesInfos:{"image_count":40,"image_list_address":4295244704}
+//      Look for an array of the old dyld_all_image_infos style of binary infos at the image_list_address.
+//      This an array of {void* load_addr, void* mod_date, void* pathname} 
+//
+//  jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}
+//      Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to get a list of all the
+//      libraries loaded
+//
+//  jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]}
+//      Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to get the information
+//      about the libraries loaded at these addresses.
+//
 rnb_err_t
 RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p)
 {
@@ -5505,28 +5636,81 @@ RNBRemote::HandlePacket_jGetLoadedDynami
     {
         p += strlen (get_loaded_dynamic_libraries_infos_str);
 
-        nub_addr_t image_list_address = get_integer_value_for_key_name_from_json ("image_list_address", p);
-        nub_addr_t image_count = get_integer_value_for_key_name_from_json ("image_count", p);
+        JSONGenerator::ObjectSP json_sp;
 
-        if (image_list_address != INVALID_NUB_ADDRESS && image_count != INVALID_NUB_ADDRESS)
+        std::vector<uint64_t> macho_addresses;
+        bool fetch_all_solibs = false;
+        if (get_boolean_value_for_key_name_from_json ("fetch_all_solibs", p, fetch_all_solibs) && fetch_all_solibs)
+        {
+            json_sp = DNBGetAllLoadedLibrariesInfos (pid);
+        }
+        else if (get_array_of_ints_value_for_key_name_from_json ("solib_addresses", p, macho_addresses))
         {
-            JSONGenerator::ObjectSP json_sp;
+            json_sp = DNBGetLibrariesInfoForAddresses (pid, macho_addresses);
+        }
+        else
+        {
+            nub_addr_t image_list_address = get_integer_value_for_key_name_from_json ("image_list_address", p);
+            nub_addr_t image_count = get_integer_value_for_key_name_from_json ("image_count", p);
 
-            json_sp = DNBGetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count);
+            if (image_list_address != INVALID_NUB_ADDRESS && image_count != INVALID_NUB_ADDRESS)
+            {
+                json_sp = DNBGetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count);
+            }
+        }
 
-            if (json_sp.get())
+        if (json_sp.get())
+        {
+            std::ostringstream json_str;
+            json_sp->Dump (json_str);
+            if (json_str.str().size() > 0)
             {
-                std::ostringstream json_str;
-                json_sp->Dump (json_str);
-                if (json_str.str().size() > 0)
-                {
-                    std::string json_str_quoted = binary_encode_string (json_str.str());
-                    return SendPacket (json_str_quoted.c_str());
-                }
-                else
-                {
-                    SendPacket ("E84");
-                }
+                std::string json_str_quoted = binary_encode_string (json_str.str());
+                return SendPacket (json_str_quoted.c_str());
+            }
+            else
+            {
+                SendPacket ("E84");
+            }
+        }
+    }
+    return SendPacket ("OK");
+}
+
+// This packet does not currently take any arguments.  So the behavior is
+//    jGetSharedCacheInfo:{}
+//         send information about the inferior's shared cache
+//    jGetSharedCacheInfo:
+//         send "OK" to indicate that this packet is supported
+rnb_err_t
+RNBRemote::HandlePacket_jGetSharedCacheInfo (const char *p)
+{
+    nub_process_t pid;
+    // If we haven't run the process yet, return an error.
+    if (!m_ctx.HasValidProcessID())
+    {
+        return SendPacket ("E85");
+    }
+
+    pid = m_ctx.ProcessID();
+
+    const char get_shared_cache_info_str[] = { "jGetSharedCacheInfo:{" };
+    if (strncmp (p, get_shared_cache_info_str, sizeof (get_shared_cache_info_str) - 1) == 0)
+    {
+        JSONGenerator::ObjectSP json_sp = DNBGetSharedCacheInfo (pid);
+
+        if (json_sp.get())
+        {
+            std::ostringstream json_str;
+            json_sp->Dump (json_str);
+            if (json_str.str().size() > 0)
+            {
+                std::string json_str_quoted = binary_encode_string (json_str.str());
+                return SendPacket (json_str_quoted.c_str());
+            }
+            else
+            {
+                SendPacket ("E86");
             }
         }
     }

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=274718&r1=274717&r2=274718&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.h Wed Jul  6 20:09:23 2016
@@ -105,6 +105,7 @@ public:
         json_query_thread_extended_info,// 'jThreadExtendedInfo'
         json_query_get_loaded_dynamic_libraries_infos, // 'jGetLoadedDynamicLibrariesInfos'
         json_query_threads_info,        // 'jThreadsInfo'
+        json_query_get_shared_cache_info, // 'jGetSharedCacheInfo'
         pass_signals_to_inferior,       // 'QPassSignals'
         start_noack_mode,               // 'QStartNoAckMode'
         prefix_reg_packets_with_tid,    // 'QPrefixRegisterPacketsWithThreadID
@@ -194,6 +195,7 @@ public:
     rnb_err_t HandlePacket_jThreadExtendedInfo (const char *p);
     rnb_err_t HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p);
     rnb_err_t HandlePacket_jThreadsInfo (const char *p);
+    rnb_err_t HandlePacket_jGetSharedCacheInfo (const char *p);
     rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
     rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
     rnb_err_t HandlePacket_qHostInfo (const char *p);




More information about the lldb-commits mailing list