Skip to content

Commit 98e50a7

Browse files
committed
[lldb] Honor the CPU type & subtype when launching on macOS
Honor the CPU type (and subtype) when launching the inferior on macOS. Part of this functionality was thought to be no longer needed and removed in 85bd436, however it's still needed, for example to launch binaries under Rosetta 2 on Apple Silicon. This patch will use posix_spawnattr_setarchpref_np if available and fallback to posix_spawnattr_setbinpref_np if not. Differential revision: https://reviews.llvm.org/D95922
1 parent 4dc08cc commit 98e50a7

File tree

7 files changed

+157
-1
lines changed

7 files changed

+157
-1
lines changed

lldb/source/Host/macosx/objcxx/Host.mm

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <asl.h>
4040
#include <crt_externs.h>
41+
#include <dlfcn.h>
4142
#include <grp.h>
4243
#include <libproc.h>
4344
#include <pwd.h>
@@ -1108,6 +1109,55 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
11081109
}
11091110
}
11101111

1112+
// Don't set the binpref if a shell was provided. After all, that's only
1113+
// going to affect what version of the shell is launched, not what fork of
1114+
// the binary is launched. We insert "arch --arch <ARCH> as part of the
1115+
// shell invocation to do that job on OSX.
1116+
if (launch_info.GetShell() == FileSpec()) {
1117+
const ArchSpec &arch_spec = launch_info.GetArchitecture();
1118+
cpu_type_t cpu_type = arch_spec.GetMachOCPUType();
1119+
cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType();
1120+
const bool set_cpu_type =
1121+
cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) &&
1122+
cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE);
1123+
const bool set_cpu_subtype =
1124+
cpu_subtype != 0 &&
1125+
cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) &&
1126+
cpu_subtype != CPU_SUBTYPE_X86_64_H;
1127+
if (set_cpu_type) {
1128+
size_t ocount = 0;
1129+
typedef int (*posix_spawnattr_setarchpref_np_t)(
1130+
posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *);
1131+
posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =
1132+
(posix_spawnattr_setarchpref_np_t)dlsym(
1133+
RTLD_DEFAULT, "posix_spawnattr_setarchpref_np");
1134+
if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {
1135+
error.SetError((*posix_spawnattr_setarchpref_np_fn)(
1136+
&attr, 1, &cpu_type, &cpu_subtype, &ocount),
1137+
eErrorTypePOSIX);
1138+
if (error.Fail())
1139+
LLDB_LOG(log,
1140+
"error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "
1141+
"cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )",
1142+
error, cpu_type, cpu_subtype, ocount);
1143+
1144+
if (error.Fail() || ocount != 1)
1145+
return error;
1146+
} else {
1147+
error.SetError(
1148+
::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),
1149+
eErrorTypePOSIX);
1150+
if (error.Fail())
1151+
LLDB_LOG(log,
1152+
"error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
1153+
"cpu_type = {1:x}, count => {2} )",
1154+
error, cpu_type, ocount);
1155+
if (error.Fail() || ocount != 1)
1156+
return error;
1157+
}
1158+
}
1159+
}
1160+
11111161
const char *tmp_argv[2];
11121162
char *const *argv = const_cast<char *const *>(
11131163
launch_info.GetArguments().GetConstArgumentVector());

