linux – 如何在进程信号处理程序(armv7-uclibc)中获得适当的回溯?
作者:互联网
我已经多次谷歌为信号处理程序中的backtrace()找到正确的解决方案,并尝试了几乎所有的东西,但我无法在我的信号处理程序中成功获得回溯 – 这不是SIGUSR1处理程序.
>在uclibc config中启用UCLIBC_HAS_BACKTRACE = y并编译它
>验证了libubacktrace.so已创建
>使用以下选项编译我的应用程序二进制文件
-G
-rdynamic
-fexception或-funwind-tables
>二进制本身似乎被“剥离”
但是,我无法从信号处理程序中获得完整的回溯.
只打印了我在信号处理程序中调用的函数地址.
如果我使用target-gdb二进制文件并使用gdb –pid命令附加进程,我就可以正确地获得完整的回溯.
另外,我试过pstack但是(pstack-1.2 – 尝试了手臂补丁,但它很可怕……没有打印)不是很有帮助.
有什么建议?
1)Makefile中的编译器选项
CFLAGS = -g -fexceptions -funwind-tables -Werror $(WARN)…
2)代码
代码非常简单.
#define CALLSTACK_SIZE 10
static void print_stack(void) {
int i, nptrs;
void *buf[CALLSTACK_SIZE + 1];
char **strings;
nptrs = backtrace(buf, CALLSTACK_SIZE);
printf("%s: backtrace() returned %d addresses\n", __func__, nptrs);
strings = backtrace_symbols(buf, nptrs);
if(strings == NULL) {
printf("%s: no backtrace captured\n", __func__);
return;
}
for(i = 0; i < nptrs; i++) {
printf("%s\n", strings[i]);
}
free(strings);
}
...
static void sigHandler(int signum)
{
printf("%s: signal %d\n", __FUNCTION__, signum);
switch(signum ) {
case SIGUSR2:
// told to quit
print_stack();
break;
default:
break;
}
}
解决方法:
仔细阅读signal(7)和signal-safety(7).
信号处理程序仅限于(直接或间接)调用异步信号安全功能(实际上,仅大多数syscalls(2))和backtrace(3)甚至printf(3)或malloc(3)或免费不是异步信号安全.所以你的代码是不正确的:信号处理程序sigHandler正在调用printf并间接(通过print_stack)释放它们并且它们不是异步信号安全的.
因此,您唯一的选择是使用gdb调试器.
了解更多关于POSIX signal.h&实际上,信号处理程序可以做的几乎唯一合理的事情是设置一些全局,线程局部或静态易失性sig_atomic_t flag,必须在别处进行测试.它也可以直接write(2)到pipe(7)的几个字节,你的应用程序将在别处读取(例如,在它的事件循环中,如果它是一个GUI应用程序).
您也可以使用Ian Taylor的libbacktrace
from inside GCC(假设您的程序使用调试信息编译,例如使用-g).它不能保证在信号处理程序中工作(因为它不仅仅使用异步信号安全功能),但它实际上非常有用.
请注意,内核在处理信号时为sigreturn(2)设置了一个调用帧(在call stack中).
您也可以使用(特别是如果您的应用程序是单线程的)sigaltstack(2)具有备用信号堆栈.我不确定它会有所帮助.
如果您有事件循环,则可以考虑使用特定于Linux的signalfd(2)并请求您的事件循环轮询它.对于SIGTERM或SIGQUIT或SIGALRM,这是一个非常有用的技巧.
标签:linux,arm,uclibc 来源: https://codeday.me/bug/20190609/1204978.html