Android _Unwind_Backtrace inside sigaction

I am trying to catch signals, such as SIGSEGV, in an Android NDK application for debugging purposes. For this, I configured sigaction, which is called.

Now I am trying to get a call stack. The problem is that _Unwind_Backtrace only works with current stacks and sigaction works inside its own stack.

So, is there a way to get the progress bar stack that received the signal? (Basically, say _Unwind_Backtrace to expand a different stack than the current one?)

I must indicate that:

  • Using backtrace() and backtrace_symbols() not an option since these functions are not shipped in Android NDK

  • I use GDB to investigate failures on local devices. I do not want to replace GDB, I want to be able to receive meaningful stack traces from the client when I send it a test assembly.

EDIT: I tried using Android libcorkscrew from the system / kernel, as suggested by fadden, but when I use the unind_backtrace_signal_arch function, I get a strange backtrace that does not constitute a failure.

+6
source share
2 answers

You can get the base address of the stack with pthread_getattr_np and pthread_attr_getstack , but what you really need is a PC and SP during the crash. On Linux, you can pull them out of ucontext .

If you set the SA_SIGINFO flag when setting up a signal handler, your handler function receives three arguments instead of one. The third argument to void* is the ucontext pointer. The accepted answer to this question explains a little more.

Once you have everything you can expand on the stack. If you don't mind going beyond what the NDK provides, Android libcorkscrew has features that can expand the stacks and output the results. This is used by the debuggerd daemons to dump their own failures into the log file.

It may be useful to know that the built-in failures logged by debuggerd generate stack dumps in /data/tombstones/ . File permissions make it inaccessible to regular applications, but on a modified device, you can just pull them out and send them.

+3
source

In my practice, the _Unwind_Backtrace standard could not switch to the preliminary signal stack.

I managed to get some packets before the signal by calling the internal libgcc __gnu_Unwind_Backtrace - it has an additional agrument, which is the "current registry value" - therefore it works with this stack and not with the current stack.

 //definitions copied from arm-specific libgcc 4.8 sources. struct core_regs { _uw r[16]; }; typedef struct { _uw demand_save_flags; struct core_regs core; } phase2_vrs; extern "C" _Unwind_Reason_Code __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, phase2_vrs * entry_vrs); // Getting backtrace with those definitions //istead of _Unwind_Backtrace(tracer, &state); if (const ucontext_t* signal_context = last_sigaction_parameter) { phase2_vrs pre_signal_state = {}; pre_signal_state.core = *reinterpret_cast<const core_regs*>(&(signal_context->uc_mcontext.arm_r0)); __gnu_Unwind_Backtrace(tracer, &state, &pre_signal_state); } 
+2
source

Source: https://habr.com/ru/post/950907/


All Articles