2014-01-21 5 views
2

Я пытаюсь отлаживать программу на Debian, построенную с помощью gcc/g ++ (DEBUG=1 и NDEBUG undefined). Я использую стороннюю библиотеку и ее встроенную для отладки тоже (DEBUG=1, NDEBUG undefined, а также другие определения отладки). Библиотека представляет собой 150 тыс. Строк и содержит множество утверждений. Это хорошо.Изменить поведение assert для Debug (SIGABRT -> SIGTRAP)

В моем коде есть ошибка, и я пытаюсь отлаживать SQL-запрос сейчас. Это вызывает утверждение в сторонней библиотеке. Это нормально и его курс для курса.

Тем не менее, этот аргумент, обозначенный Posix, вызывает ошибку при запуске программы assert в библиотеке. Это бесполезное поведение при отладке для функции «debugging and diagnostic». Это должно быть одним из самых глупых решений этого комитета, и неудивительно, что многие люди редко используют его во время разработки.

Я хочу изменить поведение таким образом, чтобы при срабатывании assert он поднимал SIGTRAP, а не SIGABRT. Я немного ограничен, потому что я не писал стороннюю библиотеку (мой код использует MY_ASSERT, и он вызывает SIGTRAP, поэтому я могу продолжить и смотреть пути отрицательного кода).

Я знаю, что я могу установить или изменить обработчики сигналов через gdb, но gdb уже останавливается на SIGABRT перед передачей его программе и прерыванием. Я также попытался установить настраиваемый обработчик сигнала SIGABRT, который, похоже, не помогает, поскольку прерывание все еще происходит.

Как я могу изменить поведение assert, чтобы поднять SIGTRAP при отладке?

ответ

2

Для linux вы можете определить функцию __assert_fail, которая может поднять SIGTRAP, а не по умолчанию.

void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) { 
    fprintf(stderr, "Assert: %s failed at %s:%d in function %s", assertion, file, line, function); 
    raise(SIGTRAP); 
} 

Спецификация говорит, что вы на самом деле предполагается завершить программу в этой точке, и как функция объявлена ​​как имеющая __attribute__((noreturn)) в signal.h.

Вы можете добавить сомнительный код, как это (отредактированного использовать ptrace обнаружение с помощью fork, а не сигналы):

#include <assert.h> 
#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/ptrace.h> 

static int ptrace_failed; 

static int 
detect_ptrace(void) 
{ 
    int status, waitrc; 

    pid_t child = fork(); 
    if (child == -1) return -1; 
    if (child == 0) { 
     if (ptrace(PT_ATTACH, getppid(), 0, 0)) 
      exit(1); 
     do { 
      waitrc = waitpid(getppid(), &status, 0); 
     } while (waitrc == -1 && errno == EINTR); 
     ptrace(PT_DETACH, getppid(), (caddr_t)1, SIGCONT); 
     exit(0); 
    } 
    do { 
     waitrc = waitpid(child, &status, 0); 
    } while (waitrc == -1 && errno == EINTR); 
    return WEXITSTATUS(status); 
} 

__attribute__((constructor)) 
static void 
detect_debugger(void) 
{ 
    ptrace_failed = detect_ptrace(); 
} 

void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) { 
    fprintf(stderr, "Assert: %s failed at %s:%d in function %s\n", assertion, file, line, function); 
    if (ptrace_failed) 
     raise(SIGTRAP); 
    else 
     abort(); 
} 

Какие триггеры SIGTRAP при запуске под управлением GDB, но в противном случае вызывает SIGABRT. Я протестировал его, связавшись с ним, и через LD_PRELOAD, и он работает, как ожидалось.

+0

Спасибо Patesh, я попробую скоро. Я думаю, что мой другой выбор - это инъекция в трюки 'LD_PRELOAD', что для меня немного экстремально. Что, черт возьми, было мышлением Posix ..... – jww

+0

К сожалению, это не сработало, когда я протестировал, выполнив '__assert_fail' в исходном файле' main'. '__assert_fail' никогда не вызывался. – jww

+0

Платформа? Архитектура? Варианты компиляции? функция '__assert_fail' ** отображается на глобальном уровне (если нет, то она просто не работает)? Я протестировал его простым: 'int main (int argc, char ** argv) {assert (argc! = 1); } 'как основной метод, и он отлично справился с системой i386/x64. – Petesh