Skip to content

[lldb] Honor the CPU type & subtype when launching on macOS #2428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions lldb/source/Host/macosx/objcxx/Host.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include <asl.h>
#include <crt_externs.h>
#include <dlfcn.h>
#include <grp.h>
#include <libproc.h>
#include <pwd.h>
Expand Down Expand Up @@ -1108,6 +1109,55 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
}
}

// Don't set the binpref if a shell was provided. After all, that's only
// going to affect what version of the shell is launched, not what fork of
// the binary is launched. We insert "arch --arch <ARCH> as part of the
// shell invocation to do that job on OSX.
if (launch_info.GetShell() == FileSpec()) {
const ArchSpec &arch_spec = launch_info.GetArchitecture();
cpu_type_t cpu_type = arch_spec.GetMachOCPUType();
cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType();
const bool set_cpu_type =
cpu_type != 0 && cpu_type != static_cast<cpu_type_t>(UINT32_MAX) &&
cpu_type != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE);
const bool set_cpu_subtype =
cpu_subtype != 0 &&
cpu_subtype != static_cast<cpu_subtype_t>(UINT32_MAX) &&
cpu_subtype != CPU_SUBTYPE_X86_64_H;
if (set_cpu_type) {
size_t ocount = 0;
typedef int (*posix_spawnattr_setarchpref_np_t)(
posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *);
posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn =
(posix_spawnattr_setarchpref_np_t)dlsym(
RTLD_DEFAULT, "posix_spawnattr_setarchpref_np");
if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) {
error.SetError((*posix_spawnattr_setarchpref_np_fn)(
&attr, 1, &cpu_type, &cpu_subtype, &ocount),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, "
"cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )",
error, cpu_type, cpu_subtype, ocount);

if (error.Fail() || ocount != 1)
return error;
} else {
error.SetError(
::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
"cpu_type = {1:x}, count => {2} )",
error, cpu_type, ocount);
if (error.Fail() || ocount != 1)
return error;
}
}
}

const char *tmp_argv[2];
char *const *argv = const_cast<char *const *>(
launch_info.GetArguments().GetConstArgumentVector());
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Utility/ArchSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = {
{ArchSpec::eCore_arm_armv7m, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7M, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_armv7em, llvm::MachO::CPU_TYPE_ARM, llvm::MachO::CPU_SUBTYPE_ARM_V7EM, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64e, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64E, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_V8, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_ALL, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, llvm::MachO::CPU_SUBTYPE_ARM64_V8, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64, llvm::MachO::CPU_TYPE_ARM64, 13, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 0, UINT32_MAX, SUBTYPE_MASK},
{ArchSpec::eCore_arm_arm64_32, llvm::MachO::CPU_TYPE_ARM64_32, 1, UINT32_MAX, SUBTYPE_MASK},
Expand Down
18 changes: 18 additions & 0 deletions lldb/test/API/macosx/posix_spawn/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
EXE := fat.out
LIPO=lipo

include Makefile.rules

all: fat.out

x86_64.out: x86_64.c
$(CC) -isysroot $(SDKROOT) -target x86_64-apple-macosx10.9 -o x86_64.out $<

x86_64h.out: x86_64h.c
$(CC) -isysroot $(SDKROOT) -target x86_64h-apple-macosx10.9 -o x86_64h.out $<

arm64.out: arm64.c
$(CC) -isysroot $(SDKROOT) -target arm64-apple-macosx10.9 -o arm64.out $<

fat.out: x86_64.out x86_64h.out arm64.out
$(LIPO) -o fat.out -create $^
73 changes: 73 additions & 0 deletions lldb/test/API/macosx/posix_spawn/TestLaunchProcessPosixSpawn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import contextlib
import os
import unittest2
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


def haswell():
features = subprocess.check_output(["sysctl", "machdep.cpu"])
return "AVX2" in features.decode('utf-8')


def apple_silicon():
features = subprocess.check_output(["sysctl", "machdep.cpu"])
return "Apple M" in features.decode('utf-8')


@contextlib.contextmanager
def remove_from_env(var):
old_environ = os.environ.copy()
del os.environ[var]
try:
yield
finally:
os.environ.clear()
os.environ.update(old_environ)


class TestLaunchProcessPosixSpawn(TestBase):
NO_DEBUG_INFO_TESTCASE = True
mydir = TestBase.compute_mydir(__file__)

def no_haswell(self):
if not haswell():
return "Current CPU is not Haswell"
return None

def no_apple_silicon(self):
if not apple_silicon():
return "Current CPU is not Apple Silicon"
return None

def run_arch(self, exe, arch):
self.runCmd('target create -arch {} {}'.format(arch, exe))
self.runCmd('run')

process = self.dbg.GetSelectedTarget().process
self.assertEqual(process.GetState(), lldb.eStateExited)
self.assertIn('slice: {}'.format(arch), process.GetSTDOUT(1000))

@skipUnlessDarwin
@skipIfDarwinEmbedded
@skipTestIfFn(no_haswell)
def test_haswell(self):
self.build()
exe = self.getBuildArtifact("fat.out")
self.run_arch(exe, 'x86_64')
self.run_arch(exe, 'x86_64h')

@skipUnlessDarwin
@skipIfDarwinEmbedded
@skipTestIfFn(no_apple_silicon)
def test_apple_silicon(self):
self.build()
exe = self.getBuildArtifact("fat.out")

# We need to remove LLDB_DEBUGSERVER_PATH from the environment if it's
# set so that the Rosetta debugserver is picked for x86_64.
with remove_from_env('LLDB_DEBUGSERVER_PATH'):
self.run_arch(exe, 'x86_64')
self.run_arch(exe, 'arm64')
5 changes: 5 additions & 0 deletions lldb/test/API/macosx/posix_spawn/arm64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("slice: arm64\n");
return 0;
}
5 changes: 5 additions & 0 deletions lldb/test/API/macosx/posix_spawn/x86_64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("slice: x86_64\n");
return 0;
}
5 changes: 5 additions & 0 deletions lldb/test/API/macosx/posix_spawn/x86_64h.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("slice: x86_64h\n");
return 0;
}