[Lldb-commits] [lldb] [lldb] [debugserver] Use "full" x86_64 GPR state when available. (PR #108663)

2024-09-13 Thread Brendan Shanks via lldb-commits

https://github.com/mrpippy created 
https://github.com/llvm/llvm-project/pull/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 

>From 4453801c7d8abf7a6adfb7fae57ad9fa9d52a0c4 Mon Sep 17 00:00:00 2001
From: Brendan Shanks 
Date: Thu, 12 Sep 2024 16:01:30 -0700
Subject: [PATCH] [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
---
 .../MacOSX/x86_64/DNBArchImplX86_64.cpp   | 52 +++
 .../source/MacOSX/x86_64/DNBArchImplX86_64.h  |  4 +-
 .../MacOSX/x86_64/MachRegisterStatesX86_64.h  |  5 ++
 3 files changed, 51 insertions(+), 10 deletions(-)

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,

[Lldb-commits] [lldb] [lldb] [debugserver] Use "full" x86_64 GPR state when available. (PR #108663)

2024-09-18 Thread Brendan Shanks via lldb-commits

mrpippy wrote:

Great, no I don't think I have permissions to merge.

I pushed a new version that fixed a typo in the `GetGPRState` log call, and in 
`SetGPRState` adds the new fields to the log call.

https://github.com/llvm/llvm-project/pull/108663
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb] [debugserver] Use "full" x86_64 GPR state when available. (PR #108663)

2024-09-18 Thread Brendan Shanks via lldb-commits

https://github.com/mrpippy updated 
https://github.com/llvm/llvm-project/pull/108663

>From a9b19cbd20083e2b1d6c8de342206cb0ec6183b7 Mon Sep 17 00:00:00 2001
From: Brendan Shanks 
Date: Thu, 12 Sep 2024 16:01:30 -0700
Subject: [PATCH] [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
---
 .../MacOSX/x86_64/DNBArchImplX86_64.cpp   | 67 +++
 .../source/MacOSX/x86_64/DNBArchImplX86_64.h  |  4 +-
 .../MacOSX/x86_64/MachRegisterStatesX86_64.h  |  5 ++
 3 files changed, 61 insertions(+), 15 deletions(-)

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