[PATCH 2/4] ntdll: Keep track of syscall frame unix return addresses.

Rémi Bernon rbernon at codeweavers.com
Wed Feb 9 12:13:58 CST 2022


On 2/9/22 17:34, Jinoh Kang wrote:
> On 2/8/22 04:05, Rémi Bernon wrote:
>> For pthread_exit unwinding purposes, as libunwind needs to retrieve %rip
>> and we don't want to let it unwind the PE frames, we need to keep track
>> of a unix-only return address chain.
>>
>> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213
>> Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
>> ---
>>   dlls/ntdll/unix/signal_i386.c   | 7 +++++--
>>   dlls/ntdll/unix/signal_x86_64.c | 5 ++++-
>>   2 files changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
>> index 0e3b1daf51a..d98a3b1d4bb 100644
>> --- a/dlls/ntdll/unix/signal_i386.c
>> +++ b/dlls/ntdll/unix/signal_i386.c
>> @@ -463,9 +463,10 @@ struct syscall_frame
>>        * 32-bit mode, but some processors fault if they're not in writable memory.
>>        */
>>       DECLSPEC_ALIGN(64) XSTATE xstate;     /* 240 */
>> +    DWORD              unwind_eip;        /* 380 */
>>   };
>>   
>> -C_ASSERT( sizeof(struct syscall_frame) == 0x380 );
>> +C_ASSERT( sizeof(struct syscall_frame) == 0x3c0 );
>>   
>>   struct x86_thread_data
>>   {
>> @@ -2432,7 +2433,7 @@ __ASM_GLOBAL_FUNC( signal_start_thread,
>>                      "movl 0x1f8(%ecx),%eax\n\t"  /* x86_thread_data()->syscall_frame */
>>                      "orl %eax,%eax\n\t"
>>                      "jnz 1f\n\t"
>> -                   "leal -0x380(%esp),%eax\n\t" /* sizeof(struct syscall_frame) */
>> +                   "leal -0x3c0(%esp),%eax\n\t" /* sizeof(struct syscall_frame) */
>>                      "andl $~63,%eax\n\t"
>>                      "movl %eax,0x1f8(%ecx)\n"    /* x86_thread_data()->syscall_frame */
>>                      "1:\tmovl %eax,%esp\n\t"
>> @@ -2591,6 +2592,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
>>                      "6:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
>>                      "jmp 5b\n"
>>                      __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
>> +                   "movl 0(%esp),%eax\n\t"
>> +                   "movl %eax,0x380(%esp)\n\t"     /* frame->unwind_eip */
> 
> We can't unwind to the caller without also saving the caller's nonvolatile registers.
> Also, KeUserModeCallback is one of the callers of __wine_syscall_dispatcher_return, and returning to it would not be useful since it is usually called from PE modules anyway.
> Maybe just use prev_frame directly, and set unwind_eip to an hardcoded address?
> (Speaking of which, we could use .cfi_val_encoded_addr here, but it's a GNU-only extension AFAIK.)
> 

Hmm, I'm pretty sure that KeUserModeCallback is meant to be called from 
the unix side (although it's a Windows kernel API, it is meant to be 
called from kernel mode, which is our unix world), and would switch back 
to the PE stack, pushing a new syscall frame on the unix stack.

What I meant to do here, is to keep track of the unix caller (so either 
call_init_thunk or KeUserModeCallback), so that we will later link to it 
when a new syscall will be done, to the exit frame, as if we were 
returning to call_init_thunk and wherever the thread was started from, 
when the thread exits.

Regarding the registers, I think it's what __wine_setjmpex does, no? 
Otherwise it would have trouble already. Maybe call_init_thunk should do 
it too, although it's never supposed to returning to it normally (only 
through unwinding in pthread_exit).
-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list