- On macOS, add error reporting when getting/setting debug registers. - Also, as in ptrace.c, use context->machine to determine which context struct to read/write. - And when setting, ensure that the correct debug state flavor is used (needed for Wow64)
The debug register tests should now pass on Mojave and Monterey, for 32- and 64-bit.
Note that Rosetta 2 on Apple Silicon mostly doesn't emulate debug registers, and the tests fail there.
From: Brendan Shanks bshanks@codeweavers.com
--- server/mach.c | 9 --------- 1 file changed, 9 deletions(-)
diff --git a/server/mach.c b/server/mach.c index d31e4025776..0a51c3379e9 100644 --- a/server/mach.c +++ b/server/mach.c @@ -173,14 +173,9 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
if (!thread_get_state( port, x86_DEBUG_STATE, (thread_state_t)&state, &count )) { -#ifdef __x86_64__ assert( state.dsh.flavor == x86_DEBUG_STATE32 || state.dsh.flavor == x86_DEBUG_STATE64 ); -#else - assert( state.dsh.flavor == x86_DEBUG_STATE32 ); -#endif
-#ifdef __x86_64__ if (state.dsh.flavor == x86_DEBUG_STATE64) { context->debug.x86_64_regs.dr0 = state.uds.ds64.__dr0; @@ -191,7 +186,6 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int context->debug.x86_64_regs.dr7 = state.uds.ds64.__dr7; } else -#endif { context->debug.i386_regs.dr0 = state.uds.ds32.__dr0; context->debug.i386_regs.dr1 = state.uds.ds32.__dr1; @@ -227,8 +221,6 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign return; }
- -#ifdef __x86_64__ if (thread->process->machine == IMAGE_FILE_MACHINE_AMD64) { /* Mac OS doesn't allow setting the global breakpoint flags */ @@ -246,7 +238,6 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign state.uds.ds64.__dr7 = dr7; } else -#endif { dr7 = (context->debug.i386_regs.dr7 & ~0xaa) | ((context->debug.i386_regs.dr7 & 0xaa) >> 1);
From: Brendan Shanks bshanks@codeweavers.com
--- server/mach.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/server/mach.c b/server/mach.c index 0a51c3379e9..fa87bdbff38 100644 --- a/server/mach.c +++ b/server/mach.c @@ -159,6 +159,7 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int mach_msg_type_number_t count = sizeof(state) / sizeof(int); mach_msg_type_name_t type; mach_port_t port, process_port = get_process_port( thread->process ); + kern_return_t ret;
/* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); @@ -171,7 +172,8 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int return; }
- if (!thread_get_state( port, x86_DEBUG_STATE, (thread_state_t)&state, &count )) + ret = thread_get_state( port, x86_DEBUG_STATE, (thread_state_t)&state, &count ); + if (!ret) { assert( state.dsh.flavor == x86_DEBUG_STATE32 || state.dsh.flavor == x86_DEBUG_STATE64 ); @@ -196,6 +198,8 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int } context->flags |= SERVER_CTX_DEBUG_REGISTERS; } + else + mach_set_error( ret ); mach_port_deallocate( mach_task_self(), port ); #endif } @@ -209,6 +213,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign mach_msg_type_name_t type; mach_port_t port, process_port = get_process_port( thread->process ); unsigned int dr7; + kern_return_t ret;
/* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); @@ -252,7 +257,9 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign state.uds.ds32.__dr6 = context->debug.i386_regs.dr6; state.uds.ds32.__dr7 = dr7; } - thread_set_state( port, x86_DEBUG_STATE, (thread_state_t)&state, count ); + ret = thread_set_state( port, x86_DEBUG_STATE, (thread_state_t)&state, count ); + if (ret) + mach_set_error( ret ); mach_port_deallocate( mach_task_self(), port ); #endif }
From: Brendan Shanks bshanks@codeweavers.com
--- server/mach.c | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-)
diff --git a/server/mach.c b/server/mach.c index fa87bdbff38..08dbbb7d96f 100644 --- a/server/mach.c +++ b/server/mach.c @@ -160,6 +160,7 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int mach_msg_type_name_t type; mach_port_t port, process_port = get_process_port( thread->process ); kern_return_t ret; + unsigned long dr[8];
/* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); @@ -180,26 +181,50 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
if (state.dsh.flavor == x86_DEBUG_STATE64) { - context->debug.x86_64_regs.dr0 = state.uds.ds64.__dr0; - context->debug.x86_64_regs.dr1 = state.uds.ds64.__dr1; - context->debug.x86_64_regs.dr2 = state.uds.ds64.__dr2; - context->debug.x86_64_regs.dr3 = state.uds.ds64.__dr3; - context->debug.x86_64_regs.dr6 = state.uds.ds64.__dr6; - context->debug.x86_64_regs.dr7 = state.uds.ds64.__dr7; + dr[0] = state.uds.ds64.__dr0; + dr[1] = state.uds.ds64.__dr1; + dr[2] = state.uds.ds64.__dr2; + dr[3] = state.uds.ds64.__dr3; + dr[6] = state.uds.ds64.__dr6; + dr[7] = state.uds.ds64.__dr7; } else { - context->debug.i386_regs.dr0 = state.uds.ds32.__dr0; - context->debug.i386_regs.dr1 = state.uds.ds32.__dr1; - context->debug.i386_regs.dr2 = state.uds.ds32.__dr2; - context->debug.i386_regs.dr3 = state.uds.ds32.__dr3; - context->debug.i386_regs.dr6 = state.uds.ds32.__dr6; - context->debug.i386_regs.dr7 = state.uds.ds32.__dr7; + dr[0] = state.uds.ds32.__dr0; + dr[1] = state.uds.ds32.__dr1; + dr[2] = state.uds.ds32.__dr2; + dr[3] = state.uds.ds32.__dr3; + dr[6] = state.uds.ds32.__dr6; + dr[7] = state.uds.ds32.__dr7; + } + + switch (context->machine) + { + case IMAGE_FILE_MACHINE_I386: + context->debug.i386_regs.dr0 = dr[0]; + context->debug.i386_regs.dr1 = dr[1]; + context->debug.i386_regs.dr2 = dr[2]; + context->debug.i386_regs.dr3 = dr[3]; + context->debug.i386_regs.dr6 = dr[6]; + context->debug.i386_regs.dr7 = dr[7]; + break; + case IMAGE_FILE_MACHINE_AMD64: + context->debug.x86_64_regs.dr0 = dr[0]; + context->debug.x86_64_regs.dr1 = dr[1]; + context->debug.x86_64_regs.dr2 = dr[2]; + context->debug.x86_64_regs.dr3 = dr[3]; + context->debug.x86_64_regs.dr6 = dr[6]; + context->debug.x86_64_regs.dr7 = dr[7]; + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + goto done; } context->flags |= SERVER_CTX_DEBUG_REGISTERS; } else mach_set_error( ret ); +done: mach_port_deallocate( mach_task_self(), port ); #endif }
From: Brendan Shanks bshanks@codeweavers.com
--- server/mach.c | 70 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 20 deletions(-)
diff --git a/server/mach.c b/server/mach.c index 08dbbb7d96f..6051396a1bf 100644 --- a/server/mach.c +++ b/server/mach.c @@ -237,7 +237,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign mach_msg_type_number_t count = sizeof(state) / sizeof(int); mach_msg_type_name_t type; mach_port_t port, process_port = get_process_port( thread->process ); - unsigned int dr7; + unsigned long dr[8]; kern_return_t ret;
/* all other regs are handled on the client side */ @@ -251,40 +251,70 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign return; }
- if (thread->process->machine == IMAGE_FILE_MACHINE_AMD64) + /* get the debug state to determine which flavor to use */ + ret = thread_get_state(port, x86_DEBUG_STATE, (thread_state_t)&state, &count); + if (ret) { - /* Mac OS doesn't allow setting the global breakpoint flags */ - dr7 = (context->debug.x86_64_regs.dr7 & ~0xaa) | ((context->debug.x86_64_regs.dr7 & 0xaa) >> 1); + mach_set_error( ret ); + goto done; + } + assert( state.dsh.flavor == x86_DEBUG_STATE32 || + state.dsh.flavor == x86_DEBUG_STATE64 ); + + switch (context->machine) + { + case IMAGE_FILE_MACHINE_I386: + dr[0] = context->debug.i386_regs.dr0; + dr[1] = context->debug.i386_regs.dr1; + dr[2] = context->debug.i386_regs.dr2; + dr[3] = context->debug.i386_regs.dr3; + dr[6] = context->debug.i386_regs.dr6; + dr[7] = context->debug.i386_regs.dr7; + break; + case IMAGE_FILE_MACHINE_AMD64: + dr[0] = context->debug.x86_64_regs.dr0; + dr[1] = context->debug.x86_64_regs.dr1; + dr[2] = context->debug.x86_64_regs.dr2; + dr[3] = context->debug.x86_64_regs.dr3; + dr[6] = context->debug.x86_64_regs.dr6; + dr[7] = context->debug.x86_64_regs.dr7; + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + goto done; + }
- state.dsh.flavor = x86_DEBUG_STATE64; + /* Mac OS doesn't allow setting the global breakpoint flags */ + dr[7] = (dr[7] & ~0xaa) | ((dr[7] & 0xaa) >> 1); + + if (state.dsh.flavor == x86_DEBUG_STATE64) + { state.dsh.count = sizeof(state.uds.ds64) / sizeof(int); - state.uds.ds64.__dr0 = context->debug.x86_64_regs.dr0; - state.uds.ds64.__dr1 = context->debug.x86_64_regs.dr1; - state.uds.ds64.__dr2 = context->debug.x86_64_regs.dr2; - state.uds.ds64.__dr3 = context->debug.x86_64_regs.dr3; + state.uds.ds64.__dr0 = dr[0]; + state.uds.ds64.__dr1 = dr[1]; + state.uds.ds64.__dr2 = dr[2]; + state.uds.ds64.__dr3 = dr[3]; state.uds.ds64.__dr4 = 0; state.uds.ds64.__dr5 = 0; - state.uds.ds64.__dr6 = context->debug.x86_64_regs.dr6; - state.uds.ds64.__dr7 = dr7; + state.uds.ds64.__dr6 = dr[6]; + state.uds.ds64.__dr7 = dr[7]; } else { - dr7 = (context->debug.i386_regs.dr7 & ~0xaa) | ((context->debug.i386_regs.dr7 & 0xaa) >> 1); - - state.dsh.flavor = x86_DEBUG_STATE32; state.dsh.count = sizeof(state.uds.ds32) / sizeof(int); - state.uds.ds32.__dr0 = context->debug.i386_regs.dr0; - state.uds.ds32.__dr1 = context->debug.i386_regs.dr1; - state.uds.ds32.__dr2 = context->debug.i386_regs.dr2; - state.uds.ds32.__dr3 = context->debug.i386_regs.dr3; + state.uds.ds32.__dr0 = dr[0]; + state.uds.ds32.__dr1 = dr[1]; + state.uds.ds32.__dr2 = dr[2]; + state.uds.ds32.__dr3 = dr[3]; state.uds.ds32.__dr4 = 0; state.uds.ds32.__dr5 = 0; - state.uds.ds32.__dr6 = context->debug.i386_regs.dr6; - state.uds.ds32.__dr7 = dr7; + state.uds.ds32.__dr6 = dr[6]; + state.uds.ds32.__dr7 = dr[7]; } ret = thread_set_state( port, x86_DEBUG_STATE, (thread_state_t)&state, count ); if (ret) mach_set_error( ret ); +done: mach_port_deallocate( mach_task_self(), port ); #endif }