summaryrefslogtreecommitdiffstats
path: root/lldb/tools/debugserver/source/RNBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/debugserver/source/RNBRemote.cpp')
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp247
1 files changed, 241 insertions, 6 deletions
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 1f751de45e7..2241fa0a70f 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <signal.h>
#include <mach/exception_types.h>
+#include <mach-o/loader.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
@@ -4608,7 +4609,14 @@ RNBRemote::HandlePacket_qHostInfo (const char *p)
// this for now.
if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
{
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+ strm << "ostype:tvos;";
+#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ strm << "ostype:watchos;";
+#else
strm << "ostype:ios;";
+#endif
+
// On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
strm << "watchpoint_exceptions_received:before;";
}
@@ -4655,6 +4663,11 @@ RNBRemote::HandlePacket_qHostInfo (const char *p)
strm << "ptrsize:8;";
else
strm << "ptrsize:" << std::dec << sizeof(void *) << ';';
+
+#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ strm << "default_packet_timeout:10;";
+#endif
+
return SendPacket (strm.str());
}
@@ -5514,6 +5527,138 @@ RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p)
return SendPacket ("OK");
}
+static bool
+MachHeaderIsMainExecutable (nub_process_t pid, uint32_t addr_size, nub_addr_t mach_header_addr, mach_header &mh)
+{
+ DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx)", pid, addr_size, mach_header_addr);
+ const nub_size_t bytes_read = DNBProcessMemoryRead(pid, mach_header_addr, sizeof(mh), &mh);
+ if (bytes_read == sizeof(mh))
+ {
+ DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx): mh = {\n magic = 0x%8.8x\n cpu = 0x%8.8x\n sub = 0x%8.8x\n filetype = %u\n ncmds = %u\n sizeofcmds = 0x%8.8x\n flags = 0x%8.8x }", pid, addr_size, mach_header_addr, mh.magic, mh.cputype, mh.cpusubtype, mh.filetype, mh.ncmds, mh.sizeofcmds, mh.flags);
+ if ((addr_size == 4 && mh.magic == MH_MAGIC) ||
+ (addr_size == 8 && mh.magic == MH_MAGIC_64))
+ {
+ if (mh.filetype == MH_EXECUTE)
+ {
+ DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx) -> this is the executable!!!", pid, addr_size, mach_header_addr);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static nub_addr_t
+GetMachHeaderForMainExecutable (const nub_process_t pid, const uint32_t addr_size, mach_header &mh)
+{
+ struct AllImageInfos
+ {
+ uint32_t version;
+ uint32_t dylib_info_count;
+ uint64_t dylib_info_addr;
+ };
+
+ uint64_t mach_header_addr = 0;
+
+ const nub_addr_t shlib_addr = DNBProcessGetSharedLibraryInfoAddress (pid);
+ uint8_t bytes[256];
+ nub_size_t bytes_read = 0;
+ DNBDataRef data (bytes, sizeof(bytes), false);
+ DNBDataRef::offset_t offset = 0;
+ data.SetPointerSize(addr_size);
+
+ //----------------------------------------------------------------------
+ // When we are sitting at __dyld_start, the kernel has placed the
+ // address of the mach header of the main executable on the stack. If we
+ // read the SP and dereference a pointer, we might find the mach header
+ // for the executable. We also just make sure there is only 1 thread
+ // since if we are at __dyld_start we shouldn't have multiple threads.
+ //----------------------------------------------------------------------
+ if (DNBProcessGetNumThreads(pid) == 1)
+ {
+ nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, 0);
+ if (tid != INVALID_NUB_THREAD)
+ {
+ DNBRegisterValue sp_value;
+ if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_SP, &sp_value))
+ {
+ uint64_t sp = addr_size == 8 ? sp_value.value.uint64 : sp_value.value.uint32;
+ bytes_read = DNBProcessMemoryRead(pid, sp, addr_size, bytes);
+ if (bytes_read == addr_size)
+ {
+ offset = 0;
+ mach_header_addr = data.GetPointer(&offset);
+ if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh))
+ return mach_header_addr;
+ }
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Check the dyld_all_image_info structure for a list of mach header
+ // since it is a very easy thing to check
+ //----------------------------------------------------------------------
+ if (shlib_addr != INVALID_NUB_ADDRESS)
+ {
+ bytes_read = DNBProcessMemoryRead(pid, shlib_addr, sizeof(AllImageInfos), bytes);
+ if (bytes_read > 0)
+ {
+ AllImageInfos aii;
+ offset = 0;
+ aii.version = data.Get32(&offset);
+ aii.dylib_info_count = data.Get32(&offset);
+ if (aii.dylib_info_count > 0)
+ {
+ aii.dylib_info_addr = data.GetPointer(&offset);
+ if (aii.dylib_info_addr != 0)
+ {
+ const size_t image_info_byte_size = 3 * addr_size;
+ for (uint32_t i=0; i<aii.dylib_info_count; ++i)
+ {
+ bytes_read = DNBProcessMemoryRead(pid, aii.dylib_info_addr + i * image_info_byte_size, image_info_byte_size, bytes);
+ if (bytes_read != image_info_byte_size)
+ break;
+ offset = 0;
+ mach_header_addr = data.GetPointer(&offset);
+ if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh))
+ return mach_header_addr;
+ }
+ }
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // We failed to find the executable's mach header from the all image
+ // infos and by dereferencing the stack pointer. Now we fall back to
+ // enumerating the memory regions and looking for regions that are
+ // executable.
+ //----------------------------------------------------------------------
+ DNBRegionInfo region_info;
+ mach_header_addr = 0;
+ while (DNBProcessMemoryRegionInfo(pid, mach_header_addr, &region_info))
+ {
+ if (region_info.size == 0)
+ break;
+
+ if (region_info.permissions & eMemoryPermissionsExecutable)
+ {
+ DNBLogThreadedIf (LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx) permissions = %c%c%c: checking region for executable mach header", region_info.addr, region_info.addr + region_info.size, (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-');
+ if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh))
+ return mach_header_addr;
+ }
+ else
+ {
+ DNBLogThreadedIf (LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx): permissions = %c%c%c: skipping region", region_info.addr, region_info.addr + region_info.size, (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-');
+ }
+ // Set the address to the next mapped region
+ mach_header_addr = region_info.addr + region_info.size;
+ }
+ bzero (&mh, sizeof(mh));
+ return INVALID_NUB_ADDRESS;
+}
+
rnb_err_t
RNBRemote::HandlePacket_qSymbol (const char *command)
{
@@ -5593,7 +5738,7 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
pid = m_ctx.ProcessID();
- rep << "pid:" << std::hex << pid << ";";
+ rep << "pid:" << std::hex << pid << ';';
int procpid_mib[4];
procpid_mib[0] = CTL_KERN;
@@ -5607,12 +5752,12 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
{
if (proc_kinfo_size > 0)
{
- rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ";";
- rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid << ";";
- rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid << ";";
- rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid << ";";
+ rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';';
+ rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid << ';';
+ rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid << ';';
+ rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid << ';';
if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
- rep << "effective-gid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ";";
+ rep << "effective-gid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';';
}
}
@@ -5623,9 +5768,14 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
cputype = best_guess_cpu_type();
}
+ uint32_t addr_size = 0;
if (cputype != 0)
{
rep << "cputype:" << std::hex << cputype << ";";
+ if (cputype & CPU_ARCH_ABI64)
+ addr_size = 8;
+ else
+ addr_size = 4;
}
bool host_cpu_is_64bit = false;
@@ -5660,11 +5810,82 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
rep << "cpusubtype:" << std::hex << cpusubtype << ';';
}
+ bool os_handled = false;
+ if (addr_size > 0)
+ {
+ rep << "ptrsize:" << std::dec << addr_size << ';';
+
+#if (defined (__x86_64__) || defined (__i386__))
+ // Try and get the OS type by looking at the load commands in the main
+ // executable and looking for a LC_VERSION_MIN load command. This is the
+ // most reliable way to determine the "ostype" value when on desktop.
+
+ mach_header mh;
+ nub_addr_t exe_mach_header_addr = GetMachHeaderForMainExecutable (pid, addr_size, mh);
+ if (exe_mach_header_addr != INVALID_NUB_ADDRESS)
+ {
+ uint64_t load_command_addr = exe_mach_header_addr + ((addr_size == 8) ? sizeof(mach_header_64) : sizeof(mach_header));
+ load_command lc;
+ for (uint32_t i=0; i<mh.ncmds && !os_handled; ++i)
+ {
+ const nub_size_t bytes_read = DNBProcessMemoryRead (pid, load_command_addr, sizeof(lc), &lc);
+ uint32_t raw_cmd = lc.cmd & ~LC_REQ_DYLD;
+ if (bytes_read != sizeof(lc))
+ break;
+ switch (raw_cmd)
+ {
+ case LC_VERSION_MIN_IPHONEOS:
+ os_handled = true;
+ rep << "ostype:ios;";
+ DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_IPHONEOS -> 'ostype:ios;'");
+ break;
+
+ case LC_VERSION_MIN_MACOSX:
+ os_handled = true;
+ rep << "ostype:macosx;";
+ DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_MACOSX -> 'ostype:macosx;'");
+ break;
+
+#if defined (DT_VARIANT_PONDEROSA) || TARGET_OS_TV == 1
+ case LC_VERSION_MIN_TVOS:
+ os_handled = true;
+ rep << "ostype:tvos;";
+ DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_TVOS -> 'ostype:tvos;'");
+ break;
+#endif
+
+ case LC_VERSION_MIN_WATCHOS:
+ os_handled = true;
+ rep << "ostype:watchos;";
+ DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_WATCHOS -> 'ostype:watchos;'");
+ break;
+
+ default:
+ break;
+ }
+ load_command_addr = load_command_addr + lc.cmdsize;
+ }
+ }
+#endif
+ }
+
+ // If we weren't able to find the OS in a LC_VERSION_MIN load command, try
+ // to set it correctly by using the cpu type and other tricks
+ if (!os_handled)
+ {
// The OS in the triple should be "ios" or "macosx" which doesn't match our
// "Darwin" which gets returned from "kern.ostype", so we need to hardcode
// this for now.
if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
+ {
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+ rep << "ostype:tvos;";
+#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ rep << "ostype:watchos;";
+#else
rep << "ostype:ios;";
+#endif
+ }
else
{
bool is_ios_simulator = false;
@@ -5716,10 +5937,21 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
}
}
if (is_ios_simulator)
+ {
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+ rep << "ostype:tvos;";
+#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ rep << "ostype:watchos;";
+#else
rep << "ostype:ios;";
+#endif
+ }
else
+ {
rep << "ostype:macosx;";
}
+ }
+ }
rep << "vendor:apple;";
@@ -5731,6 +5963,8 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
rep << "endian:pdp;";
#endif
+ if (addr_size == 0)
+ {
#if (defined (__x86_64__) || defined (__i386__)) && defined (x86_THREAD_STATE)
nub_thread_t thread = DNBProcessGetCurrentThreadMachPort (pid);
kern_return_t kr;
@@ -5764,6 +5998,7 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p)
rep << "ptrsize:4;";
}
#endif
+ }
return SendPacket (rep.str());
}
OpenPOWER on IntegriCloud