summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/docs/lldb-gdb-remote.txt83
-rw-r--r--lldb/include/lldb/Target/Process.h32
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp183
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp19
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp39
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h3
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp12
-rw-r--r--lldb/tools/debugserver/source/DNB.h2
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h2
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.mm267
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp46
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h2
14 files changed, 698 insertions, 0 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index d8f22fe604a..78c5b32a49e 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -1447,3 +1447,86 @@ for this region.
// libcompression implements "LZMA level 6", the default compression for the
// open source LZMA implementation.
//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// "jGetLoadedDynamicLibrariesInfos"
+//
+// BRIEF
+// This packet asks the remote debug stub to send the details about libraries
+// being added/removed from the process as a performance optimization.
+//
+// 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
+//
+// Or pretty-printed,
+//
+// 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
+// }
+// ]
+// }
+// ]
+// }
+//
+//
+// This is similar to the qXfer:libraries:read packet, and it could
+// be argued that it should be merged into that packet. A separate
+// packet was created primarily because lldb needs to specify the
+// number of images to be read and the address from which the initial
+// information is read. Also the XML DTD would need to be extended
+// 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.
+//----------------------------------------------------------------------
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index db0f0cfa028..39c5fcd0421 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -30,6 +30,7 @@
#include "lldb/Core/Event.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
#include "lldb/Host/HostThread.h"
@@ -1887,6 +1888,37 @@ public:
virtual void
ModulesDidLoad (ModuleList &module_list);
+
+ //------------------------------------------------------------------
+ /// Retrieve the list of shared libraries that are loaded for this process
+ ///
+ /// For certain platforms, the time it takes for the DynamicLoader plugin to
+ /// read all of the shared libraries out of memory over a slow communication
+ /// channel may be too long. In that instance, the gdb-remote stub may be
+ /// able to retrieve the necessary information about the solibs out of memory
+ /// and return a concise summary sufficient for the DynamicLoader plugin.
+ ///
+ /// @param [in] image_list_address
+ /// The address where the table of shared libraries is stored in memory,
+ /// if that is appropriate for this platform. Else this may be
+ /// passed as LLDB_INVALID_ADDRESS.
+ ///
+ /// @param [in] image_count
+ /// The number of shared libraries that are present in this process, if
+ /// that is appropriate for this platofrm Else this may be passed as
+ /// LLDB_INVALID_ADDRESS.
+ ///
+ /// @return
+ /// A StructureDataSP object which, if non-empty, will contain the
+ /// information the DynamicLoader needs to get the initial scan of
+ /// solibs resolved.
+ //------------------------------------------------------------------
+ virtual lldb_private::StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count)
+ {
+ return StructuredData::ObjectSP();
+ }
+
protected:
void
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
index a5e89327ac0..5d7b478e014 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include <uuid/uuid.h>
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/DataBuffer.h"
@@ -793,6 +794,172 @@ DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure ()
}
+// This method is an amalgamation of code from
+// ReadMachHeader()
+// ParseLoadCommands()
+// UpdateImageInfosHeaderAndLoadCommands()
+// but written to extract everything from the JSON packet from debugserver, instead of using memory reads.
+
+bool
+DynamicLoaderMacOSXDYLD::AddModulesUsingInfosFromDebugserver (StructuredData::ObjectSP image_details, DYLDImageInfo::collection &image_infos)
+{
+ StructuredData::ObjectSP images_sp = image_details->GetAsDictionary()->GetValueForKey("images");
+ if (images_sp.get() == nullptr)
+ return false;
+
+ image_infos.resize (images_sp->GetAsArray()->GetSize());
+
+ uint32_t exe_idx = UINT32_MAX;
+
+ for (size_t i = 0; i < image_infos.size(); i++)
+ {
+ StructuredData::ObjectSP image_sp = images_sp->GetAsArray()->GetItemAtIndex(i);
+ if (image_sp.get() == nullptr || image_sp->GetAsDictionary() == nullptr)
+ return false;
+ StructuredData::Dictionary *image = image_sp->GetAsDictionary();
+ if (image->HasKey("load_address") == false
+ || image->HasKey("pathname") == false
+ || image->HasKey("mod_date") == false
+ || image->HasKey("mach_header") == false
+ || image->GetValueForKey("mach_header")->GetAsDictionary() == nullptr
+ || image->HasKey("segments") == false
+ || image->GetValueForKey("segments")->GetAsArray() == nullptr
+ || image->HasKey("uuid") == false )
+ {
+ return false;
+ }
+ image_infos[i].address = image->GetValueForKey("load_address")->GetAsInteger()->GetValue();
+ image_infos[i].mod_date = image->GetValueForKey("mod_date")->GetAsInteger()->GetValue();
+ image_infos[i].file_spec.SetFile(image->GetValueForKey("pathname")->GetAsString()->GetValue().c_str(), false);
+
+ StructuredData::Dictionary *mh = image->GetValueForKey("mach_header")->GetAsDictionary();
+ image_infos[i].header.magic = mh->GetValueForKey("magic")->GetAsInteger()->GetValue();
+ image_infos[i].header.cputype = mh->GetValueForKey("cputype")->GetAsInteger()->GetValue();
+ image_infos[i].header.cpusubtype = mh->GetValueForKey("cpusubtype")->GetAsInteger()->GetValue();
+ image_infos[i].header.filetype = mh->GetValueForKey("filetype")->GetAsInteger()->GetValue();
+
+ // Fields that aren't used by DynamicLoaderMacOSXDYLD so debugserver doesn't currently send them
+ // in the reply.
+
+ if (mh->HasKey("flags"))
+ image_infos[i].header.flags = mh->GetValueForKey("flags")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.flags = 0;
+
+ if (mh->HasKey("ncmds"))
+ image_infos[i].header.ncmds = mh->GetValueForKey("ncmds")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.ncmds = 0;
+
+ if (mh->HasKey("sizeofcmds"))
+ image_infos[i].header.sizeofcmds = mh->GetValueForKey("sizeofcmds")->GetAsInteger()->GetValue();
+ else
+ image_infos[i].header.sizeofcmds = 0;
+
+ if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE)
+ exe_idx = i;
+
+ StructuredData::Array *segments = image->GetValueForKey("segments")->GetAsArray();
+ uint32_t segcount = segments->GetSize();
+ for (size_t j = 0; j < segcount; j++)
+ {
+ Segment segment;
+ StructuredData::Dictionary *seg = segments->GetItemAtIndex(j)->GetAsDictionary();
+ segment.name = ConstString(seg->GetValueForKey("name")->GetAsString()->GetValue().c_str());
+ segment.vmaddr = seg->GetValueForKey("vmaddr")->GetAsInteger()->GetValue();
+ segment.vmsize = seg->GetValueForKey("vmsize")->GetAsInteger()->GetValue();
+ segment.fileoff = seg->GetValueForKey("fileoff")->GetAsInteger()->GetValue();
+ segment.filesize = seg->GetValueForKey("filesize")->GetAsInteger()->GetValue();
+ segment.maxprot = seg->GetValueForKey("maxprot")->GetAsInteger()->GetValue();
+
+ // Fields that aren't used by DynamicLoaderMacOSXDYLD so debugserver doesn't currently send them
+ // in the reply.
+
+ if (seg->HasKey("initprot"))
+ segment.initprot = seg->GetValueForKey("initprot")->GetAsInteger()->GetValue();
+ else
+ segment.initprot = 0;
+
+ if (seg->HasKey("flags"))
+ segment.flags = seg->GetValueForKey("flags")->GetAsInteger()->GetValue();
+ else
+ segment.flags = 0;
+
+ if (seg->HasKey("nsects"))
+ segment.nsects = seg->GetValueForKey("nsects")->GetAsInteger()->GetValue();
+ else
+ segment.nsects = 0;
+
+ image_infos[i].segments.push_back (segment);
+ }
+
+ image_infos[i].uuid.SetFromCString (image->GetValueForKey("uuid")->GetAsString()->GetValue().c_str());
+
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = image_infos[i].segments.size();
+ for (size_t k = 0; k < num_sections; ++k)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ if ((image_infos[i].segments[k].fileoff == 0 && image_infos[i].segments[k].filesize > 0)
+ || (image_infos[i].segments[k].name == ConstString("__TEXT")))
+ {
+ image_infos[i].slide = image_infos[i].address - image_infos[i].segments[k].vmaddr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+ }
+
+ Target &target = m_process->GetTarget();
+
+ if (exe_idx < image_infos.size())
+ {
+ const bool can_create = true;
+ ModuleSP exe_module_sp (FindTargetModuleForDYLDImageInfo (image_infos[exe_idx], can_create, NULL));
+
+ if (exe_module_sp)
+ {
+ UpdateImageLoadAddress (exe_module_sp.get(), image_infos[exe_idx]);
+
+ if (exe_module_sp.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded. Also when setting the
+ // executable module, it will clear the targets module list, and if we
+ // have an in memory dyld module, it will get removed from the list
+ // so we will need to add it back after setting the executable module,
+ // so we first try and see if we already have a weak pointer to the
+ // dyld module, make it into a shared pointer, then add the executable,
+ // then re-add it back to make sure it is always in the list.
+ ModuleSP dyld_module_sp(m_dyld_module_wp.lock());
+
+ const bool get_dependent_images = false;
+ m_process->GetTarget().SetExecutableModule (exe_module_sp,
+ get_dependent_images);
+
+ if (dyld_module_sp)
+ {
+ if(target.GetImages().AppendIfNeeded (dyld_module_sp))
+ {
+ // Also add it to the section list.
+ UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld);
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
bool
DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count)
{
@@ -805,6 +972,22 @@ DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress (lldb::addr_t image_in
if (m_process->GetStopID() == m_dyld_image_infos_stop_id)
return true;
+ StructuredData::ObjectSP image_infos_json_sp = m_process->GetLoadedDynamicLibrariesInfos (image_infos_addr, image_infos_count);
+ if (image_infos_json_sp.get()
+ && image_infos_json_sp->GetAsDictionary()
+ && image_infos_json_sp->GetAsDictionary()->HasKey("images")
+ && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()
+ && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()->GetSize() == image_infos_count)
+ {
+ bool return_value = false;
+ if (AddModulesUsingInfosFromDebugserver (image_infos_json_sp, image_infos))
+ {
+ return_value = AddModulesUsingImageInfos (image_infos);
+ }
+ m_dyld_image_infos_stop_id = m_process->GetStopID();
+ return return_value;
+ }
+
if (!ReadImageInfos (image_infos_addr, image_infos_count, image_infos))
return false;
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
index c9fa43fcac0..4484e31515c 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
@@ -18,6 +18,7 @@
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
@@ -344,6 +345,9 @@ protected:
ReadAllImageInfosStructure ();
bool
+ AddModulesUsingInfosFromDebugserver (lldb_private::StructuredData::ObjectSP image_details, DYLDImageInfo::collection &image_infos);
+
+ bool
AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
bool
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index ae0a2f5e66c..afc772d7345 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -87,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() :
m_supports_qXfer_features_read (eLazyBoolCalculate),
m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),
m_supports_jThreadExtendedInfo (eLazyBoolCalculate),
+ m_supports_jLoadedDynamicLibrariesInfos (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
@@ -654,6 +655,24 @@ GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
}
bool
+GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported ()
+{
+ if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jLoadedDynamicLibrariesInfos;
+}
+
+bool
GDBRemoteCommunicationClient::GetxPacketSupported ()
{
if (m_supports_x == eLazyBoolCalculate)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 65a2981018e..deb41b066b4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -550,6 +550,9 @@ public:
GetThreadExtendedInfoSupported();
bool
+ GetLoadedDynamicLibrariesInfosSupported();
+
+ bool
GetModuleInfo (const FileSpec& module_file_spec,
const ArchSpec& arch_spec,
ModuleSpec &module_spec);
@@ -614,6 +617,7 @@ protected:
LazyBool m_supports_qXfer_features_read;
LazyBool m_supports_augmented_libraries_svr4_read;
LazyBool m_supports_jThreadExtendedInfo;
+ LazyBool m_supports_jLoadedDynamicLibrariesInfos;
bool
m_supports_qProcessInfoPID:1,
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 37dbff0913e..ef79e084f3b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3985,6 +3985,44 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid)
{
if (!response.Empty())
{
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count)
+{
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported())
+ {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address);
+ args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count);
+
+ StreamString packet;
+ packet << "jGetLoadedDynamicLibrariesInfos:";
+ args_dict->Dump (packet);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version
+ // of the } character here manually in case we talk to a debugserver which
+ // un-escapes the characters at packet read time.
+ packet << (char) (0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ if (!response.Empty())
+ {
// The packet has already had the 0x7d xor quoting stripped out at the
// GDBRemoteCommunication packet receive level.
object_sp = StructuredData::ParseJSON (response.GetStringRef());
@@ -3995,6 +4033,7 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid)
return object_sp;
}
+
// Establish the largest memory read/write payloads we should use.
// If the remote stub has a max packet size, stay under that size.
//
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 2f825d3e1c3..45c74ea64ee 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -247,6 +247,9 @@ public:
void
ModulesDidLoad (ModuleList &module_list) override;
+ StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override;
+
protected:
friend class ThreadGDBRemote;
friend class GDBRemoteCommunicationClient;
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index 4cde3f87b08..f9cab2ff665 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -1066,6 +1066,18 @@ DNBGetTSDAddressForThread (nub_process_t pid, nub_thread_t tid, uint64_t plo_pth
return INVALID_NUB_ADDRESS;
}
+JSONGenerator::ObjectSP
+DNBGetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count)
+{
+ MachProcessSP procSP;
+ if (GetProcessSP (pid, procSP))
+ {
+ return procSP->GetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count);
+ }
+ return JSONGenerator::ObjectSP();
+}
+
+
const char *
DNBProcessGetExecutablePath (nub_process_t pid)
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index 3f032798f23..45a0556670e 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -16,6 +16,7 @@
#include "MacOSX/Genealogy.h"
#include "MacOSX/ThreadInfo.h"
+#include "JSONGenerator.h"
#include "DNBDefs.h"
#include <mach/thread_info.h>
#include <string>
@@ -141,6 +142,7 @@ ThreadInfo::QoS DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t
nub_addr_t DNBGetPThreadT (nub_process_t pid, nub_thread_t tid);
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);
//
//----------------------------------------------------------------------
// Breakpoint functions
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
index 3d007a36e31..66977079016 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -27,6 +27,7 @@
#include "PThreadMutex.h"
#include "Genealogy.h"
#include "ThreadInfo.h"
+#include "JSONGenerator.h"
#include <mach/mach.h>
#include <sys/signal.h>
@@ -185,6 +186,7 @@ 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);
+ JSONGenerator::ObjectSP GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count);
nub_size_t GetNumThreads () const;
nub_thread_t GetThreadAtIndex (nub_size_t thread_idx) const;
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
index 3be4d65458c..9a537939d8b 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -23,6 +23,8 @@
#include <sys/sysctl.h>
#include <unistd.h>
#include <pthread.h>
+#include <mach-o/loader.h>
+#include <uuid/uuid.h>
#include "MacOSX/CFUtils.h"
#include "SysSignal.h"
@@ -281,6 +283,271 @@ MachProcess::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_
return m_thread_list.GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
}
+
+
+JSONGenerator::ObjectSP
+MachProcess::GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count)
+{
+ JSONGenerator::ObjectSP 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;
+
+ 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;
+ size_t image_infos_size = image_count * 3 * pointer_size;
+
+ uint8_t *image_info_buf = (uint8_t *) malloc (image_infos_size);
+ if (image_info_buf == NULL)
+ {
+ return reply_sp;
+ }
+ if (ReadMemory (image_list_address, image_infos_size, image_info_buf) != image_infos_size)
+ {
+ return reply_sp;
+ }
+
+
+ //// First the image_infos array with (load addr, pathname, mod date) tuples
+
+
+ for (size_t i = 0; i < image_count; i++)
+ {
+ struct image_info info;
+ nub_addr_t pathname_address;
+ if (pointer_size == 4)
+ {
+ uint32_t load_address_32;
+ uint32_t pathname_address_32;
+ uint32_t mod_date_32;
+ ::memcpy (&load_address_32, image_info_buf + (i * 3 * pointer_size), 4);
+ ::memcpy (&pathname_address_32, image_info_buf + (i * 3 * pointer_size) + pointer_size, 4);
+ ::memcpy (&mod_date_32, image_info_buf + (i * 3 * pointer_size) + pointer_size + pointer_size, 4);
+ info.load_address = load_address_32;
+ info.mod_date = mod_date_32;
+ pathname_address = pathname_address_32;
+ }
+ else
+ {
+ uint64_t load_address_64;
+ uint64_t pathname_address_64;
+ uint64_t mod_date_64;
+ ::memcpy (&load_address_64, image_info_buf + (i * 3 * pointer_size), 8);
+ ::memcpy (&pathname_address_64, image_info_buf + (i * 3 * pointer_size) + pointer_size, 8);
+ ::memcpy (&mod_date_64, image_info_buf + (i * 3 * pointer_size) + pointer_size + pointer_size, 8);
+ info.load_address = load_address_64;
+ info.mod_date = mod_date_64;
+ pathname_address = pathname_address_64;
+ }
+ char strbuf[17];
+ info.pathname = "";
+ 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;
+ pathname_ptr += sizeof (strbuf) - 1;
+ // Stop if we found nul byte indicating the end of the string
+ for (int i = 0; i < sizeof(strbuf) - 1; i++)
+ {
+ if (strbuf[i] == '\0')
+ {
+ still_reading = false;
+ break;
+ }
+ }
+ }
+ uuid_clear (info.uuid);
+ image_infos.push_back (info);
+ }
+ if (image_infos.size() == 0)
+ {
+ return reply_sp;
+ }
+
+
+ //// 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++)
+ {
+ 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;
+ }
+ }
+
+
+ //// Thrid, format all of the above in the JSONGenerator object.
+
+
+ JSONGenerator::ObjectSP image_infos_array_sp (new JSONGenerator::Array());
+ for (size_t i = 0; i < image_count; i++)
+ {
+ JSONGenerator::ObjectSP image_info_dict_sp (new JSONGenerator::Dictionary());
+ image_info_dict_sp->GetAsDictionary()->AddIntegerItem ("load_address", image_infos[i].load_address);
+ image_info_dict_sp->GetAsDictionary()->AddIntegerItem ("mod_date", image_infos[i].mod_date);
+ image_info_dict_sp->GetAsDictionary()->AddStringItem ("pathname", image_infos[i].pathname);
+
+ uuid_string_t uuidstr;
+ uuid_unparse_upper (image_infos[i].uuid, uuidstr);
+ image_info_dict_sp->GetAsDictionary()->AddStringItem ("uuid", uuidstr);
+
+ JSONGenerator::ObjectSP mach_header_dict_sp (new JSONGenerator::Dictionary());
+ mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("magic", image_infos[i].mach_header.magic);
+ mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("cputype", image_infos[i].mach_header.cputype);
+ mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("cpusubtype", image_infos[i].mach_header.cpusubtype);
+ mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("filetype", image_infos[i].mach_header.filetype);
+
+// DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
+// mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("ncmds", image_infos[i].mach_header.ncmds);
+// mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("sizeofcmds", image_infos[i].mach_header.sizeofcmds);
+// mach_header_dict_sp->GetAsDictionary()->AddIntegerItem ("flags", image_infos[i].mach_header.flags);
+ image_info_dict_sp->GetAsDictionary()->AddItem ("mach_header", mach_header_dict_sp);
+
+ JSONGenerator::ObjectSP segments_sp (new JSONGenerator::Array());
+ for (size_t j = 0; j < image_infos[i].segments.size(); j++)
+ {
+ JSONGenerator::ObjectSP segment_sp (new JSONGenerator::Dictionary());
+ segment_sp->GetAsDictionary()->AddStringItem ("name", image_infos[i].segments[j].name);
+ segment_sp->GetAsDictionary()->AddIntegerItem ("vmaddr", image_infos[i].segments[j].vmaddr);
+ segment_sp->GetAsDictionary()->AddIntegerItem ("vmsize", image_infos[i].segments[j].vmsize);
+ segment_sp->GetAsDictionary()->AddIntegerItem ("fileoff", image_infos[i].segments[j].fileoff);
+ segment_sp->GetAsDictionary()->AddIntegerItem ("filesize", image_infos[i].segments[j].filesize);
+ segment_sp->GetAsDictionary()->AddIntegerItem ("maxprot", image_infos[i].segments[j].maxprot);
+
+// DynamicLoaderMacOSX doesn't currently need these fields, so don't send them.
+// segment_sp->GetAsDictionary()->AddIntegerItem ("initprot", image_infos[i].segments[j].initprot);
+// segment_sp->GetAsDictionary()->AddIntegerItem ("nsects", image_infos[i].segments[j].nsects);
+// segment_sp->GetAsDictionary()->AddIntegerItem ("flags", image_infos[i].segments[j].flags);
+ segments_sp->GetAsArray()->AddItem (segment_sp);
+ }
+ image_info_dict_sp->GetAsDictionary()->AddItem ("segments", segments_sp);
+
+ image_infos_array_sp->GetAsArray()->AddItem (image_info_dict_sp);
+ }
+ reply_sp.reset (new JSONGenerator::Dictionary());
+ reply_sp->GetAsDictionary()->AddItem ("images", image_infos_array_sp);
+ }
+ return reply_sp;
+}
+
nub_thread_t
MachProcess::GetCurrentThread ()
{
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 30abfa5743b..f1c5d75ff4d 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -35,6 +35,7 @@
#include "RNBSocket.h"
#include "lldb/Utility/StringExtractor.h"
#include "MacOSX/Genealogy.h"
+#include "JSONGenerator.h"
#if defined (HAVE_LIBCOMPRESSION)
#include <compression.h>
@@ -263,6 +264,7 @@ RNBRemote::CreatePacketTable ()
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 (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 (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"));
@@ -5345,6 +5347,50 @@ RNBRemote::HandlePacket_jThreadExtendedInfo (const char *p)
return SendPacket ("OK");
}
+rnb_err_t
+RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p)
+{
+ nub_process_t pid;
+ // If we haven't run the process yet, return an error.
+ if (!m_ctx.HasValidProcessID())
+ {
+ return SendPacket ("E83");
+ }
+
+ pid = m_ctx.ProcessID();
+
+ const char get_loaded_dynamic_libraries_infos_str[] = { "jGetLoadedDynamicLibrariesInfos:{" };
+ if (strncmp (p, get_loaded_dynamic_libraries_infos_str, sizeof (get_loaded_dynamic_libraries_infos_str) - 1) == 0)
+ {
+ 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);
+
+ if (image_list_address != INVALID_NUB_ADDRESS && image_count != INVALID_NUB_ADDRESS)
+ {
+ JSONGenerator::ObjectSP json_sp;
+
+ json_sp = DNBGetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count);
+
+ 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 ("E84");
+ }
+ }
+ }
+ }
+ return SendPacket ("OK");
+}
rnb_err_t
RNBRemote::HandlePacket_qSymbol (const char *command)
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index 00cfe7991f9..570d0e02d99 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -103,6 +103,7 @@ public:
query_gdb_server_version, // 'qGDBServerVersion'
query_process_info, // 'qProcessInfo'
json_query_thread_extended_info,// 'jThreadExtendedInfo'
+ json_query_get_loaded_dynamic_libraries_infos, // 'jGetLoadedDynamicLibrariesInfos'
json_query_threads_info, // 'jThreadsInfo'
pass_signals_to_inferior, // 'QPassSignals'
start_noack_mode, // 'QStartNoAckMode'
@@ -191,6 +192,7 @@ public:
rnb_err_t HandlePacket_qSyncThreadStateSupported (const char *p);
rnb_err_t HandlePacket_qThreadInfo (const char *p);
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_qThreadExtraInfo (const char *p);
rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
OpenPOWER on IntegriCloud