2009-11-12 21 views
15

Gdy asercja kończy się niepowodzeniem w programie Visual C++ w systemie Windows, debuger zatrzymuje się, wyświetla komunikat, a następnie pozwala kontynuować (lub, jeśli nie jest uruchomiona sesja debugowania, oferuje uruchomienie programu Visual Studio dla Ciebie).Kontynuuj debugowanie po niepowodzeniu asercji w systemie Linux?

W systemie Linux domyślnym zachowaniem assert() jest wyświetlenie błędu i zamknięcie programu. Ponieważ wszystkie moje twierdzi przejść makr, starałem się używać sygnałów, aby ominąć ten problem, jak

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

ale chociaż GDB (poprzez KDevelop) zatrzymuje się w odpowiednim momencie, nie wydaje się kontynuować obok sygnału i wysyłanie sygnału ręcznie w GDB po prostu pozostawia mnie w zawieszeniu, nie kontrolując ani GDB, ani debugowanego procesu.

Odpowiedz

18

Naprawdę chcesz odtworzyć zachowanie DebugBreak. Spowoduje to zatrzymanie programu w debugerze.

Moje googling "DebugBreak linux" okazało się several do tego kawałka wbudowanego zestawu, który ma zrobić to samo.

#define DEBUG_BREAK asm("int $3") 

Wtedy twój dochodzić może stać

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

Według Andomar int 3 powoduje cpu podnieść przerwania 3. Zgodnie drpepper bardziej przenośny sposób to zrobić byłoby zadzwonić :

raise(SIGTRAP); 
+1

Spowoduje to, że procesor podniesie przerwanie 3 (http://faydoc.tripod.com/cpu/int3.htm) Debugger ma program obsługi przerwań zarejestrowany dla przerwania 3 i złamie program. – Andomar

+0

idealne! łapie wydarzenie SIGTRAP, zatrzymuje się na bilonie, a następnie pozwala mi kontynuować! wielkie dzięki. – drpepper

+1

, aby uczynić go nieco bardziej przenośnym, zastąpiłem zespół równoważnym kodem: podniesienie (SIGTRAP); działa świetnie. – drpepper

10

Można skonfigurować gdb do obsługi określonych sygnałów w inny sposób. Na przykład poniższe polecenie spowoduje, że SIGSTOP nie będzie traktowany jako zdarzenie zatrzymane.

handle SIGSTOP nostop noprint pass

help handle wewnątrz gdb daje więcej informacji.

1

Czy próbowałeś wysłać sygnał SIGCONT do procesu?

kill -s SIGCONT <pid> 
+0

próbowałem, ale nic się nie dzieje ... – drpepper

2

Jeszcze lepszą użyteczność uzyskuje się dzięki

/*! 
* \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

Można zastąpić assert z własnej wersji, która nazywa pause() zamiast abort(). Kiedy asercja nie powiedzie się, program zatrzyma się i można uruchomić program gdb --pid $(pidof program), aby zbadać stację wywoławczą i zmienne. Zaletą tego podejścia jest to, że program nie trzeba uruchamiać pod GDB.

plik nagłówka (na podstawie /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 */ 

Realizacja assert_fail (na podstawie assert.c w 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

Och, miło. Posix naprawdę upuścił piłkę, gdy określili przerwanie, gdy 'NDBUG' nie jest zdefiniowany. Kto jest tam, gdzie myślisz, myśli, że samowolna awaria jest odpowiednia do debugowania i diagnostyki ... – jww

+0

Gdzie jest zadeklarowana funkcja "pauza"? – Brent

Powiązane problemy