avd*_*avd 22 c++ debugging gdb
我有一个C++函数,它在不同的地方有很多返回语句.如何在函数实际返回的return语句中设置断点?
什么"破坏"命令没有参数意味着什么?
Emp*_*ian 20
与目前为止的答案相反,大多数编译器将创建一个返回汇编指令,无论return
函数中有多少语句(编译器都方便这样做,因此只有一个地方可以执行所有堆栈帧清理).
如果你想停止该指令,你所要做的就是disas
寻找retq
(或处理器的返回指令),并在其上设置一个断点.例如:
int foo(int x)
{
switch(x) {
case 1: return 2;
case 2: return 3;
default: return 42;
}
}
int main()
{
return foo(0);
}
(gdb) disas foo
Dump of assembler code for function foo:
0x0000000000400448 <+0>: push %rbp
0x0000000000400449 <+1>: mov %rsp,%rbp
0x000000000040044c <+4>: mov %edi,-0x4(%rbp)
0x000000000040044f <+7>: mov -0x4(%rbp),%eax
0x0000000000400452 <+10>: mov %eax,-0xc(%rbp)
0x0000000000400455 <+13>: cmpl $0x1,-0xc(%rbp)
0x0000000000400459 <+17>: je 0x400463 <foo+27>
0x000000000040045b <+19>: cmpl $0x2,-0xc(%rbp)
0x000000000040045f <+23>: je 0x40046c <foo+36>
0x0000000000400461 <+25>: jmp 0x400475 <foo+45>
0x0000000000400463 <+27>: movl $0x2,-0x8(%rbp)
0x000000000040046a <+34>: jmp 0x40047c <foo+52>
0x000000000040046c <+36>: movl $0x3,-0x8(%rbp)
0x0000000000400473 <+43>: jmp 0x40047c <foo+52>
0x0000000000400475 <+45>: movl $0x2a,-0x8(%rbp)
0x000000000040047c <+52>: mov -0x8(%rbp),%eax
0x000000000040047f <+55>: leaveq
0x0000000000400480 <+56>: retq
End of assembler dump.
(gdb) b *0x0000000000400480
Breakpoint 1 at 0x400480
(gdb) r
Breakpoint 1, 0x0000000000400480 in foo ()
(gdb) p $rax
$1 = 42
Run Code Online (Sandbox Code Playgroud)
ks1*_*322 19
您可以使用反向调试来找出函数实际返回的位置.完成执行当前帧,执行reverse-step然后你应该停在刚返回的语句.
(gdb) record
(gdb) fin
(gdb) reverse-step
Run Code Online (Sandbox Code Playgroud)
打破当前功能的所有retq
这个Python命令retq
在当前函数的每个指令上放置一个断点:
class BreakReturn(gdb.Command):
def __init__(self):
super().__init__(
'break-return',
gdb.COMMAND_RUNNING,
gdb.COMPLETE_NONE,
False
)
def invoke(self, arg, from_tty):
frame = gdb.selected_frame()
# TODO make this work if there is no debugging information, where .block() fails.
block = frame.block()
# Find the function block in case we are in an inner block.
while block:
if block.function:
break
block = block.superblock
start = block.start
end = block.end
arch = frame.architecture()
pc = gdb.selected_frame().pc()
instructions = arch.disassemble(start, end - 1)
for instruction in instructions:
if instruction['asm'].startswith('retq '):
gdb.Breakpoint('*{}'.format(instruction['addr']))
BreakReturn()
Run Code Online (Sandbox Code Playgroud)
来源:
source gdb.py
Run Code Online (Sandbox Code Playgroud)
并使用命令:
break-return
continue
Run Code Online (Sandbox Code Playgroud)
你现在应该在retq
.
一直到retq
只是为了好玩,另一个实现在retq
找到a时停止(由于没有硬件支持而效率较低):
class ContinueReturn(gdb.Command):
def __init__(self):
super().__init__(
'continue-return',
gdb.COMMAND_RUNNING,
gdb.COMPLETE_NONE,
False
)
def invoke(self, arg, from_tty):
thread = gdb.inferiors()[0].threads()[0]
while thread.is_valid():
gdb.execute('ni', to_string=True)
frame = gdb.selected_frame()
arch = frame.architecture()
pc = gdb.selected_frame().pc()
instruction = arch.disassemble(pc)[0]['asm']
if instruction.startswith('retq '):
break
ContinueReturn()
Run Code Online (Sandbox Code Playgroud)
这将忽略您的其他断点.TODO:可以避免吗?
不确定它是否比它更快或更慢retq
.
可以在以下位置找到在给定操作码处停止的版本:https://stackoverflow.com/a/31249378/895245
不带参数的break在当前所选堆栈帧的下一条指令处停止执行.您可以通过frame
or up
和down
命令选择strack frames .如果要调试实际离开当前函数的点,请选择下一个外框并在那里中断.
rr
反向调试
与/sf/answers/255478891/record
提到的GDB相似,但是从GDB 7.11 到Ubuntu 16.04中的4.1.0,功能更多。rr
值得注意的是,它可以正确处理AVX:
这使其无法使用默认的标准库调用。
安装Ubuntu 16.04:
sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
sudo cpupower frequency-set -g performance
Run Code Online (Sandbox Code Playgroud)
但也可以考虑从源代码进行编译以获取最新更新,这并不难。
测试程序:
int where_return(int i) {
if (i)
return 1;
else
return 0;
}
int main(void) {
where_return(0);
where_return(1);
}
Run Code Online (Sandbox Code Playgroud)
编译并运行:
gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay
Run Code Online (Sandbox Code Playgroud)
现在您就处于GDB会话中,可以正确地进行调试了:
(rr) break main
Breakpoint 1 at 0x56057c458619: file a.c, line 9.
(rr) continue
Continuing.
Breakpoint 1, main () at a.c:9
9 where_return(0);
(rr) step
where_return (i=0) at a.c:2
2 if (i)
(rr) finish
Run till exit from #0 where_return (i=0) at a.c:2
main () at a.c:10
10 where_return(1);
Value returned is $1 = 0
(rr) reverse-step
where_return (i=0) at a.c:6
6 }
(rr) reverse-step
5 return 0;
Run Code Online (Sandbox Code Playgroud)
我们现在位于正确的返回线上。
归档时间: |
|
查看次数: |
20283 次 |
最近记录: |