除了错误代码、错误字符串和日志之外,是否还可以在代码中加入其他功能,在代码运行期间增加获取调试/跟踪信息的能力,以帮助调试问题(或让我们知道正在发生什么)?
除了错误代码、错误字符串和日志之外,是否还可以在代码中加入其他功能,在代码运行期间增加获取调试/跟踪信息的能力,以帮助调试问题(或让我们知道正在发生什么)?
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <stdarg.h>在函数
static void signal_handler(int); static void dumpstack(void); static void cleanup(void); void init_signals(void); void panic(const char *, ...);
struct sigaction sigact; char *progname;
int main(int argc, char **argv){ char *s; progname = *(argv); atexit(cleanup); init_signals(); printf("即将通过将零分配给*s来导致段错误\n"); *s = 0; sigemptyset(&sigact.sa_mask); return 0; }
void init_signals(void){ sigact.sa_handler = signal_handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV); sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS); sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT); sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP); sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL); sigaction(SIGKILL, &sigact, (struct sigaction *)NULL); }
static void signal_handler(int sig){ if (sig == SIGHUP) panic("致命错误:程序挂起\n"); if (sig == SIGSEGV || sig == SIGBUS){ dumpstack(); panic("致命错误:%s故障。已记录堆栈跟踪\n", (sig == SIGSEGV) ? "分段" : ((sig == SIGBUS) ? "总线" : "未知")); } if (sig == SIGQUIT) panic("QUIT信号结束程序\n"); if (sig == SIGKILL) panic("KILL信号结束程序\n"); if (sig == SIGINT) ; }
void panic(const char *fmt, ...){ char buf[50]; va_list argptr; va_start(argptr, fmt); vsprintf(buf, fmt, argptr); va_end(argptr); fprintf(stderr, buf); exit(-1); }
static void dumpstack(void){ /* 从http://www.whitefang.com/unix/faq_toc.html获取此例程 ** 第6.5节。修改以重定向到文件以防止杂乱无章 */ char dbx[160]; sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname); system(dbx); return; }
void cleanup(void){ sigemptyset(&sigact.sa_mask); /* 在这里执行任何清理任务 */ }
dumpstack
中,需要更改dbx
以适应您的调试器,例如GNU调试器gdb
。这段代码是我几年前在AIX平台上编程时使用的。请注意信号的设置,如果发生SIGSEGV故障,则处理程序将堆栈转储到扩展名为.dump
的文件中。该代码演示了分段错误并转储了堆栈跟踪。