ntdll: Remove libunwind support for ARM.
Building for ARM with libunwind available has been broken since89f3c59739
, due to references to raise_func_trampoline that were left behind. In Linux builds, libunwind isn't practically needed sincea27b202a4d
(which implemented an internal EHABI unwinder). That unwinder currently only supports Linux, due to relying on dl_iterate_phdr, but if necessary, we could also try to detect support for dl_iterate_phdr in configure for other OSes. Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
parent
57b8d4c019
commit
4e9838fbc2
1 changed files with 12 additions and 104 deletions
|
@ -51,10 +51,6 @@
|
||||||
#ifdef HAVE_SYS_UCONTEXT_H
|
#ifdef HAVE_SYS_UCONTEXT_H
|
||||||
# include <sys/ucontext.h>
|
# include <sys/ucontext.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBUNWIND
|
|
||||||
# define UNW_LOCAL_ONLY
|
|
||||||
# include <libunwind.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LINK_H
|
#ifdef HAVE_LINK_H
|
||||||
# include <link.h>
|
# include <link.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -260,8 +256,6 @@ static BOOL is_inside_syscall( ucontext_t *sigcontext )
|
||||||
(char *)SP_sig(sigcontext) <= (char *)arm_thread_data()->syscall_frame);
|
(char *)SP_sig(sigcontext) <= (char *)arm_thread_data()->syscall_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher );
|
|
||||||
|
|
||||||
struct exidx_entry
|
struct exidx_entry
|
||||||
{
|
{
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
@ -559,11 +553,6 @@ static NTSTATUS ehabi_virtual_unwind( UINT ip, DWORD *frame, CONTEXT *context,
|
||||||
if (!set_pc)
|
if (!set_pc)
|
||||||
context->Pc = context->Lr;
|
context->Pc = context->Lr;
|
||||||
|
|
||||||
/* There's no need to check for raise_func_trampoline and manually restore
|
|
||||||
* Lr separately from Pc like with libunwind; the EHABI unwind info
|
|
||||||
* describes how both of them are restored separately, and as long as
|
|
||||||
* the unwind info restored Pc, it doesn't have to be set from Lr. */
|
|
||||||
|
|
||||||
TRACE( "next function pc=%08lx\n", context->Pc );
|
TRACE( "next function pc=%08lx\n", context->Pc );
|
||||||
TRACE(" r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
|
TRACE(" r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
|
||||||
context->R0, context->R1, context->R2, context->R3 );
|
context->R0, context->R1, context->R2, context->R3 );
|
||||||
|
@ -672,94 +661,6 @@ static const struct exidx_entry *find_exidx_entry( void *ip )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBUNWIND
|
|
||||||
static NTSTATUS libunwind_virtual_unwind( DWORD ip, DWORD *frame, CONTEXT *context,
|
|
||||||
PEXCEPTION_ROUTINE *handler, void **handler_data )
|
|
||||||
{
|
|
||||||
unw_context_t unw_context;
|
|
||||||
unw_cursor_t cursor;
|
|
||||||
unw_proc_info_t info;
|
|
||||||
int rc, i;
|
|
||||||
|
|
||||||
for (i = 0; i <= 12; i++)
|
|
||||||
unw_context.regs[i] = (&context->R0)[i];
|
|
||||||
unw_context.regs[13] = context->Sp;
|
|
||||||
unw_context.regs[14] = context->Lr;
|
|
||||||
unw_context.regs[15] = context->Pc;
|
|
||||||
rc = unw_init_local( &cursor, &unw_context );
|
|
||||||
|
|
||||||
if (rc != UNW_ESUCCESS)
|
|
||||||
{
|
|
||||||
WARN( "setup failed: %d\n", rc );
|
|
||||||
return STATUS_INVALID_DISPOSITION;
|
|
||||||
}
|
|
||||||
rc = unw_get_proc_info( &cursor, &info );
|
|
||||||
if (UNW_ENOINFO < 0) rc = -rc; /* LLVM libunwind has negative error codes */
|
|
||||||
if (rc != UNW_ESUCCESS && rc != -UNW_ENOINFO)
|
|
||||||
{
|
|
||||||
WARN( "failed to get info: %d\n", rc );
|
|
||||||
return STATUS_INVALID_DISPOSITION;
|
|
||||||
}
|
|
||||||
if (rc == -UNW_ENOINFO || ip < info.start_ip || ip > info.end_ip)
|
|
||||||
{
|
|
||||||
NTSTATUS status = context->Pc != context->Lr ?
|
|
||||||
STATUS_SUCCESS : STATUS_INVALID_DISPOSITION;
|
|
||||||
TRACE( "no info found for %x ip %x-%x, %s\n",
|
|
||||||
ip, info.start_ip, info.end_ip, status == STATUS_SUCCESS ?
|
|
||||||
"assuming leaf function" : "error, stuck" );
|
|
||||||
*handler = NULL;
|
|
||||||
*frame = context->Sp;
|
|
||||||
context->Pc = context->Lr;
|
|
||||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE( "ip %#x function %#lx-%#lx personality %#lx lsda %#lx fde %#lx\n",
|
|
||||||
ip, (unsigned long)info.start_ip, (unsigned long)info.end_ip, (unsigned long)info.handler,
|
|
||||||
(unsigned long)info.lsda, (unsigned long)info.unwind_info );
|
|
||||||
|
|
||||||
rc = unw_step( &cursor );
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
|
||||||
WARN( "failed to unwind: %d %d\n", rc, UNW_ENOINFO );
|
|
||||||
return STATUS_INVALID_DISPOSITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
*handler = (void *)info.handler;
|
|
||||||
*handler_data = (void *)info.lsda;
|
|
||||||
*frame = context->Sp;
|
|
||||||
|
|
||||||
for (i = 0; i <= 12; i++)
|
|
||||||
unw_get_reg( &cursor, UNW_ARM_R0 + i, (unw_word_t *)&(&context->R0)[i] );
|
|
||||||
unw_get_reg( &cursor, UNW_ARM_R13, (unw_word_t *)&context->Sp );
|
|
||||||
unw_get_reg( &cursor, UNW_ARM_R14, (unw_word_t *)&context->Lr );
|
|
||||||
unw_get_reg( &cursor, UNW_REG_IP, (unw_word_t *)&context->Pc );
|
|
||||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
|
||||||
|
|
||||||
if ((info.start_ip & ~(unw_word_t)1) ==
|
|
||||||
((unw_word_t)raise_func_trampoline & ~(unw_word_t)1)) {
|
|
||||||
/* raise_func_trampoline stores the original Lr at the bottom of the
|
|
||||||
* stack. The unwinder normally can't restore both Pc and Lr to
|
|
||||||
* individual values, thus do that manually here.
|
|
||||||
* (The function we unwind to might be a leaf function that hasn't
|
|
||||||
* backed up its own original Lr value on the stack.) */
|
|
||||||
const DWORD *orig_lr = (const DWORD *) *frame;
|
|
||||||
context->Lr = *orig_lr;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE( "next function pc=%08lx%s\n", context->Pc, rc ? "" : " (last frame)" );
|
|
||||||
TRACE(" r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
|
|
||||||
context->R0, context->R1, context->R2, context->R3 );
|
|
||||||
TRACE(" r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
|
|
||||||
context->R4, context->R5, context->R6, context->R7 );
|
|
||||||
TRACE(" r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
|
|
||||||
context->R8, context->R9, context->R10, context->R11 );
|
|
||||||
TRACE(" r12=%08lx sp=%08lx lr=%08lx pc=%08lx\n",
|
|
||||||
context->R12, context->Sp, context->Lr, context->Pc );
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* unwind_builtin_dll
|
* unwind_builtin_dll
|
||||||
*/
|
*/
|
||||||
|
@ -771,16 +672,23 @@ NTSTATUS unwind_builtin_dll( void *args )
|
||||||
DWORD ip = context->Pc - (dispatch->ControlPcIsUnwound ? 2 : 0);
|
DWORD ip = context->Pc - (dispatch->ControlPcIsUnwound ? 2 : 0);
|
||||||
#ifdef linux
|
#ifdef linux
|
||||||
const struct exidx_entry *entry = find_exidx_entry( (void *)ip );
|
const struct exidx_entry *entry = find_exidx_entry( (void *)ip );
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
if (entry)
|
if (entry)
|
||||||
return ehabi_virtual_unwind( ip, &dispatch->EstablisherFrame, context, entry,
|
return ehabi_virtual_unwind( ip, &dispatch->EstablisherFrame, context, entry,
|
||||||
&dispatch->LanguageHandler, &dispatch->HandlerData );
|
&dispatch->LanguageHandler, &dispatch->HandlerData );
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBUNWIND
|
status = context->Pc != context->Lr ?
|
||||||
return libunwind_virtual_unwind( ip, &dispatch->EstablisherFrame, context,
|
STATUS_SUCCESS : STATUS_INVALID_DISPOSITION;
|
||||||
&dispatch->LanguageHandler, &dispatch->HandlerData );
|
TRACE( "no info found for %lx, %s\n", ip, status == STATUS_SUCCESS ?
|
||||||
|
"assuming leaf function" : "error, stuck" );
|
||||||
|
dispatch->LanguageHandler = NULL;
|
||||||
|
dispatch->EstablisherFrame = context->Sp;
|
||||||
|
context->Pc = context->Lr;
|
||||||
|
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||||
|
return status;
|
||||||
#else
|
#else
|
||||||
ERR("libunwind not available, unable to unwind\n");
|
ERR("ARM EHABI unwinding available, unable to unwind\n");
|
||||||
return STATUS_INVALID_DISPOSITION;
|
return STATUS_INVALID_DISPOSITION;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue