用于改进代码可调试性的输入,除了日志和错误代码

除了错误代码,错误字符串和日志之外,是否还有其他function可以合并到代码中以增加在代码运行期间获取调试/跟踪信息,这有助于在运行时调试问题(或让我们知道发生了什么)?

以下是在分段错误时将堆栈跟踪发送到文件的代码示例

 #include 
 #include 
 #include 
 #include 

 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(清理);
     init_signals();
     printf(“关于通过将零分配给* s \ n来判断故障”);
     * s = 0;
     sigemptyset(&sigact.sa_mask);
    返回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)恐慌(“致命:程序被绞死\ n”);
     if(sig == SIGSEGV || sig == SIGBUS){
         dumpstack();
        恐慌(“致命:%s故障。记录StackTrace \ n”,(sig == SIGSEGV)?“分段”:((sig == SIGBUS)?“总线”:“未知”));
     }
     if(sig == SIGQUIT)恐慌(“QUIT信号结束程序\ n”);
     if(sig == SIGKILL)恐慌(“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);
    出口(-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);
    系统(DBX);
    返回;
 }

 void cleanup(void){
     sigemptyset(&sigact.sa_mask);
     / *在这里做任何清理工作* /
 }

在函数dumpstack ,需要更改dbx以适应您的调试器,例如GNU调试器的gdb ,几年前我在AIX机器上编程时使用了此代码。 注意如何设置信号,如果发生SIGSEGV故障,处理程序会将堆栈转储到扩展名为.dump的文件。 该代码演示了分段错误并转储堆栈跟踪。

这是我最喜欢的代码。

希望这会有所帮助,最好的问候,汤姆。

  • 在没有优化的情况下构建,以尽可能多地保留代码的“意图”
  • 在调试模式下构建,以添加符号信息
  • 不要剥离可执行文件(在Linux / Unix系统上),以保留尽可能多的符号信息供调试器使用

在为Linux构建时,我希望能够从信号处理程序中打印堆栈回溯 。 这有助于调试崩溃( SIGSEGV )或允许我向程序发送信号以在运行时启动堆栈回溯。 核心转储在调试崩溃时也很有用(同样在Linux中)。