summaryrefslogtreecommitdiffstats
path: root/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/debugserver/source/MacOSX/MachProcess.mm')
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.mm267
1 files changed, 267 insertions, 0 deletions
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 ()
{
OpenPOWER on IntegriCloud