Skip to content

Commit a9b19cb

Browse files
committed
[lldb] [debugserver] Use "full" x86_64 GPR state when available.
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, 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. Fixes #57591
1 parent b74e779 commit a9b19cb

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)