Как перейти к предыдущей строке в GDB?

Возможно ли в gdb перейти на строку перед текущей выполняемой строкой. например:


void my_fun( somePtrType** arr,int start,int end)
{
 // arr is an array of pointers to somePtrType
  //line a
 ... some assignments
 swap(&arr[ind1] , &arr[ind2] ) ;
 //line b (current line )
}

Я нахожусь на линии б в настоящее время и могу изучить arr значения там, но я хочу вернуться к строке а и проверить содержимое arr в это время.

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

9 ответов

Решение

Да! С новой версией 7.0 GDB, вы можете сделать именно это!

Команда будет "reverse-step", или же "reverse-next".

Вы можете получить gdb-7.0 с ftp.gnu.org:/pub/gnu/gdb

Если вы столкнулись с ошибкой: Target child does not support this command. затем попробуйте добавить target record в начале исполнения, после запуска run,

Изменить: начиная с GDB 7,6 target record устарела, использовать target record-full вместо.

Да, это возможно, и прямо сейчас, с реальным оборудованием (то есть, не только с виртуальной машиной). GDB-7.0 поддерживает обратную отладку с помощью таких команд, как reverse-step и reverse-continue, на машинах с Linux x86.

Здесь есть учебное пособие: http://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial

Mozilla RR

https://github.com/mozilla/rr

Встроенная запись и воспроизведение GDB имеет серьезные ограничения, например, нет поддержки инструкций AVX: обратная отладка gdb завершается неудачно с "Запись процесса не поддерживает инструкцию 0xf0d по адресу"

Перевернутая сторона рр:

  • гораздо надежнее в настоящее время
  • также предлагает интерфейс GDB с протоколом gdbserver, что делает его отличной заменой
  • небольшое падение производительности для многих программ

В следующем примере демонстрируются некоторые из его функций, в частности reverse-next, reverse-step а также reverse-continue команды.

Установите Ubuntu 16.04:

sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
sudo cpupower frequency-set -g performance

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

Тестовая программа:

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

int f() {
    int i;
    i = 0;
    i = 1;
    i = 2;
    return i;
}

int main(void) {
    int i;

    i = 0;
    i = 1;
    i = 2;

    /* Local call. */
    f();

    printf("i = %d\n", i);

    /* Is randomness completely removed?
     * Recently fixed: https://github.com/mozilla/rr/issues/2088 */
    i = time(NULL);
    printf("time(NULL) = %d\n", i);

    return EXIT_SUCCESS;
}

скомпилируйте и запустите:

gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay

Теперь вы остались внутри сеанса GDB, и вы можете правильно отменить отладку:

(rr) break main
Breakpoint 1 at 0x55da250e96b0: file a.c, line 16.
(rr) continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;
(rr) next
17          i = 1;
(rr) print i
$1 = 0
(rr) next
18          i = 2;
(rr) print i
$2 = 1
(rr) reverse-next
17          i = 1;
(rr) print i
$3 = 0
(rr) next
18          i = 2;
(rr) print i
$4 = 1
(rr) next
21          f();
(rr) step
f () at a.c:7
7           i = 0;
(rr) reverse-step
main () at a.c:21
21          f();
(rr) next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) reverse-next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$5 = 1509245372
(rr) reverse-next
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$6 = 1509245372
(rr) reverse-continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;

Если ваша программа короткая, обычный трюк,

  1. Поместите новую точку останова на предыдущей строке
    • Пожар r перезапустить отладку

GDB был создан для этого!

Краткий ответ: Нет.

Обходной путь читайте ниже.

Хотя в строке b невозможно определить значение в строке a, можно записать значение arr в точках a и b и других местах только по одной точке прерывания, по которой ударили.

  • Используйте команду "display" (display variable_name, где variable_name должно быть заменено на arr, *arr, **arr, в зависимости от того, что вы ищете), чтобы при попадании на любую точку останова содержимое переменной name_name было помещено в экран. Обратите внимание, что вы можете добавить в список отображения, когда переменная variabe_name находится в области видимости, поэтому вам может потребоваться дождаться первой точки останова.
  • Создайте точки останова в различных местах кода, где вы заинтересованы, чтобы записать значение variable_name. Одна такая точка останова будет на линии а.
  • Для каждой точки останова используйте команду (команда breakpoint_number) и дайте указание вашей точке останова не останавливать выполнение программы. Команда, которую вам нужно использовать, это продолжить с последующим завершением. Смотрите пример ниже.

(GDB) команда 1

Введите команды, когда достигается точка останова 1, по одной на строку. Конец строки с надписью "конец".

Продолжить

конец

  • Поместите точку останова в строку b.

Теперь, когда все остальные точки прерывания журналирования достигнуты, значение arr будет выведено на экран, но точка останова не будет ожидать взаимодействия с пользователем и будет автоматически продолжаться. Когда вы достигаете точки останова в строке b, вы можете видеть прошлые значения arr, которые будут записываться в сам gdb.

В зависимости от ситуации вы также можете сбросить (и отобразить) много полезной информации. Например, вы можете также захотеть сбросить счетчик цикла (скажем, i), если вышеуказанная функция вызывается 10000 раз в цикле. Это действительно зависит от того, чего вы пытаетесь достичь.

Если ваш установочный код для arr чуть выше "строки a" (очень распространенный сценарий), вы можете сделать это следующим образом:

tbreak myfilename.c:123 (строка 123 - это начало кода настройки для arr), затем

jump 123

"Tbreak" не позволяет gdb продолжать (возобновлять) программу после перехода.

затем вы можете пройти через установочный код или просто установить точку останова на "линии А" и продолжить

В соответствии с http://sourceware.org/gdb/current/onlinedocs/gdb.html и "если целевая среда это поддерживает", да.

Не GDB, но вы можете легко вернуться в историю, используя отладчик qira. Вы можете использовать стрелки вверх и вниз для перемещения вперед и назад, а также подсвечивать, какие регистры изменились.

Каждый желает иметь Всезнающий Отладчик, как этот: http://www.lambdacs.com/debugger/, но их (в зависимости от языка / машины) сложно создать, и у них много работы по бухгалтерии.

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

Другие вопросы по тегам