Skip to content

Commit 01450dd

Browse files
committed
Change debugserver to report the cpu(sub)type of process, not the host.
This way debugserver can correctly report qProcessInfo for arm64 processes on arm64e-capable hosts. Patch implemented with help from Jason Molenda!
1 parent f9f3316 commit 01450dd

File tree

8 files changed

+108
-49
lines changed

8 files changed

+108
-49
lines changed

lldb/source/Target/Target.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "lldb/Expression/UtilityFunction.h"
3434
#include "lldb/Host/Host.h"
3535
#include "lldb/Host/PosixApi.h"
36+
#include "lldb/Host/SafeMachO.h"
3637
#include "lldb/Host/StreamFile.h"
3738
#include "lldb/Interpreter/CommandInterpreter.h"
3839
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -1571,6 +1572,13 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform,
15711572

15721573
if (m_arch.GetSpec().GetTriple() == other.GetTriple())
15731574
replace_local_arch = false;
1575+
// Workaround for for pre-2024 debugserver, which always
1576+
// returns arm64e on arm64e-capable hardware regardless of
1577+
// what the process is. This can be deleted at some point in
1578+
// the future.
1579+
if (!m_arch.GetSpec().GetMachOCPUSubType() &&
1580+
other.GetMachOCPUSubType() == llvm::MachO::CPU_SUBTYPE_ARM64E)
1581+
replace_local_arch = true;
15741582
}
15751583
}
15761584
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
C_SOURCES := main.c
2+
3+
# Uncomment this for local debugging.
4+
#all:
5+
# xcrun clang -g $(SRCDIR)/main.c -o a.out -target arm64e-apple-macosx
6+
27
include Makefile.rules

lldb/test/API/macosx/arm64e-attach/TestArm64eAttach.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,23 @@ def test(self):
1313
# Skip this test if not running on AArch64 target that supports PAC
1414
if not self.isAArch64PAuth():
1515
self.skipTest("Target must support pointer authentication.")
16+
1617
self.build()
1718
popen = self.spawnSubprocess(self.getBuildArtifact(), [])
18-
error = lldb.SBError()
19+
1920
# This simulates how Xcode attaches to a process by pid/name.
21+
error = lldb.SBError()
2022
target = self.dbg.CreateTarget("", "arm64", "", True, error)
2123
listener = lldb.SBListener("my.attach.listener")
2224
process = target.AttachToProcessWithID(listener, popen.pid, error)
2325
self.assertSuccess(error)
2426
self.assertTrue(process, PROCESS_IS_VALID)
2527
self.assertEqual(target.GetTriple().split('-')[0], "arm64e",
2628
"target triple is updated correctly")
29+
30+
self.expect('process plugin packet send qProcessInfo',
31+
"debugserver returns correct triple",
32+
substrs=['cputype:100000c', 'cpusubtype:2', 'ptrsize:8'])
33+
2734
error = process.Kill()
2835
self.assertSuccess(error)

lldb/tools/debugserver/source/DNB.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,14 @@ DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
10621062
return INVALID_NUB_ADDRESS;
10631063
}
10641064

1065+
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
1066+
DNBGetMainBinaryCPUTypes(nub_process_t pid) {
1067+
MachProcessSP procSP;
1068+
if (GetProcessSP(pid, procSP))
1069+
return procSP->GetMainBinaryCPUTypes(pid);
1070+
return {};
1071+
}
1072+
10651073
JSONGenerator::ObjectSP
10661074
DNBGetAllLoadedLibrariesInfos(nub_process_t pid, bool report_load_commands) {
10671075
MachProcessSP procSP;

lldb/tools/debugserver/source/DNB.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
210210
uint64_t plo_pthread_tsd_base_address_offset,
211211
uint64_t plo_pthread_tsd_base_offset,
212212
uint64_t plo_pthread_tsd_entry_size);
213+
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
214+
DNBGetMainBinaryCPUTypes(nub_process_t pid);
213215
JSONGenerator::ObjectSP
214216
DNBGetAllLoadedLibrariesInfos(nub_process_t pid, bool report_load_commands);
215217
JSONGenerator::ObjectSP

lldb/tools/debugserver/source/MacOSX/MachProcess.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ class MachProcess {
103103
const char *stdin_path, const char *stdout_path, const char *stderr_path,
104104
bool no_stdio, MachProcess *process, int disable_aslr, DNBError &err);
105105
nub_addr_t GetDYLDAllImageInfosAddress();
106+
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
107+
GetMainBinaryCPUTypes(nub_process_t pid);
106108
static const void *PrepareForAttach(const char *path,
107109
nub_launch_flavor_t launch_flavor,
108110
bool waitfor, DNBError &err_str);

lldb/tools/debugserver/source/MacOSX/MachProcess.mm

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,23 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
11111111
return FormatDynamicLibrariesIntoJSON(image_infos, report_load_commands);
11121112
}
11131113

1114+
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
1115+
MachProcess::GetMainBinaryCPUTypes(nub_process_t pid) {
1116+
int pointer_size = GetInferiorAddrSize(pid);
1117+
std::vector<struct binary_image_information> image_infos;
1118+
GetAllLoadedBinariesViaDYLDSPI(image_infos);
1119+
uint32_t platform = GetPlatform();
1120+
for (auto &image_info : image_infos)
1121+
if (GetMachOInformationFromMemory(platform, image_info.load_address,
1122+
pointer_size, image_info.macho_info))
1123+
if (image_info.macho_info.mach_header.filetype == MH_EXECUTE)
1124+
return {
1125+
{static_cast<cpu_type_t>(image_info.macho_info.mach_header.cputype),
1126+
static_cast<cpu_subtype_t>(
1127+
image_info.macho_info.mach_header.cpusubtype)}};
1128+
return {};
1129+
}
1130+
11141131
// Fetch information about the shared libraries at the given load addresses
11151132
// using the
11161133
// dyld SPIs that exist in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer.

