1

我在将堆栈跟踪输出到 stderr 或转储到日志文件时遇到问题。我正在使用 gcc 编译器(4.4.3)在 Kubuntu10.04 中运行代码。问题是在正常运行模式下(没有gdb),程序除了'Segmentation Fault' 不输出任何东西。我希望在下面的打印语句中输出回溯输出。当我使用我的应用程序运行 gdb 时,它会出现 printf/fprintf/(function call) 语句,然后由于以下语句而崩溃:

669     {
(gdb) 
670       printf("Testing for stability.\n");
(gdb) 

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffff68b1f45 in puts () from /lib/libc.so.6

奇怪的是,如果我在同一个文件中调用一个崩溃的函数,它就可以正常工作,并且可以正常输出。但是如果程序在这个文件之外的函数中崩溃,它不会打印任何输出。因此,不会处理任何 printf 或文件转储语句或函数调用。我正在使用以下示例代码:

void bt_sighandler(int sig, siginfo_t *info,
               void *secret) {

void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
ucontext_t *uc = (ucontext_t *)secret;

/* Do something useful with siginfo_t */
if (sig == SIGSEGV)
  printf("Got signal %d, faulty address is %p, "
       "from %p\n", sig, info->si_addr, 
       uc->uc_mcontext.gregs[0]);
else
  printf("Got signal %d#92; \n", sig);

trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *) uc->uc_mcontext.gregs[0];

messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:#92; \n");
for (i=1; i<trace_size; ++i)
  printf("[bt] %s#92; \n", messages[i]);

exit(0);
}


int main() {

/* Install our signal handler */
struct sigaction sa;

sa.sa_sigaction = (void *)bt_sighandler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
/* Do something */
printf("%d#92; \n", func_b());
}

提前感谢您的帮助。

4

6 回答 6

3

不幸的是,您不能在 SIGSEGV 处理程序中可靠地做很多事情。这样想:你的程序有一个严重的错误,它的状态(包括堆这样的系统级状态)处于不一致的状态。

在这种情况下,您不能指望操作系统会神奇地修复堆和它需要的其他内部结构,以便能够在信号处理程序中执行任意代码。

如果 SEGV 发生在您自己的代码中,那么好的解决方案是使用核心并修复根本问题。如果核心通过共享库发生在其他代码中,我建议将该代码隔离在一个完全独立的二进制文件中并在两个二进制文件之间进行通信。然后,如果库崩溃,您的主程序不会。

于 2011-03-22T12:49:11.457 回答
2

您应该在信号处理程序中做的很少,原则上只访问 sig_atomic_t 类型的变量和 volatile 数据。

做 I/O 绝对是不可能的。请参阅此页面以了解 gcc:

http://www.gnu.org/s/libc/manual/html_node/Nonreentrancy.html#Nonreentrancy

于 2011-03-22T12:05:18.463 回答
0

你有理由不能使用valgrind吗?

于 2011-03-22T13:01:13.157 回答
0

当应用程序崩溃时,Linux 会创建一个核心转储,其中包含应用程序崩溃时的状态。可以使用 gdb 检查核心文件。

如果没有创建核心文件,请尝试更改核心文件大小

ulimit -c unlimited

在同一个shell中并且在程序启动之前。核心文件的名称通常是 core.PID,其中 PID 是程序的 pid。核心文件通常放在 /tmp 中的某个位置或程序启动的目录中。

有关核心文件的更多信息可在核心手册页上找到。利用

man core

阅读手册页。

于 2011-03-22T14:12:57.610 回答
0

我设法让它部分工作。实际上我是在“sudo”模式下运行应用程序的。在用户模式下运行它会给我调用堆栈。但是在用户模式下运行会禁用硬件加速(nvidia 图形驱动程序)。为了解决这个问题,我将自己添加到“视频”组,这样我就可以访问 /dev/nvidia0 和 /dev/nvidiactl。但是,当我获得访问权限时,堆栈不再生成。只有当我处于用户模式并且硬件加速被禁用时,堆栈才会到来。但是我不能在没有硬件加速的情况下运行我的应用程序(意味着一些重要的功能会被禁用)。如果有人有任何想法,请告诉我。

谢谢。

于 2011-03-25T06:12:05.413 回答
0

Try using simpler functions, such as strcat() and write().

于 2011-03-22T12:13:38.093 回答