在Linux上失败的断言后继续debugging?

当Windows上的Visual C ++断言失败时,debugging器停止,显示消息,然后让您继续(或者,如果没有debugging会话正在运行,则为您启动Visual Studio)。

在Linux上,似乎assert()的默认行为是显示错误并退出程序。 由于我所有的断言都是通过macros,我试图用信号来解决这个问题

#define ASSERT(TEST) if(!(TEST)) raise(SIGSTOP); 

但是,虽然GDB (通过KDevelop )停止在正确的点,我似乎无法继续超过信号,并在GDB手动发送信号,让我挂起,既不控制GDB也不debugging的过程。

Solutions Collecting From Web of "在Linux上失败的断言后继续debugging?"

你真的想重新创建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); 

您可以配置gdb以不同的方式处理特定的信号。 例如,以下将导致SIGSTOP不被视为可停止的事件。

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 

你有没有试图发送一个SIGCONT信号的过程?

 kill -s SIGCONT <pid> 

你可以用你自己的版本来代替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):

 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(); }