除了日志和错误代码之外,提高代码可调试性的输入内容

4

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

3个回答

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

2
这是一段发送堆栈跟踪到文件的代码示例,当出现分段错误时触发。
#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的文件中。该代码演示了分段错误并转储了堆栈跟踪。
这是我最喜欢的代码。
希望这可以帮助到您。 最好的问候, 汤姆。

这对多线程代码有效吗?另外,如果我有一个库作为可交付成果,我也可以添加这个吗?这不会干扰应用程序的信号处理程序(如果存在)吗? - Jay
信号处理程序在所有线程之间共享:当线程调用sigaction()时,它不仅为自己设置信号处理方式,还为程序中的所有其他线程设置。您还可以查看backtrace(3)函数。 - jschmier

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接