ntdll: Add ARM EHABI unwind instructions in assembly functions.

On most ELF platforms on ARM, ARM EHABI is the unwind info
format normally used, instead of DWARF like on most other platforms.

Currently, when unwinding through ELF objects with libunwind, the
libraries don't have any .eh_frame section mapped at runtime (since
DWARF isn't used for unwinding). Instead, what happens is that
libunwind ends up loading .debug_frame from the libraries on disk
instead.

Therefore, currently, ELF unwinding relies on the .so files not being
stripped.

This patch adds the necessary EHABI unwinding instructions in the
assembly functions that currently have DWARF CFI instructions.

EHABI isn't signaled via any specific preprocessor macro, but
is signaled by the absence of other unwind mechanisms (such
as __ARM_DWARF_EH__ and __SEH__, or maybe SjLj).

Mark the asm functions in the preloaders as .cantunwind, to avoid
undefined references to __aeabi_unwind_cpp_pr* functions.

Also mark other assembly functions as .cantunwind; for
signal_exit_thread this is essential if the function is marked
with .fnstart/.fnend - otherwise exiting threads does hang.
(pthread_exit internally calls _Unwind_ForcedUnwind, which would
hang if signal_exit_thread had .fnstart without any matching unwind
info).

This would, in principle, allow unwinding through these functions with
libunwind, for versions of libunwind that can parse the EHABI unwind
info - see e.g.
4d779f55c0.
(This commit isn't yet in any current release AFAIK). Unwinding with
EHABI via libunwind would require a few tweaks to the libunwind interface
usage in unix/signal_arm.c though, since e.g. the unw_get_proc_info call
fails if there's no .eh_frame or .debug_frame available.

Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
Martin Storsjö 2022-10-20 13:44:24 +03:00 committed by Alexandre Julliard
parent 9d1175a464
commit f760976803
4 changed files with 35 additions and 1 deletions

View file

@ -1129,6 +1129,18 @@ __ASM_GLOBAL_FUNC( call_consolidate_callback,
__ASM_CFI(".cfi_escape 0x10,0x8e,0x02,0x03,0x7d,0xc0,0x01\n\t") /* DW_CFA_expression: D14 DW_OP_breg13 + 192 */
__ASM_CFI(".cfi_escape 0x10,0x8f,0x02,0x03,0x7d,0xc8,0x01\n\t") /* DW_CFA_expression: D15 DW_OP_breg13 + 200 */
#endif
/* These EHABI opcodes are to be read bottom up - they
* restore relevant registers from the CONTEXT. */
__ASM_EHABI(".save {sp}\n\t") /* Restore Sp last */
__ASM_EHABI(".pad #-(0x80 + 0x0c + 0x0c)\n\t") /* Move back across D0-D15, Cpsr, Fpscr, Padding, Pc, Lr and Sp */
__ASM_EHABI(".vsave {d8-d15}\n\t")
__ASM_EHABI(".pad #0x40\n\t") /* Skip past D0-D7 */
__ASM_EHABI(".pad #0x0c\n\t") /* Skip past Cpsr, Fpscr and Padding */
__ASM_EHABI(".save {lr, pc}\n\t")
__ASM_EHABI(".pad #0x08\n\t") /* Skip past R12 and Sp - Sp is restored last */
__ASM_EHABI(".save {r4-r11}\n\t")
__ASM_EHABI(".pad #0x14\n\t") /* Skip past ContextFlags and R0-R3 */
"ldrd r1, r2, [sp, #0x1a4]\n\t"
"mov r0, r2\n\t"
"blx r1\n\t"
@ -1327,6 +1339,7 @@ extern LONG __C_ExecuteExceptionFilter(PEXCEPTION_POINTERS ptrs, PVOID frame,
PUCHAR nonvolatile);
__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter,
"push {r4-r11,lr}\n\t"
__ASM_EHABI(".save {r4-r11,lr}\n\t")
__ASM_SEH(".seh_save_regs_w {r4-r11,lr}\n\t")
__ASM_SEH(".seh_endprologue\n\t")
@ -1439,8 +1452,10 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
*/
__ASM_STDCALL_FUNC( RtlRaiseException, 4,
"push {r0, lr}\n\t"
__ASM_EHABI(".save {r0, lr}\n\t")
__ASM_SEH(".seh_save_regs {r0, lr}\n\t")
"sub sp, sp, #0x1a0\n\t" /* sizeof(CONTEXT) */
__ASM_EHABI(".pad #0x1a0\n\t")
__ASM_SEH(".seh_stackalloc 0x1a0\n\t")
__ASM_SEH(".seh_endprologue\n\t")
__ASM_CFI(".cfi_adjust_cfa_offset 424\n\t")

View file

@ -593,6 +593,11 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
"push {r3}\n\t" /* Original Sp */
__ASM_CFI(".cfi_escape 0x0f,0x03,0x7D,0x04,0x06\n\t") /* CFA, DW_OP_breg13 + 0x04, DW_OP_deref */
__ASM_CFI(".cfi_escape 0x10,0x0e,0x02,0x7D,0x0c\n\t") /* LR, DW_OP_breg13 + 0x0c */
__ASM_EHABI(".save {sp}\n\t")
__ASM_EHABI(".pad #-12\n\t")
__ASM_EHABI(".save {pc}\n\t")
__ASM_EHABI(".pad #8\n\t")
__ASM_EHABI(".save {lr}\n\t")
/* We can't express restoring both Pc and Lr with CFI
* directives, but we manually load Lr from the stack
* in unwind_builtin_dll above. */
@ -1171,6 +1176,7 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B
* signal_start_thread
*/
__ASM_GLOBAL_FUNC( signal_start_thread,
__ASM_EHABI(".cantunwind\n\t")
"push {r4-r12,lr}\n\t"
/* store exit frame */
"str sp, [r3, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */
@ -1187,6 +1193,7 @@ __ASM_GLOBAL_FUNC( signal_start_thread,
* signal_exit_thread
*/
__ASM_GLOBAL_FUNC( signal_exit_thread,
__ASM_EHABI(".cantunwind\n\t")
"ldr r3, [r2, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */
"mov ip, #0\n\t"
"str ip, [r2, #0x1d4]\n\t"
@ -1200,6 +1207,7 @@ __ASM_GLOBAL_FUNC( signal_exit_thread,
* __wine_syscall_dispatcher
*/
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
__ASM_EHABI(".cantunwind\n\t")
"mrc p15, 0, r1, c13, c0, 2\n\t" /* NtCurrentTeb() */
"ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
"add r0, r1, #0x10\n\t"
@ -1276,6 +1284,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
* __wine_setjmpex
*/
__ASM_GLOBAL_FUNC( __wine_setjmpex,
__ASM_EHABI(".cantunwind\n\t")
"stm r0, {r1,r4-r11}\n" /* jmp_buf->Frame,R4..R11 */
"str sp, [r0, #0x24]\n\t" /* jmp_buf->Sp */
"str lr, [r0, #0x28]\n\t" /* jmp_buf->Pc */
@ -1293,6 +1302,7 @@ __ASM_GLOBAL_FUNC( __wine_setjmpex,
* __wine_longjmp
*/
__ASM_GLOBAL_FUNC( __wine_longjmp,
__ASM_EHABI(".cantunwind\n\t")
"ldm r0, {r3-r11}\n\t" /* jmp_buf->Frame,R4..R11 */
"ldr sp, [r0, #0x24]\n\t" /* jmp_buf->Sp */
"ldr r2, [r0, #0x28]\n\t" /* jmp_buf->Pc */

View file

@ -41,6 +41,12 @@
# define __ASM_CFI(str)
#endif
#if defined(__arm__) && defined(__ELF__) && defined(__GNUC__) && !defined(__SEH__) && !defined(__ARM_DWARF_EH__)
# define __ASM_EHABI(str) str
#else
# define __ASM_EHABI(str)
#endif
#if defined(__SEH__) || (defined(_MSC_VER) && defined(__clang__) && (defined(__x86_64__) || defined(__aarch64__)))
# if defined(__aarch64__) && defined(__clang_major__) && (__clang_major__ < 12 || defined(__apple_build_version__))
/* Clang got support for aarch64 SEH assembly directives in Clang 12,
@ -86,7 +92,7 @@
#define __ASM_DEFINE_FUNC(name,code) \
__ASM_BLOCK_BEGIN(__LINE__) \
asm(".text\n\t.align 4\n\t.globl " name "\n\t" __ASM_FUNC_TYPE(name) __ASM_SEH("\n\t.seh_proc " name) "\n" name ":\n\t" \
__ASM_CFI(".cfi_startproc\n\t") code __ASM_CFI("\n\t.cfi_endproc") __ASM_SEH("\n\t.seh_endproc") __ASM_FUNC_SIZE(name)); \
__ASM_CFI(".cfi_startproc\n\t") __ASM_EHABI(".fnstart\n\t") code __ASM_CFI("\n\t.cfi_endproc") __ASM_EHABI("\n\t.fnend") __ASM_SEH("\n\t.seh_endproc") __ASM_FUNC_SIZE(name)); \
__ASM_BLOCK_END
#define __ASM_GLOBAL_FUNC(name,code) __ASM_DEFINE_FUNC(__ASM_NAME(#name),code)

View file

@ -542,6 +542,7 @@ void *thread_data[256];
void _start(void);
extern char _end[];
__ASM_GLOBAL_FUNC(_start,
__ASM_EHABI(".cantunwind\n\t")
"mov r0, sp\n\t"
"sub sp, sp, #144\n\t" /* allocate some space for extra aux values */
"str r0, [sp]\n\t" /* orig stack pointer */
@ -564,6 +565,7 @@ __ASM_GLOBAL_FUNC(_start,
#define SYSCALL_FUNC( name, nr ) \
__ASM_GLOBAL_FUNC( name, \
__ASM_EHABI(".cantunwind\n\t") \
"push {r4-r5,r7,lr}\n\t" \
"ldr r4, [sp, #16]\n\t" \
"ldr r5, [sp, #20]\n\t" \
@ -576,6 +578,7 @@ __ASM_GLOBAL_FUNC(_start,
#define SYSCALL_NOERR( name, nr ) \
__ASM_GLOBAL_FUNC( name, \
__ASM_EHABI(".cantunwind\n\t") \
"push {r7,lr}\n\t" \
"mov r7, #" #nr "\n\t" \
"svc #0\n\t" \