Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android _Unwind_Backtrace inside sigaction

I am trying to catch signals such as SIGSEGV in my Android NDK app for debugging purpose. For that, I have set up a sigaction that is called.

I am now trying to get the stack of the call. The problem is that _Unwind_Backtrace only works on current stack and sigaction runs inside its own stack.

So, is there a way to get the stack of the execution pointer that received the signal? (Basically tell _Unwind_Backtrace to unwind another stack than the current?)

I should point out that :

  • Using backtrace() and backtrace_symbols() is not an option since those functions are not delivered in the Android NDK

  • I am using GDB to investigate crashes on my 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 him a test build.

EDIT: I have tried using Android's libcorkscrew from system/core as proposed by fadden but when I use it's unwind_backtrace_signal_arch function, I get a strange backtrace that do not represent the crash.

like image 593
Salomon BRYS Avatar asked Aug 02 '13 12:08

Salomon BRYS


2 Answers

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

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

Once you've got all that you can unwind the stack. If you don't mind stepping outside the bounds of what the NDK provides, Android's libcorkscrew has functions that can unwind stacks and output the results. This is used by the debuggerd daemon to dump native crashes to the log file.

It may be useful to know that native crashes logged by debuggerd generate stack dumps in /data/tombstones/. The file permissions render it inaccessible to normal apps, but on a modified device you could just pull these out and send them.

like image 128
fadden Avatar answered Oct 20 '22 01:10

fadden


In my practice standard _Unwind_Backtrace failed to switch to pre-signal stack.

I've managed to get some before-signal stacks by calling internal libgcc __gnu_Unwind_Backtrace - it has an extra agrument being "current registry values" - so it operates on given stack, not on 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);
}
like image 22
Vasily Galkin Avatar answered Oct 20 '22 01:10

Vasily Galkin