lldb/tools/debugserver/source/RNBRemote.cpp

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6195,59 +6195,14 @@ rnb_err_t RNBRemote::HandlePacket_qSymbol(const char *command) {
61956195
}
61966196
}
61976197

6198-
// Note that all numeric values returned by qProcessInfo are hex encoded,
6199-
// including the pid and the cpu type.
6200-
6201-
rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {
6202-
nub_process_t pid;
6203-
std::ostringstream rep;
6204-
6205-
// If we haven't run the process yet, return an error.
6206-
if (!m_ctx.HasValidProcessID())
6207-
return SendPacket("E68");
6208-
6209-
pid = m_ctx.ProcessID();
6210-
6211-
rep << "pid:" << std::hex << pid << ';';
6212-
6213-
int procpid_mib[4];
6214-
procpid_mib[0] = CTL_KERN;
6215-
procpid_mib[1] = KERN_PROC;
6216-
procpid_mib[2] = KERN_PROC_PID;
6217-
procpid_mib[3] = pid;
6218-
struct kinfo_proc proc_kinfo;
6219-
size_t proc_kinfo_size = sizeof(struct kinfo_proc);
6220-
6221-
if (::sysctl(procpid_mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
6222-
if (proc_kinfo_size > 0) {
6223-
rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';';
6224-
rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid
6225-
<< ';';
6226-
rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid
6227-
<< ';';
6228-
rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid
6229-
<< ';';
6230-
if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
6231-
rep << "effective-gid:" << std::hex
6232-
<< proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';';
6233-
}
6234-
}
6235-
6198+
static std::pair<cpu_type_t, cpu_subtype_t>
6199+
GetCPUTypesFromHost(nub_process_t pid) {
62366200
cpu_type_t cputype = DNBProcessGetCPUType(pid);
62376201
if (cputype == 0) {
62386202
DNBLog("Unable to get the process cpu_type, making a best guess.");
62396203
cputype = best_guess_cpu_type();
62406204
}
62416205

6242-
uint32_t addr_size = 0;
6243-
if (cputype != 0) {
6244-
rep << "cputype:" << std::hex << cputype << ";";
6245-
if (cputype & CPU_ARCH_ABI64)
6246-
addr_size = 8;
6247-
else
6248-
addr_size = 4;
6249-
}
6250-
62516206
bool host_cpu_is_64bit = false;
62526207
uint32_t is64bit_capable;
62536208
size_t is64bit_capable_len = sizeof(is64bit_capable);
@@ -6288,14 +6243,69 @@ rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {
62886243
if (cputype == CPU_TYPE_ARM64_32 && cpusubtype == 2)
62896244
cpusubtype = CPU_SUBTYPE_ARM64_32_V8;
62906245
#endif
6246+
}
6247+
6248+
return {cputype, cpusubtype};
6249+
}
6250+
6251+
// Note that all numeric values returned by qProcessInfo are hex encoded,
6252+
// including the pid and the cpu type.
62916253

6254+
rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {
6255+
nub_process_t pid;
6256+
std::ostringstream rep;
6257+
6258+
// If we haven't run the process yet, return an error.
6259+
if (!m_ctx.HasValidProcessID())
6260+
return SendPacket("E68");
6261+
6262+
pid = m_ctx.ProcessID();
6263+
6264+
rep << "pid:" << std::hex << pid << ';';
6265+
6266+
int procpid_mib[4];
6267+
procpid_mib[0] = CTL_KERN;
6268+
procpid_mib[1] = KERN_PROC;
6269+
procpid_mib[2] = KERN_PROC_PID;
6270+
procpid_mib[3] = pid;
6271+
struct kinfo_proc proc_kinfo;
6272+
size_t proc_kinfo_size = sizeof(struct kinfo_proc);
6273+
6274+
if (::sysctl(procpid_mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
6275+
if (proc_kinfo_size > 0) {
6276+
rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';';
6277+
rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid
6278+
<< ';';
6279+
rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid
6280+
<< ';';
6281+
rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid
6282+
<< ';';
6283+
if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
6284+
rep << "effective-gid:" << std::hex
6285+
<< proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';';
6286+
}
6287+
}
6288+
6289+
cpu_type_t cputype;
6290+
cpu_subtype_t cpusubtype;
6291+
if (auto cputypes = DNBGetMainBinaryCPUTypes(pid))
6292+
std::tie(cputype, cpusubtype) = *cputypes;
6293+
else
6294+
std::tie(cputype, cpusubtype) = GetCPUTypesFromHost(pid);
6295+
6296+
uint32_t addr_size = 0;
6297+
if (cputype != 0) {
6298+
rep << "cputype:" << std::hex << cputype << ";";
62926299
rep << "cpusubtype:" << std::hex << cpusubtype << ';';
6300+
if (cputype & CPU_ARCH_ABI64)
6301+
addr_size = 8;
6302+
else
6303+
addr_size = 4;
62936304
}
62946305

62956306
bool os_handled = false;
62966307
if (addr_size > 0) {
62976308
rep << "ptrsize:" << std::dec << addr_size << ';';
6298-
62996309
#if defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1
63006310
// Try and get the OS type by looking at the load commands in the main
63016311
// executable and looking for a LC_VERSION_MIN load command. This is the

0 commit comments

Comments
 (0)