Skip to content

Commit 4453801

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 4453801

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

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

Lines changed: 43 additions & 9 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 ? __x86_64_THREAD_FULL_STATE
216+
: __x86_64_THREAD_STATE,
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"
@@ -461,9 +480,11 @@ kern_return_t DNBArchImplX86_64::SetGPRState() {
461480

462481
m_state.SetError(e_regSetGPR, Write,
463482
::thread_set_state(m_thread->MachPortNumber(),
464-
__x86_64_THREAD_STATE,
483+
m_state.hasFullGPRState ? __x86_64_THREAD_FULL_STATE
484+
: __x86_64_THREAD_STATE,
465485
(thread_state_t)&m_state.context.gpr,
466-
e_regSetWordSizeGPR));
486+
m_state.hasFullGPRState ? e_regSetWordSizeGPRFull
487+
: e_regSetWordSizeGPR));
467488
DNBLogThreadedIf(
468489
LOG_THREAD,
469490
"::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
@@ -1157,6 +1178,10 @@ enum {
11571178
gpr_cs,
11581179
gpr_fs,
11591180
gpr_gs,
1181+
gpr_ds,
1182+
gpr_es,
1183+
gpr_ss,
1184+
gpr_gsbase,
11601185
gpr_eax,
11611186
gpr_ebx,
11621187
gpr_ecx,
@@ -1543,6 +1568,7 @@ enum debugserver_regnums {
15431568
debugserver_k5 = 123,
15441569
debugserver_k6 = 124,
15451570
debugserver_k7 = 125,
1571+
debugserver_gsbase = 126,
15461572
};
15471573

15481574
#define GPR_OFFSET(reg) (offsetof(DNBArchImplX86_64::GPR, __##reg))
@@ -1690,6 +1716,10 @@ const DNBRegisterInfo DNBArchImplX86_64::g_gpr_registers[] = {
16901716
DEFINE_GPR_ALT2(cs, NULL),
16911717
DEFINE_GPR_ALT2(fs, NULL),
16921718
DEFINE_GPR_ALT2(gs, NULL),
1719+
DEFINE_GPR_ALT2(ds, NULL),
1720+
DEFINE_GPR_ALT2(es, NULL),
1721+
DEFINE_GPR_ALT2(ss, NULL),
1722+
DEFINE_GPR_ALT2(gsbase, NULL),
16931723
DEFINE_GPR_PSEUDO_32(eax, rax),
16941724
DEFINE_GPR_PSEUDO_32(ebx, rbx),
16951725
DEFINE_GPR_PSEUDO_32(ecx, rcx),
@@ -2313,6 +2343,8 @@ bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg,
23132343
value->info = *regInfo;
23142344
switch (set) {
23152345
case e_regSetGPR:
2346+
if (reg > gpr_gs && !m_state.hasFullGPRState)
2347+
return false;
23162348
if (reg < k_num_gpr_registers) {
23172349
value->value.uint64 = ((uint64_t *)(&m_state.context.gpr))[reg];
23182350
return true;
@@ -2524,6 +2556,8 @@ bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg,
25242556
if (regInfo) {
25252557
switch (set) {
25262558
case e_regSetGPR:
2559+
if (reg > gpr_gs && !m_state.hasFullGPRState)
2560+
return false;
25272561
if (reg < k_num_gpr_registers) {
25282562
((uint64_t *)(&m_state.context.gpr))[reg] = value->value.uint64;
25292563
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)