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

Jinoh Kang jinoh.kang.kr at gmail.com
Wed Feb 9 10:34:15 CST 2022


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.)

>                     "movl 8(%esp),%eax\n\t"
>                     "movl 4(%esp),%esp\n\t"
>                     "jmp 5b" )
> diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
> index da89b958665..f8cddd15569 100644
> --- a/dlls/ntdll/unix/signal_x86_64.c
> +++ b/dlls/ntdll/unix/signal_x86_64.c
> @@ -349,7 +349,8 @@ struct syscall_frame
>      struct syscall_frame *prev_frame;    /* 00a0 */
>      SYSTEM_SERVICE_TABLE *syscall_table; /* 00a8 */
>      DWORD                 syscall_flags; /* 00b0 */
> -    DWORD                 align[3];      /* 00b4 */
> +    DWORD                 align;         /* 00b4 */
> +    ULONG64               unwind_rip;    /* 00b8 */
>      XMM_SAVE_AREA32       xsave;         /* 00c0 */
>      DECLSPEC_ALIGN(64) XSTATE xstate;    /* 02c0 */
>  };
> @@ -3278,6 +3279,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
>                     "5:\tmovl $0xc000000d,%edx\n\t" /* STATUS_INVALID_PARAMETER */
>                     "movq %rsp,%rcx\n"
>                     __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
> +                   "movq 0(%rsp),%r14\n\t"
> +                   "movq %r14,0xb8(%rcx)\n\t"      /* frame->unwind_rip */

Ditto.

>                     "movl 0xb0(%rcx),%r14d\n\t"     /* frame->syscall_flags */
>                     "movq %rdx,%rax\n\t"
>                     "jmp 2b" )


-- 
Sincerely,
Jinoh Kang



More information about the wine-devel mailing list