我正在尝试在使用gcc / g ++构建的Debian上调试程序(DEBUG=1
和NDEBUG
未定义)。我正在使用第三方库,它也用于调试(DEBUG=1
,NDEBUG
未定义,以及其他调试定义)。该库是150K行,充满了断言。这很好。
我的代码有一个错误,我正在尝试调试SQL查询。它导致断言在第三方库中触发。这是好的,也是课程的标准。
但是,当assert
在库中触发时,脑死亡Posix指定的行为会导致程序崩溃。调试“debugging and diagnostic”功能时,这是无用的行为。这必须是该委员会最愚蠢的决定之一,难怪很多人很少在开发过程中使用它。
我想改变行为,以便在断言触发时,它会引发SIGTRAP
而不是SIGABRT
。我有点受限制,因为我没有写第三方库(我的代码使用MY_ASSERT
,并且它调用SIGTRAP
,所以我可以继续观看负代码路径。)
我知道我可以通过gdb安装或更改信号处理程序,但gdb已经在SIGABRT
停止,然后再将其传递给程序并中止。我还尝试安装一个自定义SIGABRT
信号处理程序,由于中止仍然存在,因此似乎没有帮助。
如何在调试时更改assert
的行为以提升SIGTRAP
?
答案 0 :(得分:2)
对于linux,您可以定义一个可以引发SIGTRAP
的{{3}}函数,而不是默认实现。
void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) {
fprintf(stderr, "Assert: %s failed at %s:%d in function %s", assertion, file, line, function);
raise(SIGTRAP);
}
规范说你实际上应该在此时终止程序,因为该函数在__attribute__((noreturn))
中被声明为signal.h
。
您可以添加一些像这样的iffy代码(通过ptrace
进行编辑以使用fork
检测而不是信号):
#include <assert.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ptrace.h>
static int ptrace_failed;
static int
detect_ptrace(void)
{
int status, waitrc;
pid_t child = fork();
if (child == -1) return -1;
if (child == 0) {
if (ptrace(PT_ATTACH, getppid(), 0, 0))
exit(1);
do {
waitrc = waitpid(getppid(), &status, 0);
} while (waitrc == -1 && errno == EINTR);
ptrace(PT_DETACH, getppid(), (caddr_t)1, SIGCONT);
exit(0);
}
do {
waitrc = waitpid(child, &status, 0);
} while (waitrc == -1 && errno == EINTR);
return WEXITSTATUS(status);
}
__attribute__((constructor))
static void
detect_debugger(void)
{
ptrace_failed = detect_ptrace();
}
void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) {
fprintf(stderr, "Assert: %s failed at %s:%d in function %s\n", assertion, file, line, function);
if (ptrace_failed)
raise(SIGTRAP);
else
abort();
}
在gdb下运行时触发SIGTRAP
,否则会触发SIGABRT
。我已经通过LD_PRELOAD
测试了它,并且似乎按预期工作了。