2009-11-12 12 views
15

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

Linuxでは、assert()のデフォルトの動作はエラーを表示してプログラムを終了するようです。すべての私がマクロを通過主張するので、私は

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

のように、この問題を回避するために信号を使用しようとしたが、(KDevelop経由)GDBが正しい位置で停止しますが、私は信号を過ぎて続けるように見えることはできませんGDB内で手動でシグナルを送信するだけで、GDBやデバッグされたプロセスを制御することができなくなります。

答えて

18

実際には、DebugBreakの動作を再作成する必要があります。これにより、デバッガでプログラムが停止します。

「DebugBreak linux」の私のグーグルが、同じことをするはずのこのインラインアセンブリにseveralreferencesとなっています。

#define DEBUG_BREAK asm("int $3") 

次に、あなたのアサートは、CPUがこれを行うために、よりポータブルな方法を呼び出すことであろう drpepper によると(3)割り込み上げるになりAndomar int型3によれば

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

になることができます:

raise(SIGTRAP); 
+1

CPUが割り込み3を発生させます(http://faydoc.tripod.com/cpu/int3。htm)デバッガには、割り込みハンドラ3が登録されており、プログラムが中断されます。 – Andomar

+0

完璧!それはSIGTRAPイベントをキャッチし、10セントで停止し、次に私に続けさせます!どうもありがとう。 – drpepper

+1

これをもう少し移植性の高いものにするために、アセンブリを同等のCコードに置き換えました。 raise(SIGTRAP); は素晴らしいです。 – drpepper

10

特定の信号を別の方法で処理するようにgdbを設定できます。たとえば、次のようにすると、SIGSTOPは停止可能なイベントとして扱われません。 GDB内

handle SIGSTOP nostop noprint pass

help handleあなたにより多くの情報を提供します。

1

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

kill -s SIGCONT <pid> 
+0

私はそれを試してみましたが、何も起こりそうにない... – drpepper

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 
1

あなたはpause()代わりのabort()呼び出し、独自のバージョンでassertを置き換えることができます。アサーションが失敗すると、プログラムは一時停止し、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 */ 

(glibcの中assert.cに基づく)assert_failの実装:

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

ああ、いいですね。 Posixは、 'NDBUG'が定義されていないときに、打ち切り動作を指定したとき、本当にボールを落としました。右心の中で、自己誘発クラッシュがデバッグと診断に適していると思う人は誰ですか? – jww

+0

"pause"関数はどこで宣言されていますか? – Brent

関連する問題