C 除了日志和错误代码之外,用于提高代码可调试性的输入
除了错误代码、错误字符串和日志之外,代码中是否还有其他功能可用于增加代码运行时获取调试/跟踪信息的能力,从而有助于在运行时调试问题(或让我们知道发生了什么情况?C 除了日志和错误代码之外,用于提高代码可调试性的输入,c,code-maintainability,C,Code Maintainability,除了错误代码、错误字符串和日志之外,代码中是否还有其他功能可用于增加代码运行时获取调试/跟踪信息的能力,从而有助于在运行时调试问题(或让我们知道发生了什么情况? 在不进行优化的情况下构建,以尽可能多地保留代码的“意图” 在调试模式下生成,以添加符号信息 不要剥离可执行文件(在Linux/Unix系统上),以保留尽可能多的符号信息供调试器使用 在为Linux构建时,我希望能够从信号处理程序打印一个。这有助于调试崩溃(SIGSEGV)或允许我向程序发送信号,以便在运行时启动堆栈回溯。在调试崩溃时也很
- 在不进行优化的情况下构建,以尽可能多地保留代码的“意图”
- 在调试模式下生成,以添加符号信息
- 不要剥离可执行文件(在Linux/Unix系统上),以保留尽可能多的符号信息供调试器使用
SIGSEGV
)或允许我向程序发送信号,以便在运行时启动堆栈回溯。在调试崩溃时也很有用(同样在Linux中)。下面是一个代码示例,该代码在出现分段错误时向文件发送堆栈跟踪
#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("About to seg fault by assigning zero to *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("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\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){
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
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);
/* Do any cleaning up chores here */
}
#包括
#包括
#包括
#包括
静态无效信号处理器(int);
静态无效转储堆栈(void);
静态空洞清理(空洞);
void init_信号(void);
无效恐慌(常量字符*,…);
struct-sigaction-sigact;
字符*程序名;
int main(int argc,字符**argv){
char*s;
progname=*(argv);
脱欧(清理);
初始化信号();
printf(“即将通过将零赋值给*s\n来隔离故障”);
*s=0;
sigemptyset(&sigact.sa_mask);
返回0;
}
无效初始信号(无效){
sigact.sa_handler=信号_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_标志=0;
sigaction(SIGINT,&sigact,(struct-sigaction*)NULL);
sigaddset(&sigact.sa_mask,SIGSEGV);
sigaction(SIGSEGV,&sigact,(struct-sigaction*)NULL;
sigaddset(&sigact.sa_掩码,SIGBUS);
sigaction(SIGBUS,&sigact,(结构sigaction*)NULL);
sigaddset(&sigact.sa_mask,SIGQUIT);
sigaction(SIGQUIT,&sigact,(struct-sigaction*)NULL);
sigaddset(&sigact.sa_mask,SIGHUP);
sigaction(SIGHUP,&sigact,(struct-sigaction*)空值;
sigaddset(&sigact.sa_mask,SIGKILL);
sigaction(SIGKILL,&sigact,(struct-sigaction*)NULL);
}
静态无效信号处理器(int sig){
if(sig==SIGHUP)恐慌(“致命:程序挂起\n”);
if(sig==SIGSEGV | | sig==SIGBUS){
转储堆栈();
死机(“致命:%s故障。记录的堆栈跟踪\n”,(sig==SIGSEGV)?“分段”:((sig==SIGBUS)?“总线”:“未知”);
}
如果(sig==SIGQUIT)死机(“退出信号结束程序\n”);
如果(sig==SIGKILL)死机(“终止信号结束程序\n”);
如果(sig==SIGINT);
}
无效恐慌(常量字符*fmt,…){
char-buf[50];
va_列表参数;
va_启动(argptr、fmt);
vsprintf(buf、fmt、argptr);
va_端(argptr);
fprintf(标准,基本单位);
出口(-1);
}
静态void转储堆栈(void){
/*这套动作是从http://www.whitefang.com/unix/faq_toc.html
**第6.5节修改为重定向到文件以防止混乱
*/
char-dbx[160];
sprintf(dbx,“echo'where\n附加'| dbx-a%d>%s.dump',getpid(),progname);
系统(dbx);
返回;
}
空洞清理(空洞){
sigemptyset(&sigact.sa_mask);
/*这里有打扫家务的事吗*/
}
在函数dumpstack
中,dbx
需要更改以适合您的调试器,例如gdb
对于GNU调试器,这段代码是几年前我在AIX box上编程时使用的。注意信号是如何设置的,如果发生SIGSEGV故障,处理程序会将堆栈转储到扩展名为.dump
的文件中。代码演示分段错误并转储stacktrace
这是我最喜欢的代码
希望这有帮助,
顺致敬意,
Tom。这对多线程代码有效吗?另外,如果我有一个库作为可交付成果,我可以把它也添加到其中吗?如果存在,这不会干扰应用程序的信号处理程序吗?信号处理程序在所有线程之间共享:当线程调用sigaction()时,它不仅为自身设置信号处理方式,还为程序中的所有其他线程设置信号处理方式。您还可以查看backtrace(3)函数。