(file_path, max_attempts))
return read_file_on_target(testcase, file_path)
+
+def packetlog_get_process_info(log):
+ """parse a gdb-remote packet log file and extract the response to qProcessInfo"""
+ process_info = dict()
+ with open(log, "r") as logfile:
+ process_info_ostype = None
+ expect_process_info_response = False
+ for line in logfile:
+ if expect_process_info_response:
+ for pair in line.split(';'):
+ keyval = pair.split(':')
+ if len(keyval) == 2:
+ process_info[keyval[0]] = keyval[1]
+ break
+ if 'send packet: $qProcessInfo#' in line:
+ expect_process_info_response = True
+ return process_info
+
+def packetlog_get_dylib_info(log):
+ """parse a gdb-remote packet log file and extract the *last* response to jGetLoadedDynamicLibrariesInfos"""
+ import json
+ dylib_info = None
+ with open(log, "r") as logfile:
+ dylib_info = None
+ expect_dylib_info_response = False
+ for line in logfile:
+ if expect_dylib_info_response:
+ while line[0] != '$':
+ line = line[1:]
+ line = line[1:]
+ # Unescape '}'.
+ dylib_info = json.loads(line.replace('}]','}')[:-4])
+ expect_dylib_info_response = False
+ if 'send packet: $jGetLoadedDynamicLibrariesInfos:{' in line:
+ expect_dylib_info_response = True
+
+ return dylib_info
--- /dev/null
+C_SOURCES := main.c
+
+TRIPLE := $(ARCH)-apple-ios13.0-macabi
+CFLAGS_EXTRAS := -target $(TRIPLE)
+
+# FIXME: rdar://problem/54986190
+# There is a Clang driver change missing on llvm.org.
+override CC=xcrun clang
+
+include Makefile.rules
--- /dev/null
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+import os
+import unittest2
+
+
+class TestMacCatalyst(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIf(macos_version=["<", "10.15"])
+ @skipUnlessDarwin
+ @skipIfDarwinEmbedded
+ @skipIfReproducer # This is hitting https://bugs.python.org/issue22393
+ def test_macabi(self):
+ """Test the x86_64-apple-ios-macabi target linked against a macos dylib"""
+ self.build()
+ log = self.getBuildArtifact('packets.log')
+ self.expect("log enable gdb-remote packets -f "+log)
+ lldbutil.run_to_source_breakpoint(self, "break here",
+ lldb.SBFileSpec('main.c'))
+ self.expect("image list -t -b",
+ patterns=[self.getArchitecture() +
+ r'.*-apple-ios.*-macabi a\.out'])
+ self.expect("fr v s", "Hello macCatalyst")
+ self.expect("p s", "Hello macCatalyst")
+ self.check_debugserver(log)
+
+ def check_debugserver(self, log):
+ """scan the debugserver packet log"""
+ process_info = lldbutil.packetlog_get_process_info(log)
+ self.assertTrue('ostype' in process_info)
+ self.assertEquals(process_info['ostype'], 'maccatalyst')
+
+ aout_info = None
+ dylib_info = lldbutil.packetlog_get_dylib_info(log)
+ for image in dylib_info['images']:
+ if image['pathname'].endswith('a.out'):
+ aout_info = image
+ self.assertTrue(aout_info)
+ self.assertEquals(aout_info['min_version_os_name'], 'maccatalyst')
--- /dev/null
+int main() {
+ const char *s = "Hello macCatalyst!";
+ return 0; // break here
+}
C_SOURCES := main.c
LD_EXTRAS := -L. -lfoo
-TRIPLE := x86_64-apple-ios13.0-macabi
+TRIPLE := $(ARCH)-apple-ios13.0-macabi
CFLAGS_EXTRAS := -target $(TRIPLE)
+# FIXME: rdar://problem/54986190
+override CC=xcrun clang
+
all: libfoo.dylib a.out
libfoo.dylib: foo.c
--- /dev/null
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+import os
+import unittest2
+
+
+class TestMacCatalystAppWithMacOSFramework(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIf(macos_version=["<", "10.15"])
+ @skipUnlessDarwin
+ @skipIfDarwinEmbedded
+ # There is a Clang driver change missing on llvm.org.
+ @expectedFailureAll(bugnumber="rdar://problem/54986190>")
+ @skipIfReproducer # This is hitting https://bugs.python.org/issue22393
+ def test(self):
+ """Test the x86_64-apple-ios-macabi target linked against a macos dylib"""
+ self.build()
+ log = self.getBuildArtifact('packets.log')
+ self.expect("log enable gdb-remote packets -f "+log)
+ lldbutil.run_to_source_breakpoint(self, "break here",
+ lldb.SBFileSpec('main.c'))
+ arch = self.getArchitecture()
+ self.expect("image list -t -b",
+ patterns=[arch + r'.*-apple-ios.*-macabi a\.out',
+ arch + r'.*-apple-macosx.* libfoo.dylib[^(]'])
+ self.expect("fr v s", "Hello macCatalyst")
+ self.expect("p s", "Hello macCatalyst")
+ self.check_debugserver(log)
+
+ def check_debugserver(self, log):
+ """scan the debugserver packet log"""
+ process_info = lldbutil.packetlog_get_process_info(log)
+ self.assertTrue('ostype' in process_info)
+ self.assertEquals(process_info['ostype'], 'maccatalyst')
+
+ aout_info = None
+ libfoo_info = None
+ dylib_info = lldbutil.packetlog_get_dylib_info(log)
+ for image in dylib_info['images']:
+ if image['pathname'].endswith('a.out'):
+ aout_info = image
+ if image['pathname'].endswith('libfoo.dylib'):
+ libfoo_info = image
+ self.assertTrue(aout_info)
+ self.assertTrue(libfoo_info)
+ self.assertEquals(aout_info['min_version_os_name'], 'maccatalyst')
+ self.assertEquals(libfoo_info['min_version_os_name'], 'macosx')
#include "foo.h"
int main() {
- const char *s = "Hello MacABI!";
+ const char *s = "Hello macCatalyst!";
return foo(); // break here
}
+++ /dev/null
-import lldb
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.decorators import *
-import lldbsuite.test.lldbutil as lldbutil
-import os
-import unittest2
-
-
-class TestMacABImacOSFramework(TestBase):
-
- mydir = TestBase.compute_mydir(__file__)
-
- @skipIf(macos_version=["<", "10.15"])
- @skipUnlessDarwin
- @skipIfDarwinEmbedded
- # There is a Clang driver change missing on llvm.org.
- @expectedFailureAll(bugnumber="rdar://problem/54986190>")
- @skipIfReproducer # This is hitting https://bugs.python.org/issue22393
- def test_macabi(self):
- """Test the x86_64-apple-ios-macabi target linked against a macos dylib"""
- self.build()
- lldbutil.run_to_source_breakpoint(self, "break here",
- lldb.SBFileSpec('main.c'))
- self.expect("image list -t -b",
- patterns=["x86_64.*-apple-ios.*-macabi a\.out",
- "x86_64.*-apple-macosx.* libfoo.dylib[^(]"])
- self.expect("fr v s", "Hello MacABI")
- self.expect("p s", "Hello MacABI")
def check_debugserver(self, log, expected_platform, expected_version):
"""scan the debugserver packet log"""
- logfile = open(log, "r")
- dylib_info = None
- process_info_ostype = None
- expect_dylib_info_response = False
- expect_process_info_response = False
- for line in logfile:
- if expect_dylib_info_response:
- while line[0] != '$':
- line = line[1:]
- line = line[1:]
- # Unescape '}'.
- dylib_info = json.loads(line.replace('}]','}')[:-4])
- expect_dylib_info_response = False
- if 'send packet: $jGetLoadedDynamicLibrariesInfos:{' in line:
- expect_dylib_info_response = True
- if expect_process_info_response:
- for pair in line.split(';'):
- keyval = pair.split(':')
- if len(keyval) == 2 and keyval[0] == 'ostype':
- process_info_ostype = keyval[1]
- if 'send packet: $qProcessInfo#' in line:
- expect_process_info_response = True
-
- self.assertEquals(process_info_ostype, expected_platform)
+ process_info = lldbutil.packetlog_get_process_info(log)
+ self.assertTrue('ostype' in process_info)
+ self.assertEquals(process_info['ostype'], expected_platform)
+ dylib_info = lldbutil.packetlog_get_dylib_info(log)
self.assertTrue(dylib_info)
aout_info = None
for image in dylib_info['images']:
return false;
}
-const char *DNBGetDeploymentInfo(nub_process_t pid,
- const struct load_command& lc,
+const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable,
+ const struct load_command &lc,
uint64_t load_command_address,
- uint32_t& major_version,
- uint32_t& minor_version,
- uint32_t& patch_version) {
+ uint32_t &major_version,
+ uint32_t &minor_version,
+ uint32_t &patch_version) {
MachProcessSP procSP;
if (GetProcessSP(pid, procSP)) {
// FIXME: This doesn't return the correct result when xctest (a
// macOS binary) is loaded with the macCatalyst dyld platform
// override. The image info corrects for this, but qProcessInfo
// will return what is in the binary.
- auto info = procSP->GetDeploymentInfo(lc, load_command_address);
+ auto info =
+ procSP->GetDeploymentInfo(lc, load_command_address, is_executable);
major_version = info.major_version;
minor_version = info.minor_version;
patch_version = info.patch_version;
return nullptr;
}
-
// Get the current shared library information for a process. Only return
// the shared libraries that have changed since the last shared library
// state changed event if only_changed is non-zero.
nub_size_t
DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
DNBExecutableImageInfo **image_infos) DNB_EXPORT;
-const char *DNBGetDeploymentInfo(nub_process_t pid,
- const struct load_command& lc,
+const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable,
+ const struct load_command &lc,
uint64_t load_command_address,
- uint32_t& major_version,
- uint32_t& minor_version,
- uint32_t& patch_version);
+ uint32_t &major_version,
+ uint32_t &minor_version,
+ uint32_t &patch_version);
nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
DNBCallbackNameToAddress callback,
void *baton) DNB_EXPORT;
uint32_t patch_version = 0;
};
DeploymentInfo GetDeploymentInfo(const struct load_command &,
- uint64_t load_command_address);
+ uint64_t load_command_address,
+ bool is_executable);
static const char *GetPlatformString(unsigned char platform);
bool GetMachOInformationFromMemory(uint32_t platform,
nub_addr_t mach_o_header_addr,
struct mach_o_information &inf);
JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON(
const std::vector<struct binary_image_information> &image_infos);
- uint32_t GetAllLoadedBinariesViaDYLDSPI(
+ /// Get the runtime platform from DYLD via SPI.
+ uint32_t GetProcessPlatformViaDYLDSPI();
+ /// 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 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);
typedef bool (*CallOpenApplicationFunction)(NSString *bundleIDNSStr,
NSDictionary *options,
DNBError &error, pid_t *return_pid);
+
// This function runs the BKSSystemService (or FBSSystemService) method
// openApplication:options:clientPort:withResult,
// messaging the app passed in bundleIDNSStr.
#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
#endif
+
MachProcess::MachProcess()
: m_pid(0), m_cpu_type(0), m_child_stdin(-1), m_child_stdout(-1),
m_child_stderr(-1), m_path(), m_args(), m_task(this),
MachProcess::DeploymentInfo
MachProcess::GetDeploymentInfo(const struct load_command &lc,
- uint64_t load_command_address) {
+ uint64_t load_command_address,
+ bool is_executable) {
DeploymentInfo info;
uint32_t cmd = lc.cmd & ~LC_REQ_DYLD;
+
// Handle the older LC_VERSION load commands, which don't
// distinguish between simulator and real hardware.
auto handle_version_min = [&](char platform) {
// unambiguous LC_BUILD_VERSION load commands.
#endif
};
+
switch (cmd) {
case LC_VERSION_MIN_IPHONEOS:
handle_version_min(PLATFORM_IOS);
}
#endif
}
+
+ // The xctest binary is a pure macOS binary but is launched with
+ // DYLD_FORCE_PLATFORM=6. In that case, force the platform to
+ // macCatalyst and use the macCatalyst version of the host OS
+ // instead of the macOS deployment target.
+ if (is_executable && GetProcessPlatformViaDYLDSPI() == PLATFORM_MACCATALYST) {
+ info.platform = PLATFORM_MACCATALYST;
+ std::string catalyst_version = GetMacCatalystVersionString();
+ const char *major = catalyst_version.c_str();
+ char *minor = nullptr;
+ char *patch = nullptr;
+ info.major_version = std::strtoul(major, &minor, 10);
+ info.minor_version = 0;
+ info.patch_version = 0;
+ if (minor && *minor == '.') {
+ info.minor_version = std::strtoul(++minor, &patch, 10);
+ if (patch && *patch == '.')
+ info.patch_version = std::strtoul(++patch, nullptr, 10);
+ }
+ }
+
return info;
}
sizeof(struct uuid_command))
uuid_copy(inf.uuid, uuidcmd.uuid);
}
- if (DeploymentInfo deployment_info = GetDeploymentInfo(lc, load_cmds_p)) {
+ if (DeploymentInfo deployment_info = GetDeploymentInfo(
+ lc, load_cmds_p, inf.mach_header.filetype == MH_EXECUTE)) {
const char *lc_platform = GetPlatformString(deployment_info.platform);
- // macCatalyst support.
- //
- // This handles two special cases:
- //
- // 1. Frameworks that have both a PLATFORM_MACOS and a
- // PLATFORM_MACCATALYST load command. 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 binary with both PLATFORM_MACOS and
- // PLATFORM_MACCATALYST load commands 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
+ if (dyld_platform != PLATFORM_MACCATALYST &&
+ inf.min_version_os_name == "macosx") {
+ // macCatalyst support.
+ //
+ // This the special case of "zippered" frameworks that have both
+ // a PLATFORM_MACOS and a PLATFORM_MACCATALYST load command.
+ //
+ // When we are in this block, this is a binary with both
+ // PLATFORM_MACOS and PLATFORM_MACCATALYST load commands 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;
return reply_sp;
}
-// From dyld SPI header dyld_process_info.h
+/// 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
+ /// UUID of cache used by process.
+ uuid_t cacheUUID;
+ /// Load address of dyld shared cache.
+ uint64_t cacheBaseAddress;
+ /// Process is running without a dyld cache.
+ bool noCache;
+ /// Process is using a private copy of its dyld cache.
+ bool privateCache;
};
-// 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.
-uint32_t MachProcess::GetAllLoadedBinariesViaDYLDSPI(
- std::vector<struct binary_image_information> &image_infos) {
+uint32_t MachProcess::GetProcessPlatformViaDYLDSPI() {
+ kern_return_t kern_ret;
uint32_t platform = 0;
+ if (m_dyld_process_info_create) {
+ dyld_process_info info =
+ m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret);
+ if (info) {
+ if (m_dyld_process_info_get_platform)
+ platform = m_dyld_process_info_get_platform(info);
+ m_dyld_process_info_release(info);
+ }
+ }
+ return platform;
+}
+
+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 =
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
pointer_size = 8;
std::vector<struct binary_image_information> image_infos;
- uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(image_infos);
+ GetAllLoadedBinariesViaDYLDSPI(image_infos);
+ uint32_t platform = GetProcessPlatformViaDYLDSPI();
const size_t image_count = image_infos.size();
for (size_t i = 0; i < image_count; i++) {
GetMachOInformationFromMemory(platform,
pointer_size = 8;
std::vector<struct binary_image_information> all_image_infos;
- uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(all_image_infos);
+ GetAllLoadedBinariesViaDYLDSPI(all_image_infos);
+ uint32_t platform = GetProcessPlatformViaDYLDSPI();
std::vector<struct binary_image_information> image_infos;
const size_t macho_addresses_count = macho_addresses.size();
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 =
DNBProcessMemoryRead(pid, load_command_addr, sizeof(lc), &lc);
(void)bytes_read;
+ bool is_executable = true;
uint32_t major_version, minor_version, patch_version;
- auto *platform = DNBGetDeploymentInfo(pid, lc, load_command_addr,
- major_version, minor_version,
- patch_version);
+ auto *platform =
+ DNBGetDeploymentInfo(pid, is_executable, lc, load_command_addr,
+ major_version, minor_version, patch_version);
if (platform) {
os_handled = true;
rep << "ostype:" << platform << ";";