Continue to debug after failed assertion on Linux?

前端 未结 5 709
萌比男神i
萌比男神i 2020-12-29 07:57

When an assertion fails with Visual C++ on Windows, the debugger stops, displays the message, and then lets you continue (or, if no debugging session is running, offers to l

相关标签:
5条回答
  • 2020-12-29 08:06

    You really want to recreate the behavior of DebugBreak. This stops the program in the debugger.

    My googling of "DebugBreak linux" has turned up several references to this piece of inline assembly which is supposed to do the same.

    #define DEBUG_BREAK asm("int $3")
    

    Then your assert can become

    #define ASSERT(TEST) if(!(TEST)) asm("int $3");
    

    According to Andomar int 3 causes the cpu to raise interrupt 3. According to drpepper a more portable way to do this would be to call:

     raise(SIGTRAP);
    
    0 讨论(0)
  • 2020-12-29 08:06

    You can replace assert with your own version which calls pause() instead of abort(). When the assertion fails, the program will pause and you can run gdb --pid $(pidof program) to examine the callstack and variables. An advantage of this approach is that the program does not need to be started under GDB.

    Header file (based on /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 */
    

    Implementation of assert_fail (based on assert.c in glibc):

    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();
    }
    
    0 讨论(0)
  • 2020-12-29 08:21

    You can configure gdb to handle specific signals in a different way. For example, the following will cause SIGSTOP not to be treated as a stoppable event.

    handle SIGSTOP nostop noprint pass

    help handle within gdb will give you more information.

    0 讨论(0)
  • 2020-12-29 08:25

    Even better usability is achieved with

    /*!
     * \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
    
    0 讨论(0)
  • 2020-12-29 08:28

    Have you tried to send a SIGCONT signal to the process?

    kill -s SIGCONT <pid>
    
    0 讨论(0)
提交回复
热议问题