lldb/source/Utility/ArchSpec.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = {
291291
{ArchSpec::eCore_arm_armv7m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7M, UINT32_MAX, SUBTYPE_MASK},
292292
{ArchSpec::eCore_arm_armv7em, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7EM, UINT32_MAX, SUBTYPE_MASK},
293293
{ArchSpec::eCore_arm_arm64e, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64E, UINT32_MAX, SUBTYPE_MASK},
294-
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_V8, UINT32_MAX, SUBTYPE_MASK},
295294
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_ALL, UINT32_MAX, SUBTYPE_MASK},
295+
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_V8, UINT32_MAX, SUBTYPE_MASK},
296296
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, 13, UINT32_MAX, SUBTYPE_MASK},
297297
{ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 0, UINT32_MAX, SUBTYPE_MASK},
298298
{ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 1, UINT32_MAX, SUBTYPE_MASK},
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
EXE := fat.out
2+
LIPO=lipo
3+
4+
include Makefile.rules
5+
6+
all: fat.out
7+
8+
x86_64.out: x86_64.c
9+
$(CC) -isysroot $(SDKROOT) -target x86_64-apple-macosx10.9 -o x86_64.out $<
10+
11+
x86_64h.out: x86_64h.c
12+
$(CC) -isysroot $(SDKROOT) -target x86_64h-apple-macosx10.9 -o x86_64h.out $<
13+
14+
arm64.out: arm64.c
15+
$(CC) -isysroot $(SDKROOT) -target arm64-apple-macosx10.9 -o arm64.out $<
16+
17+
fat.out: x86_64.out x86_64h.out arm64.out
18+
$(LIPO) -o fat.out -create $^
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import contextlib
2+
import os
3+
import unittest2
4+
import lldb
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test import lldbutil
8+
9+
10+
def haswell():
11+
features = subprocess.check_output(["sysctl", "machdep.cpu"])
12+
return "AVX2" in features.decode('utf-8')
13+
14+
15+
def apple_silicon():
16+
features = subprocess.check_output(["sysctl", "machdep.cpu"])
17+
return "Apple M" in features.decode('utf-8')
18+
19+
20+
@contextlib.contextmanager
21+
def remove_from_env(var):
22+
old_environ = os.environ.copy()
23+
del os.environ[var]
24+
try:
25+
yield
26+
finally:
27+
os.environ.clear()
28+
os.environ.update(old_environ)
29+
30+
31+
class TestLaunchProcessPosixSpawn(TestBase):
32+
NO_DEBUG_INFO_TESTCASE = True
33+
mydir = TestBase.compute_mydir(__file__)
34+
35+
def no_haswell(self):
36+
if not haswell():
37+
return "Current CPU is not Haswell"
38+
return None
39+
40+
def no_apple_silicon(self):
41+
if not apple_silicon():
42+
return "Current CPU is not Apple Silicon"
43+
return None
44+
45+
def run_arch(self, exe, arch):
46+
self.runCmd('target create -arch {} {}'.format(arch, exe))
47+
self.runCmd('run')
48+
49+
process = self.dbg.GetSelectedTarget().process
50+
self.assertEqual(process.GetState(), lldb.eStateExited)
51+
self.assertIn('slice: {}'.format(arch), process.GetSTDOUT(1000))
52+
53+
@skipUnlessDarwin
54+
@skipIfDarwinEmbedded
55+
@skipTestIfFn(no_haswell)
56+
def test_haswell(self):
57+
self.build()
58+
exe = self.getBuildArtifact("fat.out")
59+
self.run_arch(exe, 'x86_64')
60+
self.run_arch(exe, 'x86_64h')
61+
62+
@skipUnlessDarwin
63+
@skipIfDarwinEmbedded
64+
@skipTestIfFn(no_apple_silicon)
65+
def test_apple_silicon(self):
66+
self.build()
67+
exe = self.getBuildArtifact("fat.out")
68+
69+
# We need to remove LLDB_DEBUGSERVER_PATH from the environment if it's
70+
# set so that the Rosetta debugserver is picked for x86_64.
71+
with remove_from_env('LLDB_DEBUGSERVER_PATH'):
72+
self.run_arch(exe, 'x86_64')
73+
self.run_arch(exe, 'arm64')
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <stdio.h>
2+
int main() {
3+
printf("slice: arm64\n");
4+
return 0;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <stdio.h>
2+
int main() {
3+
printf("slice: x86_64\n");
4+
return 0;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <stdio.h>
2+
int main() {
3+
printf("slice: x86_64h\n");
4+
return 0;
5+
}

0 commit comments

Comments
 (0)