16

Windows上のVisualC++でアサーションが失敗すると、デバッガーが停止してメッセージを表示し、続行できるようにします(または、デバッグセッションが実行されていない場合は、Visual Studioの起動を提案します)。

Linuxでは、assert()のデフォルトの動作は、エラーを表示してプログラムを終了することのようです。すべてのアサートはマクロを通過するため、シグナルを使用してこの問題を回避しようとしました。

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

しかし、GDBKDevelopを介して)は正しいポイントで停止しますが、シグナルを超えて続行できないようです。GDB内でシグナルを手動で送信すると、GDBもデバッグされたプロセスも制御できず、ハングしたままになります。

4

5 に答える 5

19

あなたは本当にDebugBreakの振る舞いを再現したいと思っています。これにより、デバッガーのプログラムが停止します。

「DebugBreaklinux」をグーグルで検索すると、同じことを行うはずのこのインラインアセンブリへの参照がいくつか見つかりました。

#define DEBUG_BREAK asm("int $3")

その後、あなたの主張は

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

Andomar int 3によると、CPUは割り込み3を発生させます。drpepperによると、これを行うためのよりポータブルな方法は、次のように呼び出すことです。

 raise(SIGTRAP);
于 2009-11-12T11:28:50.450 に答える
10

特定のシグナルを別の方法で処理するようにgdbを構成できます。たとえば、次の場合、SIGSTOPは停止可能なイベントとして扱われません。

handle SIGSTOP nostop noprint pass

help handlegdb内でより多くの情報が得られます。

于 2009-11-12T11:26:43.637 に答える
2

さらに優れたユーザビリティは、

/*!
 * \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
于 2011-11-25T15:34:24.107 に答える
1

プロセスにSIGCONTシグナルを送信しようとしましたか?

kill -s SIGCONT <pid>
于 2009-11-12T11:28:23.227 に答える
1

の代わりにassert呼び出す独自のバージョンに置き換えることができます。アサーションが失敗すると、プログラムは一時停止し、実行してコールスタックと変数を調べることができます。このアプローチの利点は、GDBで開始する必要がないことです。pause()abort()gdb --pid $(pidof program)program

ヘッダーファイル(/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();
}
于 2012-12-03T15:23:22.037 に答える