Как перейти к предыдущей строке в GDB? - PullRequest
60 голосов
/ 30 июля 2009

Возможно ли в 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 )
}

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

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

Ответы [ 9 ]

96 голосов
/ 09 октября 2009

Да! С новой версией 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.

12 голосов
/ 26 октября 2009

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

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

5 голосов

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

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

reverse.c

#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;
5 голосов
/ 06 августа 2009

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

Для обходного пути см. Ниже.

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

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

(GDB) команда 1

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

продолжение

конец

  • Поставьте точку останова на линии b.

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

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

2 голосов
/ 30 июля 2009

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

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

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

2 голосов
/ 30 июля 2009

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

1 голос
/ 28 марта 2016

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

enter image description here

0 голосов
/ 13 января 2015

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

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

jump 123

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

, затем вы можете пройти через код настройки или просто установить точку останова на «строке a» и продолжить

0 голосов
/ 30 июля 2009

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

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

...