Skip to content

Commit 7281e0c

Browse files
authored
[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
1 parent 23123aa commit 7281e0c

File tree

3 files changed

+61
-15
lines changed

3 files changed

+61
-15
lines changed

lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -182,22 +182,39 @@ kern_return_t DNBArchImplX86_64::GetGPRState(bool force) {
182182
m_state.context.gpr.__gs = ('g' << 8) + 's';
183183
m_state.SetError(e_regSetGPR, Read, 0);
184184
#else
185-
mach_msg_type_number_t count = e_regSetWordSizeGPR;
185+
mach_msg_type_number_t count = e_regSetWordSizeGPRFull;
186+
int flavor = __x86_64_THREAD_FULL_STATE;
186187
m_state.SetError(
187188
e_regSetGPR, Read,
188-
::thread_get_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE,
189+
::thread_get_state(m_thread->MachPortNumber(), flavor,
189190
(thread_state_t)&m_state.context.gpr, &count));
191+
192+
if (!m_state.GetError(e_regSetGPR, Read)) {
193+
m_state.hasFullGPRState = true;
194+
} else {
195+
m_state.hasFullGPRState = false;
196+
count = e_regSetWordSizeGPR;
197+
flavor = __x86_64_THREAD_STATE;
198+
m_state.SetError(
199+
e_regSetGPR, Read,
200+
::thread_get_state(m_thread->MachPortNumber(), flavor,
201+
(thread_state_t)&m_state.context.gpr, &count));
202+
}
190203
DNBLogThreadedIf(
191204
LOG_THREAD,
192-
"::thread_get_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
205+
"::thread_get_state (0x%4.4x, %u (%s), &gpr, %u) => 0x%8.8x"
193206
"\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
194207
"\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
195208
"\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
196209
"\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
197210
"\n\trip = %16.16llx"
198-
"\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
199-
m_thread->MachPortNumber(), x86_THREAD_STATE64,
200-
x86_THREAD_STATE64_COUNT, m_state.GetError(e_regSetGPR, Read),
211+
"\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx"
212+
"\n\t ds = %16.16llx es = %16.16llx ss = %16.16llx gsB = %16.16llx",
213+
m_thread->MachPortNumber(), flavor,
214+
m_state.hasFullGPRState ? "full" : "non-full",
215+
m_state.hasFullGPRState ? e_regSetWordSizeGPRFull
216+
: e_regSetWordSizeGPR,
217+
m_state.GetError(e_regSetGPR, Read),
201218
m_state.context.gpr.__rax, m_state.context.gpr.__rbx,
202219
m_state.context.gpr.__rcx, m_state.context.gpr.__rdx,
203220
m_state.context.gpr.__rdi, m_state.context.gpr.__rsi,
@@ -208,7 +225,9 @@ kern_return_t DNBArchImplX86_64::GetGPRState(bool force) {
208225
m_state.context.gpr.__r14, m_state.context.gpr.__r15,
209226
m_state.context.gpr.__rip, m_state.context.gpr.__rflags,
210227
m_state.context.gpr.__cs, m_state.context.gpr.__fs,
211-
m_state.context.gpr.__gs);
228+
m_state.context.gpr.__gs, m_state.context.gpr.__ds,
229+
m_state.context.gpr.__es, m_state.context.gpr.__ss,
230+
m_state.context.gpr.__gsbase );
212231

213232
// DNBLogThreadedIf (LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u)
214233
// => 0x%8.8x"
@@ -459,21 +478,26 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
459478
"(SetGPRState() for stop_count = %u)",
460479
m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
461480

481+
mach_msg_type_number_t count =
482+
m_state.hasFullGPRState ? e_regSetWordSizeGPRFull : e_regSetWordSizeGPR;
483+
int flavor = m_state.hasFullGPRState ? __x86_64_THREAD_FULL_STATE
484+
: __x86_64_THREAD_STATE;
462485
m_state.SetError(e_regSetGPR, Write,
463-
::thread_set_state(m_thread->MachPortNumber(),
464-
__x86_64_THREAD_STATE,
486+
::thread_set_state(m_thread->MachPortNumber(), flavor,
465487
(thread_state_t)&m_state.context.gpr,
466-
e_regSetWordSizeGPR));
488+
count));
467489
DNBLogThreadedIf(
468490
LOG_THREAD,
469-
"::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
491+
"::thread_set_state (0x%4.4x, %u (%s), &gpr, %u) => 0x%8.8x"
470492
"\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx"
471493
"\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx"
472494
"\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx"
473495
"\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx"
474496
"\n\trip = %16.16llx"
475-
"\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx",
476-
m_thread->MachPortNumber(), __x86_64_THREAD_STATE, e_regSetWordSizeGPR,
497+
"\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx"
498+
"\n\t ds = %16.16llx es = %16.16llx ss = %16.16llx gsB = %16.16llx",
499+
m_thread->MachPortNumber(), flavor,
500+
m_state.hasFullGPRState ? "full" : "non-full", count,
477501
m_state.GetError(e_regSetGPR, Write), m_state.context.gpr.__rax,
478502
m_state.context.gpr.__rbx, m_state.context.gpr.__rcx,
479503
m_state.context.gpr.__rdx, m_state.context.gpr.__rdi,
@@ -484,7 +508,9 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
484508
m_state.context.gpr.__r13, m_state.context.gpr.__r14,
485509
m_state.context.gpr.__r15, m_state.context.gpr.__rip,
486510
m_state.context.gpr.__rflags, m_state.context.gpr.__cs,
487-
m_state.context.gpr.__fs, m_state.context.gpr.__gs);
511+
m_state.context.gpr.__fs, m_state.context.gpr.__gs,
512+
m_state.context.gpr.__ds, m_state.context.gpr.__es,
513+
m_state.context.gpr.__ss, m_state.context.gpr.__gsbase);
488514
return m_state.GetError(e_regSetGPR, Write);
489515
}
490516

