Upstream a few small Apple changes to debugserver - arm64_32, Catalyst

Adrian's changes to support Catalyst processes and my
changes to support debugserver running on an arm64_32
device (Apple Watch Series 4, which uses an IPL32 model
on arm64 cpus).

llvm-svn: 368118
This commit is contained in:
Jason Molenda 2019-08-07 02:06:06 +00:00
parent 5dbfca8541
commit 6cebeafac3
10 changed files with 171 additions and 30 deletions

View File

@ -162,7 +162,7 @@ let Definition = "process" in {
Desc<"Disable reading and caching of memory in fixed-size units.">;
def ExtraStartCommand: Property<"extra-startup-command", "Array">,
DefaultUnsignedValue<16>,
Desc<"A list containing extra commands understood by the particular process plugin used. For instance, to turn on debugserver logging set this to 'QSetLogging:bitmask=LOG_DEFAULT;">;
Desc<"A list containing extra commands understood by the particular process plugin used. For instance, to turn on debugserver logging set this to 'QSetLogging:bitmask=LOG_DEFAULT;'">;
def IgnoreBreakpointsInExpressions: Property<"ignore-breakpoints-in-expressions", "Boolean">,
Global,
DefaultTrue,

View File

@ -1695,6 +1695,10 @@ bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
return MachProcess::GetOSVersionNumbers(major, minor, patch);
}
std::string DNBGetMacCatalystVersionString() {
return MachProcess::GetMacCatalystVersionString();
}
void DNBInitialize() {
DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
#if defined(__i386__) || defined(__x86_64__)
@ -1715,6 +1719,8 @@ nub_bool_t DNBSetArchitecture(const char *arch) {
else if ((strcasecmp(arch, "x86_64") == 0) ||
(strcasecmp(arch, "x86_64h") == 0))
return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
else if (strstr(arch, "arm64_32") == arch)
return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch ||
strstr(arch, "aarch64") == arch)
return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);

View File

@ -20,6 +20,8 @@
#include "MacOSX/ThreadInfo.h"
#include <mach/thread_info.h>
#include <string>
#include <Availability.h>
#include <mach/machine.h>
#define DNB_EXPORT __attribute__((visibility("default")))
@ -27,6 +29,10 @@
#define CPU_TYPE_ARM64 ((cpu_type_t)12 | 0x01000000)
#endif
#ifndef CPU_TYPE_ARM64_32
#define CPU_TYPE_ARM64_32 ((cpu_type_t)12 | 0x02000000)
#endif
typedef bool (*DNBShouldCancelCallback)(void *);
void DNBInitialize();
@ -226,5 +232,6 @@ const char *DNBStateAsString(nub_state_t state);
nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
size_t resolved_path_size);
bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch);
/// \return the iOSSupportVersion of the host OS.
std::string DNBGetMacCatalystVersionString();
#endif

View File

