我可以让gdb跳过函数末尾的throw语句吗?

时间:2009-08-06 15:40:09

标签: debugging gdb

当我调试时,我有时发现“重放”最后几个代码语句很有用。例如:

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

在通过调试器运行时,可以在函数体的顶部添加断点,然后在foo内的任何语句中添加一个断点,如果键入:“jump file.cc:2”调试器将返回i = 0。我很欣赏这并不总是完美的,但有时它足以找到你正在寻找的bug。

我正在调查导致异常被抛出的问题。异常被抛出在被调用函数的底部,所以类似于:

void bar ()
{
  throw int ();
}

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

  bar ();

  i++;
}

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

我希望能够做的是在throw int ()之前设置断点,然后跳过该语句,完成功能栏 - 这样我就可以跳回{{1在foo中行。

有没有办法可以跳过i = 0,或者在没有执行throw语句的情况下完成throw int ()

问题似乎是在bar之后没有声明,所以我无处可放置我想要跳转到的断点。

更新

要突出显示上面的简单示例中发生的事情:

throw

'bar'的近似卷曲位于't.cc'的第4行,但是gdb认为这是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 的断点。

5 个答案:

答案 0 :(得分:5)

是的,你可以。您需要将指令指针设置为您想要的值。

  (gdb) set $eip = 0xValue

答案 1 :(得分:5)

我的拼写错误实际上为我提供了答案!

我的“反汇编”变体不起作用,所以在寻找正确的拼写时,我最终偶然发现了“帮助堆栈”:

  

检查堆栈。   堆栈由堆栈帧组成。 Gdb为堆栈帧分配数字   从最内(当前正在执行)的帧开始从零开始计数。

     

任何时候gdb都将一帧标识为“选定”帧。   对所选帧进行变量查找。   当正在调试的程序停止时,gdb选择最里面的帧。   以下命令可用于按编号或地址选择其他帧。

     

命令列表:

     

backtrace - 打印所有堆栈帧的回溯

     

bt - 打印所有堆栈帧的回溯

     

down - 选择并打印由此调用的堆栈帧

     

frame - 选择并打印堆栈帧

     

return - 使选定的堆栈帧返回其调用者

     

select-frame - 选择一个不打印任何内容的堆栈帧

     

up - 选择并打印调用此框架的堆栈框架

上面列表中的 return 命令完全符合我的要求。

感谢大家的帮助。

答案 2 :(得分:2)

在许多情况下,编译器将消除函数的结束,因为它无法访问。你可能想制作一个你可以设置的标志来避免这种情况:

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

确保该标志是全局的(不是静态的),因此编译器无法证明它永远不会被写入。

跳过投掷,

(gdb) set debugFlag = 1

请务必稍后再将其设置回来。

答案 3 :(得分:2)

扩展@ Justin的答案 - 在bar()函数类型disassemble中,记下ret指令的地址,将eip设置为该地址。

答案 4 :(得分:1)

%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.