if there's any Frida hook (either via Interceptor or via NativeCallback swizzling like ObjC.implement) anywhere in the call stack between the raise and the catch of the exception, libunwind fails to find the exception handler, leading to uncaught exceptions which wouldn't happen without instrumentation.
When libunwind fails to unwind it usually means it can't resolve the unwind info, and it can happen for 2 different reasons:
libunwind asks dyld (via _dyld_find_unwind_sections()) but if the Frida agent is injected then dyld doesn't know about it and libunwind gives up on the first instruction pointer to any Frida agent's code in the stack (like normally happens for swizzling-like hooks)
in case of Interceptor instead, for function-aware hooks, the original return address on the stack is replaced with the one needed to implement onLeave() which belongs to a runtime-generated code thunk therefore missing its mapping to unwind info
The solution proposed here addresses the two above problems directly, via the new UnwindSitter component:
by hooking _dyld_find_unwind_sections to provide the right unwind info for the "invader"
by hooking UnwindCursor::setInfoBasedOnIPRegister() to call gum_invocation_stack_translate() on the return address to restore the original one on the stack at unwind-time
All this can be disabled via the "unwind-sitter:off" frida-agent option.
The problem this change intends to solve is that, currently, with code like this:
if there's any Frida hook (either via
Interceptor
or viaNativeCallback
swizzling likeObjC.implement
) anywhere in the call stack between the raise and the catch of the exception, libunwind fails to find the exception handler, leading to uncaught exceptions which wouldn't happen without instrumentation.When libunwind fails to unwind it usually means it can't resolve the unwind info, and it can happen for 2 different reasons:
_dyld_find_unwind_sections()
) but if the Frida agent is injected then dyld doesn't know about it and libunwind gives up on the first instruction pointer to any Frida agent's code in the stack (like normally happens for swizzling-like hooks)onLeave()
which belongs to a runtime-generated code thunk therefore missing its mapping to unwind infoThe solution proposed here addresses the two above problems directly, via the new
UnwindSitter
component:_dyld_find_unwind_sections
to provide the right unwind info for the "invader"UnwindCursor::setInfoBasedOnIPRegister()
to callgum_invocation_stack_translate()
on the return address to restore the original one on the stack at unwind-timeAll this can be disabled via the
"unwind-sitter:off"
frida-agent option.