当我调试时,我有时发现“重放”最后几个代码语句很有用。例如:
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
的断点。
答案 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.