Могу ли я сделать так, чтобы gdb перепрыгнул через оператор throw в конце функции? - PullRequest
4 голосов
/ 06 августа 2009

Когда я отлаживаю, я иногда нахожу полезным «воспроизвести» последние несколько утверждений кода. Например:

void foo (int & i) {
  i = 0;
  ++i;
  i++;
}

Во время выполнения этого через отладчик вы можете добавить точку останова вверху тела функции, а затем из любого оператора внутри foo, если вы введете: «jump file.cc:2», отладчик вернется обратно до i = 0. Я ценю, что это не всегда идеально, но иногда этого может быть достаточно, чтобы найти искомую ошибку.

В настоящее время я изучаю проблему, которая приводит к возникновению исключения. Исключение создается в нижней части вызываемой функции, поэтому что-то вроде:

void bar ()
{
  throw int ();
}

void foo (int & i)
{
  i = 0;
  ++i;

  bar ();

  i++;
}

int main ()
{
  try
  {
    int i;
    foo (i);
  }
  catch (...)
  {
  }
}

То, что я хочу сделать, - это поставить точку останова перед throw int (), затем перепрыгнуть только через это утверждение, завершить функциональную панель - чтобы я мог затем вернуться к строке i = 0 в Foo.

Есть ли способ, которым я могу перепрыгнуть через throw int () или закончить из bar без выполнения оператора throw?

Проблема заключается в том, что после throw нет оператора, поэтому мне некуда поставить точку останова, к которой я хочу перейти.

UPDATE:

Чтобы подчеркнуть, что происходит в моем простом примере выше:

This GDB was configured as "i486-slackware-linux"...
(gdb) break bar
Breakpoint 1 at 0x804856a: file t.cc, line 3.
(gdb) run
Starting program: ..../t 

Breakpoint 1, bar () at t.cc:3
(gdb) break t.cc:4
Breakpoint 2 at 0x8048592: file t.cc, line 4.
(gdb) jump t.cc:4
Line 4 is not in `bar()'.  Jump anyway? (y or n) y
Continuing at 0x8048592.

Breakpoint 2, foo (i=@0xb80155eb) at t.cc:6

Курчавое закрытие для 'bar' находится в строке 4 t.cc, однако GDB считает это точкой останова для foo.

Ответы [ 5 ]

5 голосов
/ 06 августа 2009

Мое плохое правописание фактически дало мне ответ!

Мой вариант «дизассемблирования» не работал, поэтому, ища правильное написание, я в конце концов наткнулся на «стек помощи»:

Изучение стека. Стек состоит из кадров стека. GDB присваивает номера стека кадров считая от нуля для самого внутреннего (выполняемого в данный момент) кадра.

В любой момент GDB идентифицирует один кадр как «выбранный» кадр. Переменный поиск выполняется относительно выбранного кадра. Когда отлаживаемая программа останавливается, GDB выбирает самый внутренний кадр. Приведенные ниже команды могут использоваться для выбора других кадров по номеру или адресу.

Список команд:

backtrace - печать обратной трассировки всех кадров стека

bt - Печать обратного следа всех кадров стека

down - Выбрать и напечатать кадр стека, вызываемый этим

frame - Выберите и напечатайте рамку стека

return - вернуть выбранный кадр стека к его вызывающему

select-frame - Выбрать рамку стека, ничего не печатая

up - Выбрать и напечатать кадр стека, который назвал этот

Команда return из приведенного выше списка делает именно то, что я хочу в этом случае.

Спасибо вам всем за помощь.

5 голосов
/ 06 августа 2009

Да, вы можете. Вам нужно установить указатель инструкции на нужное вам значение.

  (gdb) set $eip = 0xValue
2 голосов
/ 06 августа 2009

Расширяя ответ @ Джастина - находясь в функции bar() типа disassemble, запомните адрес инструкции ret, установите eip на этот адрес.

2 голосов
/ 06 августа 2009

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

void bar() {
  if (!debugFlag)
    throw int();
}

Убедитесь, что флаг является глобальным (не статическим), поэтому компилятор не может доказать, что он никогда не будет записан.

Чтобы пропустить бросок,

(gdb) set debugFlag = 1

И обязательно установите его позже.

1 голос
/ 06 августа 2009

%eip зависит от платформы и требует некоторой работы. Проще просто jump набрать номер строки с вьющимся концом. Вам нужно объединить это с тем, что предлагает bdonlan в случае, если компилятор оптимизирует возврат из функции как недоступный.

$ cat >x.cpp
#include <stdio.h>

static volatile int debug = 0;

void f() {
  if (!debug)
    throw 1;
}

int main() {
  try {
    f();
    puts("f didn't throw");
  } catch(...) {
    puts("f threw");
  }
  return 0;
}

$ g++ -g x.cpp -o x
$ gdb x
[...]
(gdb) run
Starting program: [...]/x 
Reading symbols for shared libraries . done
f threw

Program exited normally.
(gdb) break f
Breakpoint 1 at 0x1e30: file x.cpp, line 6.
(gdb) run
Starting program: [...]/x 

Breakpoint 1, f () at x.c:6
6         if (!debug)
(gdb) jump 8
Continuing at 0x1e73.
f didn't throw

Program exited normally.
...