@@ -1157,6 +1183,10 @@ enum {
11571183
gpr_cs,
11581184
gpr_fs,
11591185
gpr_gs,
1186+
gpr_ds,
1187+
gpr_es,
1188+
gpr_ss,
1189+
gpr_gsbase,
11601190
gpr_eax,
11611191
gpr_ebx,
11621192
gpr_ecx,
@@ -1543,6 +1573,7 @@ enum debugserver_regnums {
15431573
debugserver_k5 = 123,
15441574
debugserver_k6 = 124,
15451575
debugserver_k7 = 125,
1576+
debugserver_gsbase = 126,
15461577
};
15471578

15481579
#define GPR_OFFSET(reg) (offsetof(DNBArchImplX86_64::GPR, __##reg))
@@ -1690,6 +1721,10 @@ const DNBRegisterInfo DNBArchImplX86_64::g_gpr_registers[] = {
16901721
DEFINE_GPR_ALT2(cs, NULL),
16911722
DEFINE_GPR_ALT2(fs, NULL),
16921723
DEFINE_GPR_ALT2(gs, NULL),
1724+
DEFINE_GPR_ALT2(ds, NULL),
1725+
DEFINE_GPR_ALT2(es, NULL),
1726+
DEFINE_GPR_ALT2(ss, NULL),
1727+
DEFINE_GPR_ALT2(gsbase, NULL),
16931728
DEFINE_GPR_PSEUDO_32(eax, rax),
16941729
DEFINE_GPR_PSEUDO_32(ebx, rbx),
16951730
DEFINE_GPR_PSEUDO_32(ecx, rcx),
@@ -2313,6 +2348,8 @@ bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg,
23132348
value->info = *regInfo;
23142349
switch (set) {
23152350
case e_regSetGPR:
2351+
if (reg > gpr_gs && !m_state.hasFullGPRState)
2352+
return false;
23162353
if (reg < k_num_gpr_registers) {
23172354
value->value.uint64 = ((uint64_t *)(&m_state.context.gpr))[reg];
23182355
return true;
@@ -2524,6 +2561,8 @@ bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg,
25242561
if (regInfo) {
25252562
switch (set) {
25262563
case e_regSetGPR:
2564+
if (reg > gpr_gs && !m_state.hasFullGPRState)
2565+
return false;
25272566
if (reg < k_num_gpr_registers) {
25282567
((uint64_t *)(&m_state.context.gpr))[reg] = value->value.uint64;
25292568
success = true;

lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ class DNBArchImplX86_64 : public DNBArchProtocol {
103103
};
104104

105105
enum RegisterSetWordSize {
106-
e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int),
106+
e_regSetWordSizeGPR = (sizeof(GPR) - 32) / sizeof(int),
107+
e_regSetWordSizeGPRFull = sizeof(GPR) / sizeof(int),
107108
e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int),
108109
e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int),
109110
e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int),
@@ -130,6 +131,7 @@ class DNBArchImplX86_64 : public DNBArchProtocol {
130131
kern_return_t fpu_errs[2]; // Read/Write errors
131132
kern_return_t exc_errs[2]; // Read/Write errors
132133
kern_return_t dbg_errs[2]; // Read/Write errors
134+
bool hasFullGPRState;
133135

134136
State() {
135137
uint32_t i;

lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define __x86_64_DEBUG_STATE 11
2323
#define __x86_64_AVX_STATE 17
2424
#define __x86_64_AVX512F_STATE 20
25+
#define __x86_64_THREAD_FULL_STATE 23
2526

2627
typedef struct {
2728
uint64_t __rax;
@@ -45,6 +46,10 @@ typedef struct {
4546
uint64_t __cs;
4647
uint64_t __fs;
4748
uint64_t __gs;
49+
uint64_t __ds;
50+
uint64_t __es;
51+
uint64_t __ss;
52+
uint64_t __gsbase;
4853
} __x86_64_thread_state_t;
4954

5055
typedef struct {

0 commit comments

Comments
 (0)