From ecda408178fc6486ea568263cdda6624f5bcb8c7 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 27 Jul 2022 14:30:39 -0700 Subject: [PATCH] [lldb] Read from the Rosetta shared cache with Xcode 14 Xcode 14 no longer puts the Rosetta expanded shared cache in a directory named "16.0". Instead, it includes the real version number (e.g. 13.0), the build string and the architecture, similar to the device support directory names for iOS, tvOS and watchOS. Currently, when there are multiple directories, we might end up picking the wrong one in GetSDKDirectoryForCurrentOSVersion. The problem is that without the build string we have no way to differentiate between multiple directories with the same version number. This patch fixes the problem by using GetOSBuildString which, as the name implies, returns the build string if known. This also adds a test for Rosetta debugging on Apple Silicon. Depending on whether the Rosetta expanded shared cache is present, the test ensures that there is or isn't a diagnostic about reading out of memory. rdar://97576121 Differential revision: https://reviews.llvm.org/D130540 --- lldb/packages/Python/lldbsuite/test/decorators.py | 11 +++++ .../Platform/MacOSX/PlatformDarwinDevice.cpp | 25 ++++++---- lldb/test/API/macosx/rosetta/Makefile | 4 ++ lldb/test/API/macosx/rosetta/TestRosetta.py | 55 ++++++++++++++++++++++ lldb/test/API/macosx/rosetta/main.c | 6 +++ 5 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/macosx/rosetta/Makefile create mode 100644 lldb/test/API/macosx/rosetta/TestRosetta.py create mode 100644 lldb/test/API/macosx/rosetta/main.c diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 191a1e0..6d6591c 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -698,6 +698,17 @@ def skipIfTargetAndroid(bugnumber=None, api_levels=None, archs=None): archs), bugnumber) +def skipUnlessAppleSilicon(func): + """Decorate the item to skip tests unless running on Apple Silicon.""" + def not_apple_silicon(test): + if platform.system() != 'Darwin' or test.getArchitecture() not in [ + 'arm64', 'arm64e' + ]: + return "Test only runs on Apple Silicon" + return None + + return skipTestIfFn(not_apple_silicon)(func) + def skipUnlessSupportedTypeAttribute(attr): """Decorate the item to skip test unless Clang supports type __attribute__(attr).""" def compiler_doesnt_support_struct_attribute(self): diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp index 7feaef9..f4f866b 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp @@ -148,11 +148,20 @@ PlatformDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { uint32_t i; if (UpdateSDKDirectoryInfosIfNeeded()) { const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); - - // Check to see if the user specified a build string. If they did, then be - // sure to match it. std::vector check_sdk_info(num_sdk_infos, true); - ConstString build(m_sdk_build); + + // Prefer the user SDK build string. + ConstString build = GetSDKBuild(); + + // Fall back to the platform's build string. + if (!build) { + if (llvm::Optional os_build_str = GetOSBuildString()) { + build = ConstString(*os_build_str); + } + } + + // If we have a build string, only check platforms for which the build + // string matches. if (build) { for (i = 0; i < num_sdk_infos; ++i) check_sdk_info[i] = m_sdk_directory_infos[i].build == build; @@ -163,14 +172,14 @@ PlatformDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { llvm::VersionTuple version = GetOSVersion(); if (!version.empty()) { if (UpdateSDKDirectoryInfosIfNeeded()) { - // First try for an exact match of major, minor and update + // First try for an exact match of major, minor and update. for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { if (m_sdk_directory_infos[i].version == version) return &m_sdk_directory_infos[i]; } } - // First try for an exact match of major and minor + // Try for an exact match of major and minor. for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { if (m_sdk_directory_infos[i].version.getMajor() == @@ -181,7 +190,7 @@ PlatformDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { } } } - // Lastly try to match of major version only.. + // Lastly try to match of major version only. for (i = 0; i < num_sdk_infos; ++i) { if (check_sdk_info[i]) { if (m_sdk_directory_infos[i].version.getMajor() == @@ -192,7 +201,7 @@ PlatformDarwinDevice::GetSDKDirectoryForCurrentOSVersion() { } } } else if (build) { - // No version, just a build number, search for the first one that matches + // No version, just a build number, return the first one that matches. for (i = 0; i < num_sdk_infos; ++i) if (check_sdk_info[i]) return &m_sdk_directory_infos[i]; diff --git a/lldb/test/API/macosx/rosetta/Makefile b/lldb/test/API/macosx/rosetta/Makefile new file mode 100644 index 0000000..8dd53c8 --- /dev/null +++ b/lldb/test/API/macosx/rosetta/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +override ARCH = x86_64 + +include Makefile.rules diff --git a/lldb/test/API/macosx/rosetta/TestRosetta.py b/lldb/test/API/macosx/rosetta/TestRosetta.py new file mode 100644 index 0000000..628d265 --- /dev/null +++ b/lldb/test/API/macosx/rosetta/TestRosetta.py @@ -0,0 +1,55 @@ +import re +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +def get_os_version(): + try: + os_version_str = subprocess.check_output(["sysctl", "kern.osversion" + ]).decode('utf-8') + except subprocess.CalledProcessError: + return None + m = re.match(r'kern\.osversion: (\w+)', os_version_str) + if m: + return m.group(1) + return None + + +def has_rosetta_shared_cache(os_version): + if not os_version: + return False + macos_device_support = os.path.join(os.path.expanduser("~"), 'Library', + 'Developer', 'Xcode', + 'macOS DeviceSupport') + for _, subdirs, _ in os.walk(macos_device_support): + for subdir in subdirs: + if os_version in subdir: + return True + return False + + +class TestRosetta(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessAppleSilicon + def test_rosetta(self): + """There can be many tests in a test case - describe this test here.""" + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + + broadcaster = self.dbg.GetBroadcaster() + listener = lldbutil.start_listening_from( + broadcaster, lldb.SBDebugger.eBroadcastBitWarning) + + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", self.main_source_file) + + event = lldb.SBEvent() + os_version = get_os_version() + if not has_rosetta_shared_cache(os_version): + self.assertTrue(listener.GetNextEvent(event)) + else: + self.assertFalse(listener.GetNextEvent(event)) diff --git a/lldb/test/API/macosx/rosetta/main.c b/lldb/test/API/macosx/rosetta/main.c new file mode 100644 index 0000000..ca9c416 --- /dev/null +++ b/lldb/test/API/macosx/rosetta/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + int i = 0; // Set a breakpoint here + return i; +} -- 2.7.4