@ -341,6 +341,7 @@ enum DNBProfileDataScanType {
(1 << 8), // Assume eProfileMemory, get Anonymous memory as well.
eProfileEnergy = (1 << 9),
eProfileEnergyCPUCap = (1 << 10),
eProfileMemoryCap = (1 << 15),

View File

@ -489,8 +489,10 @@ const char *MachException::Name(exception_type_t exc_type) {
return "EXC_MACH_SYSCALL";
case EXC_RPC_ALERT:
return "EXC_RPC_ALERT";
#ifdef EXC_CRASH
case EXC_CRASH:
return "EXC_CRASH";
#endif
case EXC_RESOURCE:
return "EXC_RESOURCE";
#ifdef EXC_GUARD

View File

@ -116,6 +116,7 @@ public:
#endif
static bool GetOSVersionNumbers(uint64_t *major, uint64_t *minor,
uint64_t *patch);
static std::string GetMacCatalystVersionString();
#ifdef WITH_BKS
static void BKSCleanupAfterAttach(const void *attach_token,
DNBError &err_str);
@ -233,12 +234,13 @@ public:
GetDeploymentInfo(const struct load_command&, uint64_t load_command_address,
uint32_t& major_version, uint32_t& minor_version,
uint32_t& patch_version);
bool GetMachOInformationFromMemory(nub_addr_t mach_o_header_addr,
bool GetMachOInformationFromMemory(uint32_t platform,
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(
uint32_t 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);
@ -425,6 +427,7 @@ private:
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);
uint32_t (*m_dyld_process_info_get_platform)(void *info);
};
#endif // __MachProcess_h__

View File

@ -44,6 +44,30 @@
#include "CFBundle.h"
#include "CFString.h"
#ifndef PLATFORM_BRIDGEOS
#define PLATFORM_BRIDGEOS 5
#endif
#ifndef PLATFORM_MACCATALYST
#define PLATFORM_MACCATALYST 6
#endif
#ifndef PLATFORM_IOSSIMULATOR
#define PLATFORM_IOSSIMULATOR 7
#endif
#ifndef PLATFORM_TVOSSIMULATOR
#define PLATFORM_TVOSSIMULATOR 8
#endif
#ifndef PLATFORM_WATCHOSSIMULATOR
#define PLATFORM_WATCHOSSIMULATOR 9
#endif
#ifndef PLATFORM_DRIVERKIT
#define PLATFORM_DRIVERKIT 10
#endif
#ifdef WITH_SPRINGBOARD
#include <CoreFoundation/CoreFoundation.h>
@ -480,6 +504,8 @@ MachProcess::MachProcess()
(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");
m_dyld_process_info_get_platform = (uint32_t (*)(void *info))dlsym(
RTLD_DEFAULT, "_dyld_process_info_get_platform");
DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
}
@ -600,11 +626,6 @@ const char *MachProcess::GetDeploymentInfo(const struct load_command& lc,
}
}
#if defined (LC_BUILD_VERSION)
#ifndef PLATFORM_IOSSIMULATOR
#define PLATFORM_IOSSIMULATOR 7
#define PLATFORM_TVOSSIMULATOR 8
#define PLATFORM_WATCHOSSIMULATOR 9
#endif
if (cmd == LC_BUILD_VERSION) {
struct build_version_command build_vers;
if (ReadMemory(load_command_address, sizeof(struct build_version_command),
@ -618,6 +639,8 @@ const char *MachProcess::GetDeploymentInfo(const struct load_command& lc,
switch (build_vers.platform) {
case PLATFORM_MACOS:
return "macosx";
case PLATFORM_MACCATALYST:
return "maccatalyst";
case PLATFORM_IOS:
case PLATFORM_IOSSIMULATOR:
return "ios";
@ -629,6 +652,8 @@ const char *MachProcess::GetDeploymentInfo(const struct load_command& lc,
return "watchos";
case PLATFORM_BRIDGEOS:
return "bridgeos";
case PLATFORM_DRIVERKIT:
return "driverkit";
}
}
#endif
@ -643,7 +668,7 @@ const char *MachProcess::GetDeploymentInfo(const struct load_command& lc,
// commands.
bool MachProcess::GetMachOInformationFromMemory(
nub_addr_t mach_o_header_addr, int wordsize,
uint32_t dyld_platform, nub_addr_t mach_o_header_addr, int wordsize,
struct mach_o_information &inf) {
uint64_t load_cmds_p;
if (wordsize == 4) {
@ -735,17 +760,42 @@ bool MachProcess::GetMachOInformationFromMemory(
}
uint32_t major_version, minor_version, patch_version;
if (const char *platform = GetDeploymentInfo(lc, load_cmds_p,
major_version, minor_version,
patch_version)) {
inf.min_version_os_name = platform;
inf.min_version_os_version = "";
inf.min_version_os_version += std::to_string(major_version);
inf.min_version_os_version += ".";
inf.min_version_os_version += std::to_string(minor_version);
if (patch_version != 0) {
if (const char *lc_platform = GetDeploymentInfo(
lc, load_cmds_p, major_version, minor_version, patch_version)) {
// APPLE INTERNAL: macCatalyst support
// This handles two special cases:
// 1. Zippered frameworks have two deployment info load commands.
// Make sure to select the requested one.
// 2. The xctest binary is a pure macOS binary but is launched with
// DYLD_FORCE_PLATFORM=6.
if (dyld_platform == PLATFORM_MACCATALYST &&
inf.mach_header.filetype == MH_EXECUTE &&
inf.min_version_os_name.empty() &&
(strcmp("macosx", lc_platform) == 0)) {
// DYLD says this *is* a macCatalyst process. If we haven't
// parsed any load commands, transform a macOS load command
// into a generic macCatalyst load command. It will be
// overwritten by a more specific one if there is one. This
// is only done for the main executable. It is perfectly fine
// for a macCatalyst binary to link against a macOS-only framework.
inf.min_version_os_name = "maccatalyst";
inf.min_version_os_version = GetMacCatalystVersionString();
} else if (dyld_platform != PLATFORM_MACCATALYST &&
inf.min_version_os_name == "macosx") {
// This is a zippered binary and the process is not running as
// PLATFORM_MACCATALYST. Stick with the macosx load command
// that we've already processed, ignore this one, which is
// presumed to be a PLATFORM_MACCATALYST one.
} else {
inf.min_version_os_name = lc_platform;
inf.min_version_os_version = "";
inf.min_version_os_version += std::to_string(major_version);
inf.min_version_os_version += ".";
inf.min_version_os_version += std::to_string(patch_version);
inf.min_version_os_version += std::to_string(minor_version);
if (patch_version != 0) {
inf.min_version_os_version += ".";
inf.min_version_os_version += std::to_string(patch_version);
}
}
}
@ -941,7 +991,10 @@ JSONGenerator::ObjectSP MachProcess::GetLoadedDynamicLibrariesInfos(
//// Second, read the mach header / load commands for all the dylibs
for (size_t i = 0; i < image_count; i++) {
if (!GetMachOInformationFromMemory(image_infos[i].load_address,
// The SPI to provide platform is not available on older systems.
uint32_t platform = 0;
if (!GetMachOInformationFromMemory(platform,
image_infos[i].load_address,
pointer_size,
image_infos[i].macho_info)) {
return reply_sp;
@ -972,8 +1025,9 @@ struct dyld_process_cache_info {
// binary_image_information' - call
// GetMachOInformationFromMemory to fill in the mach-o header/load command
// details.
void MachProcess::GetAllLoadedBinariesViaDYLDSPI(
uint32_t MachProcess::GetAllLoadedBinariesViaDYLDSPI(
std::vector<struct binary_image_information> &image_infos) {
uint32_t platform = 0;
kern_return_t kern_ret;
if (m_dyld_process_info_create) {
dyld_process_info info =
@ -988,9 +1042,12 @@ void MachProcess::GetAllLoadedBinariesViaDYLDSPI(
image.load_address = mach_header_addr;
image_infos.push_back(image);
});
if (m_dyld_process_info_get_platform)
platform = m_dyld_process_info_get_platform(info);
m_dyld_process_info_release(info);
}
}
return platform;
}
// Fetch information about all shared libraries using the dyld SPIs that exist
@ -1011,10 +1068,11 @@ MachProcess::GetAllLoadedLibrariesInfos(nub_process_t pid) {
pointer_size = 8;
std::vector<struct binary_image_information> image_infos;
GetAllLoadedBinariesViaDYLDSPI(image_infos);
uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(image_infos);
const size_t image_count = image_infos.size();
for (size_t i = 0; i < image_count; i++) {
GetMachOInformationFromMemory(image_infos[i].load_address, pointer_size,
GetMachOInformationFromMemory(platform,
image_infos[i].load_address, pointer_size,
image_infos[i].macho_info);
}
return FormatDynamicLibrariesIntoJSON(image_infos);
@ -1040,7 +1098,7 @@ JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses(
pointer_size = 8;
std::vector<struct binary_image_information> all_image_infos;
GetAllLoadedBinariesViaDYLDSPI(all_image_infos);
uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(all_image_infos);
std::vector<struct binary_image_information> image_infos;
const size_t macho_addresses_count = macho_addresses.size();
@ -1055,7 +1113,8 @@ JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses(
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,
GetMachOInformationFromMemory(platform,
image_infos[i].load_address, pointer_size,
image_infos[i].macho_info);
}
return FormatDynamicLibrariesIntoJSON(image_infos);
@ -2543,6 +2602,18 @@ bool MachProcess::GetOSVersionNumbers(uint64_t *major, uint64_t *minor,
#endif
}
std::string MachProcess::GetMacCatalystVersionString() {
@autoreleasepool {
NSDictionary *version_info =
[NSDictionary dictionaryWithContentsOfFile:
@"/System/Library/CoreServices/SystemVersion.plist"];
NSString *version_value = [version_info objectForKey: @"iOSSupportVersion"];
if (const char *version_str = [version_value UTF8String])
return version_str;
}
return {};
}
// Do the process specific setup for attach. If this returns NULL, then there's
// no
// platform specific stuff to be done to wait for the attach. If you get

View File

@ -12,6 +12,7 @@
#include "MachThreadList.h"
#include "DNB.h"
#include "DNBLog.h"
#include "DNBThreadResumeActions.h"
#include "MachProcess.h"
@ -278,8 +279,12 @@ MachThreadList::UpdateThreadList(MachProcess *process, bool update,
#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
if (m_is_64_bit)
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
else
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
else {
if (process->GetCPUType() == CPU_TYPE_ARM64_32)
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32);
else
DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
}
#endif
}

View File

@ -69,6 +69,14 @@ void DNBArchMachARM64::Initialize() {
// Register this arch plug-in with the main protocol class
DNBArchProtocol::RegisterArchPlugin(arch_plugin_info);
DNBArchPluginInfo arch_plugin_info_32 = {
CPU_TYPE_ARM64_32, DNBArchMachARM64::Create,
DNBArchMachARM64::GetRegisterSetInfo,
DNBArchMachARM64::SoftwareBreakpointOpcode};
// Register this arch plug-in with the main protocol class
DNBArchProtocol::RegisterArchPlugin(arch_plugin_info_32);
}
DNBArchProtocol *DNBArchMachARM64::Create(MachThread *thread) {

View File

@ -1287,6 +1287,9 @@ static cpu_type_t best_guess_cpu_type() {
if (sizeof(char *) == 8) {
return CPU_TYPE_ARM64;
} else {
#if defined (__ARM64_ARCH_8_32__)
return CPU_TYPE_ARM64_32;
#endif
return CPU_TYPE_ARM;
}
#elif defined(__i386__) || defined(__x86_64__)
@ -4557,6 +4560,8 @@ static const char *GetArchName(const uint32_t cputype,
break;
case CPU_TYPE_ARM64:
return "arm64";
case CPU_TYPE_ARM64_32:
return "arm64_32";
case CPU_TYPE_I386:
return "i386";
case CPU_TYPE_X86_64:
@ -4590,6 +4595,10 @@ static bool GetHostCPUType(uint32_t &cputype, uint32_t &cpusubtype,
g_host_cputype |= CPU_ARCH_ABI64;
}
}
#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
if (g_host_cputype == CPU_TYPE_ARM64 && sizeof (void*) == 4)
g_host_cputype = CPU_TYPE_ARM64_32;
#endif
}
len = sizeof(uint32_t);
@ -4599,6 +4608,16 @@ static bool GetHostCPUType(uint32_t &cputype, uint32_t &cpusubtype,
g_host_cpusubtype == CPU_SUBTYPE_486)
g_host_cpusubtype = CPU_SUBTYPE_X86_64_ALL;
}
#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
// on arm64_32 devices, the machine's native cpu type is
// CPU_TYPE_ARM64 and subtype is 2 indicating arm64e.
// But we change the cputype to CPU_TYPE_ARM64_32 because
// the user processes are all ILP32 processes today.
// We also need to rewrite the cpusubtype so we vend
// a valid cputype + cpusubtype combination.
if (g_host_cputype == CPU_TYPE_ARM64_32)
g_host_cpusubtype = CPU_SUBTYPE_ARM64_32_V8;
#endif
}
cputype = g_host_cputype;
@ -4623,7 +4642,8 @@ rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) {
// 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 (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64
|| cputype == CPU_TYPE_ARM64_32) {
#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
strm << "ostype:tvos;";
#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
@ -4660,6 +4680,12 @@ rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) {
strm << ";";
}
std::string maccatalyst_version = DNBGetMacCatalystVersionString();
if (!maccatalyst_version.empty() &&
std::all_of(maccatalyst_version.begin(), maccatalyst_version.end(),
[](char c) { return (c >= '0' && c <= '9') || c == '.'; }))
strm << "maccatalyst_version:" << maccatalyst_version << ";";
#if defined(__LITTLE_ENDIAN__)
strm << "endian:little;";
#elif defined(__BIG_ENDIAN__)
@ -6034,6 +6060,17 @@ rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {
cpusubtype = 12; // CPU_SUBTYPE_ARM_V7K
}
}
#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
// on arm64_32 devices, the machine's native cpu type is
// CPU_TYPE_ARM64 and subtype is 2 indicating arm64e.
// But we change the cputype to CPU_TYPE_ARM64_32 because
// the user processes are all ILP32 processes today.
// We also need to rewrite the cpusubtype so we vend
// a valid cputype + cpusubtype combination.
if (cputype == CPU_TYPE_ARM64_32 && cpusubtype == 2)
cpusubtype = CPU_SUBTYPE_ARM64_32_V8;
#endif
rep << "cpusubtype:" << std::hex << cpusubtype << ';';
}
@ -6080,7 +6117,8 @@ rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {
// 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 (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64
|| cputype == CPU_TYPE_ARM64_32) {
#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
rep << "ostype:tvos;";
#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1