4

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

4

3 回答 3

2
  • 无需优化即可构建,以尽可能多地保留代码的“意图”
  • 以调试模式构建,添加符号信息
  • 不要剥离可执行文件(在 Linux/Unix 系统上),以保留尽可能多的符号信息以供调试器使用
于 2010-02-01T15:12:20.327 回答
2

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

#include <stdio.h>
#include <信号.h>
#include <stdlib.h>
#include <stdarg.h>

静态无效信号处理程序(int);
静态无效转储堆栈(无效);
静态无效清理(无效);
无效初始化信号(无效);
无效恐慌(const char *,...);

结构 sigaction sigact;
字符 *progname;

int main(int argc, char **argv){
    字符 *s;
    程序名 = *(argv);
    退出(清理);
    初始化信号();
    printf("即将通过将零分配给 *s\n 来分段故障");
    *s = 0;
    sigemptyset(&sigact.sa_mask);
    返回0;
}

无效初始化信号(无效){
    sigact.sa_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);
}

静态无效信号处理程序(int sig){
    if (sig == SIGHUP) panic("致命:程序挂起\n");
    如果(信号 == SIGSEGV || 信号 == SIGBUS){
        转储堆栈();
        panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
    }
    if (sig == SIGQUIT) panic("QUIT 信号结束程序\n");
    if (sig == SIGKILL) panic("KILL 信号结束程序\n");
    if (sig == SIGINT) ;
}

无效恐慌(const char *fmt,...){
    字符缓冲区[50];
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(buf, fmt, argptr);
    va_end(argptr);
    fprintf(stderr, buf);
    退出(-1);
}

静态无效转储堆栈(无效){
    /* 从 http://www.whitefang.com/unix/faq_toc.html 得到这个例程
    ** 第 6.5 节。修改为重定向到文件以防止混乱
    */
    字符 dbx[160];
    sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
    系统(dbx);
    返回;
}

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

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

这是我最喜欢的代码。

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

于 2010-02-01T15:26:29.300 回答
1

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

于 2010-02-01T15:17:33.267 回答