Как выйти из gdb, если программа преуспевает, сломать, если программа аварийно завершает работу?

У меня, кажется, есть какая-то ошибка многопоточности в моем коде, которая заставляет его сбой один раз каждые 30 запусков его тестового набора. Набор тестов не является интерактивным. Я хочу запустить свой набор тестов в gdb и выйти из gdb нормально, если программа выходит нормально, или сломать (и показать приглашение отладки), если он аварийно завершает работу. Таким образом, я могу позволить тестовому набору работать несколько раз, выпить чашечку кофе, вернуться и получить хороший запрос на отладку. Как я могу сделать это с gdb?

7 ответов


Это немного hacky, но вы могли бы сделать:

gdb -ex='set confirm on' -ex=run -ex=quit --args ./a.out

если a.выход завершается нормально, он просто выпадет из GDB. Но если вы потерпите крах, программа все равно будет активна, поэтому GDB обычно предложит, если вы действительно хотите выйти с активным подчиненным:

Program received signal SIGABRT, Aborted.
0x00007ffff72dad05 in raise (sig=...) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    in ../nptl/sysdeps/unix/sysv/linux/raise.c
A debugging session is active.

    Inferior 1 [process 15126] will be killed.

Quit anyway? (y or n) 

как я уже сказал, не очень, но это работает, пока вы не отключили приглашение выйти с активным процессом. Вероятно, есть способ использовать gdb quit команда тоже: требуется числовое аргумент, который является кодом выхода для сеанса отладки. Поэтому, возможно, вы можете использовать --eval-command= "quit stuff", где stuff-это некоторое выражение GDB, которое отражает, работает ли подчиненный или нет.

эта программа может быть использована для тестирования:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    if (time(NULL) % 2) {
        raise(SIGINT);
    }
    puts("no crash");
    return EXIT_SUCCESS;
}

самый простой способ-использовать Python API предложил gdb:

 def exit_handler(event):
     gdb.execute("quit")

 gdb.events.exited.connect(exit_handler)

вы даже можете сделать это с помощью одной строки:

(gdb) gdb.events.exited.connect(lambda x : gdb.execute("quit")

вы также можете проверить код возврата, чтобы убедиться, что это" нормальный " код, который вы ожидали с event.exit_code.

вы можете использовать его в связке с --eval-command или --command как упоминалось @acm для регистрации обработчика событий из командной строки или с помощью .


вы также можете запустить backtrace при сбое программы и позволить gdb выйти с кодом возврата дочернего процесса:

gdb -return-child-result -ex run -ex "thread apply all bt" -ex "quit" --args myProgram -myProgramArg

сделать его дамп ядра, когда он падает. Если вы на linux, прочитайте man core man-страница, а также ulimit builtin, если вы работаете bash.

таким образом, когда он падает, вы найдете хороший corefile, который вы можете подать в gdb:

$ ulimit -c unlimited
$ ... run program ..., gopher coffee (or reddit ;)
$ gdb progname corefile

создайте файл с именем .gdbinit и он будет использоваться при запуске gdb.

run
quit

запуск без опций:

gdb --args prog arg1...

вы говорите gdb для запуска и выхода, но он должен прекратить обработку файла, если произойдет ошибка.


Если вы поместите следующие строки в ваш , gdb выйдет, когда ваша программа завершается с кодом состояния 0.

python

def exit_handler ( event ):
  if event .exit_code == 0:
    gdb .execute ( "quit" )

gdb .events .exited .connect ( exit_handler )

end

выше читайте ответ Кевина.


вы не получаете основной файл, когда он падает? Запустите gdb как это "ядро gdb-c" и выполните трассировку стека.

скорее всего, вы захотите использовать Valgrind.