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
Docker Alpine Executable Binary Not Found Even If in Path
Makefile Command Substitution Problem
Receiving Udp Broadcast Packets on Linux
Can't Get Private Key with Openssl (No Start Line:Pem_Lib.C:703:Expecting: Any Private Key)
Why Do I Get "Suspended (Tty Output)" in One Terminal But Not in Others
Why Linux Kernel Use Trap Gate to Handle Divide_Error Exception
Differencebetween "Var=${Var:-Word}" and "Var=${Var:=Word}"
How to Read the Mouse Button State from /Dev/Input/Mice
Creating Permanent Executable Aliases
Embed Icc Color Profile in PDF
How to Increase the /Proc/Pid/Cmdline 4096 Byte Limit
Dependency Walker Equivalent for Linux
How to Point a Docker Image to My .M2 Directory for Running Maven in Docker on a MAC