[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
This commit is contained in:
Jonas Devlieghere 2022-07-27 14:30:39 -07:00
parent 98647330bf
commit ecda408178
No known key found for this signature in database
GPG Key ID: 49CC0BD90FDEED4D
5 changed files with 93 additions and 8 deletions

View File

@ -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):

View File

@ -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<bool> 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<std::string> 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];

View File

@ -0,0 +1,4 @@
C_SOURCES := main.c
override ARCH = x86_64
include Makefile.rules

View File

@ -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))

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
int i = 0; // Set a breakpoint here
return i;
}