您真的想重新创建DebugBreak的行为。这将停止调试器中的程序。
我在谷歌上搜索"DebugBreak linux",发现有几个参考文献提到此内联汇编代码可以实现相同效果。
#define DEBUG_BREAK asm("int $3")
那么您的断言可以变成这样:
#define ASSERT(TEST) if(!(TEST)) asm("int $3");
根据Andomar的说法,int 3会导致CPU触发中断3。而根据drpepper的说法,更加可移植的方法是调用:
raise(SIGTRAP);
handle SIGSTOP nostop noprint pass
在gdb中输入help handle
将提供更多信息。/*!
* \file: assert_x.h
* \brief: Usability Improving Extensions to assert.h.
* \author: Per Nordlöw
*/
#pragma once
#include <errno.h>
#include <signal.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(NDEBUG)
# define passert(expr) \
if (!(expr)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(expr)); raise(SIGTRAP); \
}
# define passert_with(expr, sig) \
if (!(expr)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(expr)); raise(sig); \
}
# define passert_eq(expected, actual) \
if (!(expected == actual)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' == `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(expected), __STRING(actual)); raise(SIGTRAP); \
}
# define passert_neq(expected, actual) \
if (!(expected != actual)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' != `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(expected), __STRING(actual)); raise(SIGTRAP); \
}
# define passert_lt(lhs, rhs) \
if (!(lhs < rhs)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' < `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(lhs), __STRING(rhs)); raise(SIGTRAP); \
}
# define passert_gt(lhs, rhs) \
if (!(lhs > rhs)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' < `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(lhs), __STRING(rhs)); raise(SIGTRAP); \
}
# define passert_lte(lhs, rhs) \
if (!(lhs <= rhs)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' <= `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(lhs), __STRING(rhs)); raise(SIGTRAP); \
}
# define passert_gte(lhs, rhs) \
if (!(lhs >= rhs)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' >= `%s' failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(lhs), __STRING(rhs)); raise(SIGTRAP); \
}
# define passert_zero(expr) \
if (!(expr == 0)) { \
fprintf(stderr, "%s:%d: %s: Assertion `%s' is zero failed.", \
__FILE__, __LINE__, __ASSERT_FUNCTION, __STRING(expr)); raise(SIGTRAP); \
}
#else
# define passert(expr)
# define passert_with(expr, sig)
# define passert_eq(expected, actual)
# define passert_lt(lhs, rhs)
# define passert_gt(lhs, rhs)
# define passert_lte(lhs, rhs)
# define passert_gte(lhs, rhs)
# define passert_zero(expr)
#endif
#ifdef __cplusplus
}
#endif
您可以将 assert
替换为自己的版本,该版本调用 pause()
而不是 abort()
。当断言失败时,程序将暂停,您可以运行 gdb --pid $(pidof program)
来检查调用栈和变量。这种方法的一个优点是,program
不需要在 GDB 下启动。
头文件(基于 /usr/include/assert.h):
#include <assert.h>
#ifndef NDEBUG
void assert_fail(const char *assertion, const char *file, unsigned line, const char *function)
__attribute__ ((noreturn));
#undef assert
#define assert(expr) \
((expr) \
? __ASSERT_VOID_CAST (0) \
: assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
#endif /* NDEBUG */
实现 assert_fail
(基于 glibc 中的 assert.c):
#include <stdio.h> /* for stderr, fprintf() */
#include <stdlib.h> /* for abort() */
#include <unistd.h> /* for pause() */
void assert_fail(const char *assertion, const char *file, unsigned line, const char *function) {
extern const char *__progname;
fprintf(stderr, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
__progname,
__progname[0] ? ": " : "",
file,
line,
function ? function : "",
function ? ": " : "",
assertion
);
pause();
abort();
}
NDBUG
未定义时,Posix在指定中止行为时真的失误了。谁会认为自我诱导的崩溃适用于调试和诊断呢…… - jwwpause()
在man. sec 2中定义,这是libc _et amici_部分。在我的副本(Debian 11)中,man pause.2
将兼容性列为“POSIX.1-2001、POSIX.1-2008、SVr4、4.3BSD”,这就说明了API的古老和广泛兼容性。示例代码只是缺少#include <unistd.h>
,我会进行编辑,感谢您的注意。 - kkmkill -s SIGCONT <pid>
else
时出现了故障。 - Lightness Races in Orbit