[Lldb-commits] [lldb] [lldb] [debugserver] Use "full" x86_64 GPR state when available. (PR #108663)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 13 16:42:39 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Brendan Shanks (mrpippy)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/108663.diff
3 Files Affected:
- (modified) lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp (+43-9)
- (modified) lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h (+3-1)
- (modified) lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h (+5)
``````````diff
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..286fd72267b349 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 ? __x86_64_THREAD_FULL_STATE
+ : __x86_64_THREAD_STATE,
+ 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"
@@ -461,9 +480,11 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
m_state.SetError(e_regSetGPR, Write,
::thread_set_state(m_thread->MachPortNumber(),
- __x86_64_THREAD_STATE,
+ m_state.hasFullGPRState ? __x86_64_THREAD_FULL_STATE
+ : __x86_64_THREAD_STATE,
(thread_state_t)&m_state.context.gpr,
- e_regSetWordSizeGPR));
+ m_state.hasFullGPRState ? e_regSetWordSizeGPRFull
+ : e_regSetWordSizeGPR));
DNBLogThreadedIf(
LOG_THREAD,
"::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
@@ -1157,6 +1178,10 @@ enum {
gpr_cs,
gpr_fs,
gpr_gs,
+ gpr_ds,
+ gpr_es,
+ gpr_ss,
+ gpr_gsbase,
gpr_eax,
gpr_ebx,
gpr_ecx,
@@ -1543,6 +1568,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 +1716,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 +2343,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 +2556,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 {
``````````
</details>
https://github.com/llvm/llvm-project/pull/108663
More information about the lldb-commits
mailing list