Подтвердить что ты не робот

Сделать gdb автоматически прекратить успешное завершение?

Я использую отладку script, которая последовательно запускает несколько связанных процессов с отладчиком. В настоящее время я использую -x для выполнения нескольких команд автоматически (например, run). Как я могу заставить gdb автоматически завершить работу после успешного завершения отладочного процесса? Добавление команды quit в файл команды приведет к тому, что эта команда будет обрабатываться не только при успешном завершении, но и при возникновении ошибок ( когда я предпочел бы взять на себя ответственность в этот момент).

Вот выдержка из того, что происходит:

+ gdb -return-child-result -x gdbbatch --args ./mkfs.cpfs /dev/loop0
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from /home/matt/cpfs/mkfs.cpfs...done.

Program exited normally.
Breakpoint 2 at 0x805224f: file log.c, line 32.
(gdb)

Содержание gdbbatch:

start
b cpfs_log if level >= WARNING
4b9b3361

Ответ 1

gdb устанавливает $_exitcode, когда программа успешно завершается. Вы можете использовать это - установите его в маловероятное значение в начале вашего script и только quit в конце, если оно изменилось:

set $_exitcode = -999
# ...
run
# ...
if $_exitcode != -999
  quit
end

(Установка $_exitcode в маловероятное значение немного уродлива, но в противном случае она не будет определена вообще, если программа не завершится, и, похоже, нет очевидного способа спросить "это переменная определена?" в условном.)

Ответ 2

Я думаю, что нашел полное решение вашего вопроса в связи с поиском чего-то подобного в Как заставить gdb отправить внешнее уведомление о получении сигнала?. Ни один из других ребята, похоже, не упомянул или не обнаружил gdb hooks.

Основываясь на подсказке Мэтью о $_exitcode, теперь это мое приложение /.gdbinit, которое обеспечивает именно то, что требуется; нормальный выход на успешное завершение и переход к подсказке gdb, отправка электронной почты, whatnot на все остальное:

set $_exitcode = -999
set height 0
handle SIGTERM nostop print pass
handle SIGPIPE nostop
define hook-stop
    if $_exitcode != -999
        quit
    else
        shell echo | mail -s "NOTICE: app has stopped on unhandled signal" root
    end
end
echo .gdbinit: running app\n
run

Ответ 3

У GDB есть другой "язык" для взаимодействия с автоматизированными программами под названием GDB/MI (подробный здесь), но, к сожалению, t выглядит так, как будто он поддерживает условные выражения, и ожидается, что он будет запускаться из других программ с разбором и разветвлением. Таким образом, похоже, что Expect - это самое простое (или, по крайней мере, работающее) решение:

$ cat gdbrunner
#!/usr/bin/expect -f

#spawn gdb -return-child-result --args ./mkfs.cpfs /dev/loop0
spawn gdb -return-child-result --args [lindex $argv 0]

#send "start\n"
#send "b cpfs_log if level >= WARNING"
send "run\n"

expect {
    normally\.         { send "quit\n" }
    "exited with code" { interact -nobuffer }
}

Я тестировал это с помощью простых программ:

$ cat prog1.c
int main(void) { return 0; }
$ cat prog2.c
int main(void) { return 1; }

Со следующими результатами:

$ ./gdbrunner ./prog1
spawn gdb -return-child-result --args ./prog1
run
(gdb) run
Starting program: /home/foo/prog1

Program exited normally.
(gdb) quit
$ ./gdbrunner ./prog2
spawn gdb -return-child-result --args ./prog2
run
(gdb) run
Starting program: /home/foo/prog2

Program exited with code 01.
(gdb)

По сути, вам нужно проанализировать вывод и ветвь, используя что-то еще. Разумеется, это будет работать с любой другой программой, способной обрабатывать ввод/вывод другого процесса, но выше ожидаемый script должен начать вас, если вы не возражаете против Tcl. Он должен быть немного лучше и ожидать первого (gdb) запроса, но работает из-за буферизации stdin.

Вы также можете изменить его, чтобы использовать этот интерфейс GDB/MI с аргументом командной строки -i для GDB; его команды и вывод немного более легко анализируются, если вы расширитесь, чтобы использовать более сложные функции, как вы можете видеть в ранее связанной документации.