Any Porting Available of Backtrace for Uclibc

How to get proper backtrace in process signal handler (armv7-uclibc)?

Read carefully signal(7) and signal-safety(7).

A signal handler is restricted to call (directly or indirectly) only async-signal-safe-functions (practically speaking, most syscalls(2) only) and backtrace(3) or even printf(3) or malloc(3) or free are not async-signal-safe. So your code is incorrect: the signal handler sigHandler is calling printf and indirectly (thru print_stack) free and they are not async-signal-safe.

So your only option is to use the gdb debugger.

Read more about POSIX signal.h & signal concepts. Practically speaking, the nearly only sensible thing a signal handler can do is set some global, thread-local, or static volatile sig_atomic_t flag, which has to be tested elsewhere. It could also directly write(2) a few bytes into a pipe(7), that your application would read elsewhere (e.g. in its event loop, if it is a GUI application).

You could also use Ian Taylor's libbacktrace from inside GCC (assuming your program is compiled with debug info, e.g. with -g). It is not guaranteed to work in signal handlers (since it is not using only async-signal-safe functions), but it is practically quite useful.

Notice that the kernel is setting a call frame (in the call stack) for sigreturn(2) when processing a signal.

You might also use (especially if your application is single-threaded) sigaltstack(2) to have an alternate signal stack. I'm not sure it would be helpful.

If you have an event loop, you might consider using the Linux specific signalfd(2) and ask your event loop to poll it. For SIGTERM or SIGQUIT or SIGALRM it is a quite useful trick.

A simple, uniform and portable way of including tracing and backtracing into a C program

There is an implementation at RosettaCode.org which uses the same basic idea as @jsl4tv's suggestion.

Example, given the following classic C code with built in "hang":

#include <stdio.h>
#include <stdlib.h>

void inner(int k)
{
for(;;){} /* hang */
}

void middle(int x, int y)
{
inner(x*y);
}

void outer(int a, int b, int c)
{
middle(a+b, b+c);
}

int main()
{
outer(2,3,5);
return(EXIT_SUCCESS);
}

#define STACK_TRACE_ON and #include "stack_trace.h" from RosettaCode.org then insert BEGIN(f)/ENDs where required:

#include <stdio.h>
#include <stdlib.h>

#define STACK_TRACE_ON /* compile in these "stack_trace" routines */
#include "stack_trace.h"

void inner(int k)
BEGIN(inner)
print_indent(); printf("*** Now dump the stack ***\n");
print_stack_trace();
for(;;){} /* hang */
END

void middle(int x, int y)
BEGIN(middle)
inner(x*y);
END

void outer(int a, int b, int c)
BEGIN(outer)
middle(a+b, b+c);
END

int main()
BEGIN(main)
stack_trace.on = TRUE; /* turn on runtime tracing */
outer(2,3,5);
stack_trace.on = FALSE;
RETURN(EXIT_SUCCESS);
END

Produces:

stack_trace_test.c:19: BEGIN outer[0x80487b4], stack(depth:1, size:60)
stack_trace_test.c:14: BEGIN middle[0x8048749], stack(depth:2, size:108)
stack_trace_test.c:8: BEGIN inner[0x80486d8], stack(depth:3, size:156)
stack_trace_test.c:8: *** Now dump the stack ***
stack_trace_test.c:8: inner[0x80486d8] --- stack(depth:4, size:156) ---
stack_trace_test.c:14: middle[0x8048749] --- stack(depth:3, size:108) ---
stack_trace_test.c:19: outer[0x80487b4] --- stack(depth:2, size:60) ---
stack_trace_test.c:24: main[0x804882a] --- stack(depth:1, size:0) ---
stack_trace_test.c:8: --- (depth 4) ---

A well polished [open source] version of this BEGIN ~ END method would be perfect. (Esp if it has a "FINALLY" clause for exception handling).

Hints/URLs appreciated.

What is the usage of the backtrace at the top of threadx stacks and why it size varies?

Yes, the ARM and ARC ports are very different, i.e., different assembly code, pragmas, intrinsics, etc. It’s also noteworthy that different development tools are in play as well. For example, the main development tool for ARC is MetaWare (compiler/debugger), while on ARM there is IAR, ARM, GCC, etc.

As for stack backtrace, this is typically setup such that the debugger can create a call tree when there is a halt of execution or breakpoint in the current thread’s code. The backtrace byte pattern effectively represents the top of the stack and signals the debugger to stop building the call tree. Of course, this is every specific to the debugger and in this example the difference between the MetaWare debugger and the ARM tool debuggers. As for the 0xEF patter on the stack, this is useful for visual inspection by the developer. The pattern is also used by the run-time stack checking feature in ThreadX (please refer to the ThreadX User Guide documentation). Also, the IAR and MetaWare debuggers are able to calculate stack usage via examination of 0xEF pattern erosion in each thread’s stack and present that very useful information to the developer.



Related Topics



Leave a reply



Submit