[Lldb-commits] [lldb] 7281e0c - [lldb] [debugserver] Use "full" x86_64 GPR state when available. (#108663)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 18 22:57:05 PDT 2024
Author: Brendan Shanks
Date: 2024-09-18T22:57:01-07:00
New Revision: 7281e0cb3bbcce396aab8b3ea0967d7a17cd287a
URL: https://github.com/llvm/llvm-project/commit/7281e0cb3bbcce396aab8b3ea0967d7a17cd287a
DIFF: https://github.com/llvm/llvm-project/commit/7281e0cb3bbcce396aab8b3ea0967d7a17cd287a.diff
LOG: [lldb] [debugserver] Use "full" x86_64 GPR state when available. (#108663)
macOS 10.15 added a "full" x86_64 GPR thread state flavor, equivalent to
the normal one but with DS, ES, SS, and GSbase added. This flavor can
only be used with processes that install a custom LDT (functionality
that was also added in 10.15 and is used by apps like Wine to execute
32-bit code).
Along with allowing DS, ES, SS, and GSbase to be viewed/modified, using
the full flavor is necessary when debugging a thread executing 32-bit
code.
If thread_set_state() is used with the regular thread state flavor, the
kernel resets CS to the 64-bit code segment (see
[set_thread_state64()](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/i386/pcb.c#L723),
which makes debugging impossible.
There's no way to detect whether the full flavor is available, try to
use it and fall back to the regular one if it's not available.
A downside is that this patch exposes the DS, ES, SS, and GSbase
registers for all x86_64 processes, even though they are not populated
unless the full thread state is available.
I'm not sure if there's a way to tell LLDB that a register is
unavailable. The classic GDB `g` command [allows returning
`x`](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Packets.html#Packets)
to denote unavailable registers, but it seems like the debug server uses
newer commands like `jThreadsInfo` and I'm not sure if those have the
same support.
Fixes #57591
(also filed as Apple FB11464104)
@jasonmolenda
Added:
Modified:
lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h
Removed:
################################################################################
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
index 5a62e2a8d12e2c..3b3f1f02a2851f 100644
--- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
@@ -182,22 +182,39 @@ kern_return_t DNBArchImplX86_64::GetGPRState(bool force) {
m_state.context.gpr.__gs = ('g' << 8) + 's';
m_state.SetError(e_regSetGPR, Read, 0);
#else
- mach_msg_type_number_t count = e_regSetWordSizeGPR;
+ mach_msg_type_number_t count = e_regSetWordSizeGPRFull;
+ int flavor = __x86_64_THREAD_FULL_STATE;
m_state.SetError(
e_regSetGPR, Read,
- ::thread_get_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE,
+ ::thread_get_state(m_thread->MachPortNumber(), flavor,
(thread_state_t)&m_state.context.gpr, &count));
+
+ if (!m_state.GetError(e_regSetGPR, Read)) {
+ m_state.hasFullGPRState = true;
+ } else {
+ m_state.hasFullGPRState = false;
+ count = e_regSetWordSizeGPR;
+ flavor = __x86_64_THREAD_STATE;
+ m_state.SetError(
+ e_regSetGPR, Read,
+ ::thread_get_state(m_thread->MachPortNumber(), flavor,
+ (thread_state_t)&m_state.context.gpr, &count));
+ }
DNBLogThreadedIf(
LOG_THREAD,
- "::thread_get_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
+ "::thread_get_state (0x%4.4x, %u (%s), &gpr, %u) => 0x%8.8x"
"\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
"\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
"\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
"\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
"\n\trip = %16.16llx"
- "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
- m_thread->MachPortNumber(), x86_THREAD_STATE64,
- x86_THREAD_STATE64_COUNT, m_state.GetError(e_regSetGPR, Read),
+ "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx"
+ "\n\t ds = %16.16llx es = %16.16llx ss = %16.16llx gsB = %16.16llx",
+ m_thread->MachPortNumber(), flavor,
+ m_state.hasFullGPRState ? "full" : "non-full",
+ m_state.hasFullGPRState ? e_regSetWordSizeGPRFull
+ : e_regSetWordSizeGPR,
+ m_state.GetError(e_regSetGPR, Read),
m_state.context.gpr.__rax, m_state.context.gpr.__rbx,
m_state.context.gpr.__rcx, m_state.context.gpr.__rdx,
m_state.context.gpr.__rdi, m_state.context.gpr.__rsi,
@@ -208,7 +225,9 @@ kern_return_t DNBArchImplX86_64::GetGPRState(bool force) {
m_state.context.gpr.__r14, m_state.context.gpr.__r15,
m_state.context.gpr.__rip, m_state.context.gpr.__rflags,
m_state.context.gpr.__cs, m_state.context.gpr.__fs,
- m_state.context.gpr.__gs);
+ m_state.context.gpr.__gs, m_state.context.gpr.__ds,
+ m_state.context.gpr.__es, m_state.context.gpr.__ss,
+ m_state.context.gpr.__gsbase );
// DNBLogThreadedIf (LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u)
// => 0x%8.8x"
@@ -459,21 +478,26 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
"(SetGPRState() for stop_count = %u)",
m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
+ mach_msg_type_number_t count =
+ m_state.hasFullGPRState ? e_regSetWordSizeGPRFull : e_regSetWordSizeGPR;
+ int flavor = m_state.hasFullGPRState ? __x86_64_THREAD_FULL_STATE
+ : __x86_64_THREAD_STATE;
m_state.SetError(e_regSetGPR, Write,
- ::thread_set_state(m_thread->MachPortNumber(),
- __x86_64_THREAD_STATE,
+ ::thread_set_state(m_thread->MachPortNumber(), flavor,
(thread_state_t)&m_state.context.gpr,
- e_regSetWordSizeGPR));
+ count));
DNBLogThreadedIf(
LOG_THREAD,
- "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
+ "::thread_set_state (0x%4.4x, %u (%s), &gpr, %u) => 0x%8.8x"
"\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
"\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
"\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
"\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
"\n\trip = %16.16llx"
- "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
- m_thread->MachPortNumber(), __x86_64_THREAD_STATE, e_regSetWordSizeGPR,
+ "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx"
+ "\n\t ds = %16.16llx es = %16.16llx ss = %16.16llx gsB = %16.16llx",
+ m_thread->MachPortNumber(), flavor,
+ m_state.hasFullGPRState ? "full" : "non-full", count,
m_state.GetError(e_regSetGPR, Write), m_state.context.gpr.__rax,
m_state.context.gpr.__rbx, m_state.context.gpr.__rcx,
m_state.context.gpr.__rdx, m_state.context.gpr.__rdi,
@@ -484,7 +508,9 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
m_state.context.gpr.__r13, m_state.context.gpr.__r14,
m_state.context.gpr.__r15, m_state.context.gpr.__rip,
m_state.context.gpr.__rflags, m_state.context.gpr.__cs,
- m_state.context.gpr.__fs, m_state.context.gpr.__gs);
+ m_state.context.gpr.__fs, m_state.context.gpr.__gs,
+ m_state.context.gpr.__ds, m_state.context.gpr.__es,
+ m_state.context.gpr.__ss, m_state.context.gpr.__gsbase);
return m_state.GetError(e_regSetGPR, Write);
}
@@ -1157,6 +1183,10 @@ enum {
gpr_cs,
gpr_fs,
gpr_gs,
+ gpr_ds,
+ gpr_es,
+ gpr_ss,
+ gpr_gsbase,
gpr_eax,
gpr_ebx,
gpr_ecx,
@@ -1543,6 +1573,7 @@ enum debugserver_regnums {
debugserver_k5 = 123,
debugserver_k6 = 124,
debugserver_k7 = 125,
+ debugserver_gsbase = 126,
};
#define GPR_OFFSET(reg) (offsetof(DNBArchImplX86_64::GPR, __##reg))
@@ -1690,6 +1721,10 @@ const DNBRegisterInfo DNBArchImplX86_64::g_gpr_registers[] = {
DEFINE_GPR_ALT2(cs, NULL),
DEFINE_GPR_ALT2(fs, NULL),
DEFINE_GPR_ALT2(gs, NULL),
+ DEFINE_GPR_ALT2(ds, NULL),
+ DEFINE_GPR_ALT2(es, NULL),
+ DEFINE_GPR_ALT2(ss, NULL),
+ DEFINE_GPR_ALT2(gsbase, NULL),
DEFINE_GPR_PSEUDO_32(eax, rax),
DEFINE_GPR_PSEUDO_32(ebx, rbx),
DEFINE_GPR_PSEUDO_32(ecx, rcx),
@@ -2313,6 +2348,8 @@ bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg,
value->info = *regInfo;
switch (set) {
case e_regSetGPR:
+ if (reg > gpr_gs && !m_state.hasFullGPRState)
+ return false;
if (reg < k_num_gpr_registers) {
value->value.uint64 = ((uint64_t *)(&m_state.context.gpr))[reg];
return true;
@@ -2524,6 +2561,8 @@ bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg,
if (regInfo) {
switch (set) {
case e_regSetGPR:
+ if (reg > gpr_gs && !m_state.hasFullGPRState)
+ return false;
if (reg < k_num_gpr_registers) {
((uint64_t *)(&m_state.context.gpr))[reg] = value->value.uint64;
success = true;
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
index 96da02a4c9ff9f..7fffd60b2064e0 100644
--- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
@@ -103,7 +103,8 @@ class DNBArchImplX86_64 : public DNBArchProtocol {
};
enum RegisterSetWordSize {
- e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int),
+ e_regSetWordSizeGPR = (sizeof(GPR) - 32) / sizeof(int),
+ e_regSetWordSizeGPRFull = sizeof(GPR) / sizeof(int),
e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int),
e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int),
e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int),
@@ -130,6 +131,7 @@ class DNBArchImplX86_64 : public DNBArchProtocol {
kern_return_t fpu_errs[2]; // Read/Write errors
kern_return_t exc_errs[2]; // Read/Write errors
kern_return_t dbg_errs[2]; // Read/Write errors
+ bool hasFullGPRState;
State() {
uint32_t i;
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h
index b566accd397285..743c665b691067 100644
--- a/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h
@@ -22,6 +22,7 @@
#define __x86_64_DEBUG_STATE 11
#define __x86_64_AVX_STATE 17
#define __x86_64_AVX512F_STATE 20
+#define __x86_64_THREAD_FULL_STATE 23
typedef struct {
uint64_t __rax;
@@ -45,6 +46,10 @@ typedef struct {
uint64_t __cs;
uint64_t __fs;
uint64_t __gs;
+ uint64_t __ds;
+ uint64_t __es;
+ uint64_t __ss;
+ uint64_t __gsbase;
} __x86_64_thread_state_t;
typedef struct {
More information about the lldb-commits
mailing list