GDB调试如何在return设置断点

GDB调试时常用设置断点的方法有:

1. 按照源文件代码,在某行设置断点,如:b **.cpp:40

2. 指定函数符号,在函数入口设置断点,如:b CBiPlayer::_CanAutoStart

这次遇到一个问题,用方法1在一条 return 语句设置断点,无法设置,查看断点信息,实际上断点是后续代码。

代码如:

001 // bi_player.cpp
...
180 CBiPlayer::_CanAutoStart(int)
181 {
...
189   if (m_mng) { ... }
...
199   if(!bAutoStart)
200     return ECANNOTAUTOSTART;
201
202   if(mng->GetActorNumber() < AutoStartMinPlayerCount())
203     return ECANNOTAUTOSTART;
204
...
207   if(!IsAllowAutoStart(modeid))
208     return ECANNOTAUTOSTART;
209
210   return mng->CanStartGame(param);
211 }

设置断点:b bi_player.cpp:200  实际是:bi_player.cpp:202

设置断点:b bi_player.cpp:203  实际是:bi_player.cpp:205

设置断点:b bi_player.cpp:208  实际是:bi_player.cpp:210

为什么呢?具体原因以后另开文章分析下,这里直接分析解决当前问题。

我们知道代码最终都会汇编成汇编代码,看看return这句汇编是啥样的。

查看汇编方法:

disassemble bi_player.cpp:CBiPlayer::_CanAutoStart

即使是对汇编熟悉的人,在遇到复杂函数时估计也难以下手。

为了定位某条语句的汇编代码,我用了比较简单的办法,单步调试:

首先,断点到函数入口:CBiPlayer::_CanAutoStart(这个断点可以设置在return前的语句,更快定位);

然后,用单步调试(step/next),和指令调试(stepi/nexti)找到return语句对应指令。

为了在调试过程显示代码行,需要设置:

display/i $pc

下面展示调试过程

(gdb) b CBiPlayer::_CanAutoStart
cBreakpoint 7 at 0x7f0279068a30: CBiPlayer::_CanAutoStart. (2 locations)
(gdb) c
Continuing.

Thread 1 hit Breakpoint 7, CBiPlayer::_CanAutoStart (this=0x225487a8, param=0) at /home/workspace/bi/core/bi_player.cpp:189
189 if (m_mng)
1: x/i $pc
=> 0x7f027c56c5a0 <CBiPlayer::_CanAutoStart(int)>:      push   r15
(gdb) c

Thread 1 hit Breakpoint 7, CBiPlayer::_CanAutoStart (this=0x225487a8, param=0) at /home/workspace/bi/core/bi_player.cpp:189
189 if (m_mng)
1: x/i $pc
=> 0x7f027c56c5a0 <CBiPlayer::_CanAutoStart(int)>:      push   r15

...


#====== 1. 断点到return前的条件语句


199 if(!bAutoStart)
1: x/i $pc
=> 0x7f027c56c6b1 <CBiPlayer::_CanAutoStart(int)+273>:  test   bl,bl


#====== 2. 开始指令级调试,发现 test 后是一条 je 跳转到 0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>


(gdb) si
0x00007f027c56c6b3      199 if(!bAutoStart)
1: x/i $pc
=> 0x7f027c56c6b3 <CBiPlayer::_CanAutoStart(int)+275>:  je     0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>

#====== 3. 继续指令级调试(空命令,代表继续上一次的命令

(gdb)
202 if(mng->GetActorNumber() < AutoStartMinPlayerCount())
1: x/i $pc
=> 0x7f027c56c6b9 <CBiPlayer::_CanAutoStart(int)+281>:  mov    rax,QWORD PTR [r12]
(gdb)
0x00007f027c56c6bd      202 if(mng->GetActorNumber() < AutoStartMinPlayerCount())
1: x/i $pc
=> 0x7f027c56c6bd <CBiPlayer::_CanAutoStart(int)+285>:  mov    rdi,r12
(gdb)
0x00007f027c56c6c0      202 if(mng->GetActorNumber() < AutoStartMinPlayerCount())
1: x/i $pc
=> 0x7f027c56c6c0 <CBiPlayer::_CanAutoStart(int)+288>:  call   QWORD PTR [rax+0x218]

...


#====== 4. 这里也是 jl 跳转到 0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>


(gdb)
0x00007f027c56c6d7      202 if(mng->GetActorNumber() < AutoStartMinPlayerCount())
1: x/i $pc
=> 0x7f027c56c6d7 <CBiPlayer::_CanAutoStart(int)+311>:  jl     0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>


...

(gdb)
0x00007f027c56c6ec      207 if(!IsAllowAutoStart(modeid))
1: x/i $pc
=> 0x7f027c56c6ec <CBiPlayer::_CanAutoStart(int)+332>:  mov    rdi,rbp

...



#======= 5. 同上 je 跳转到 0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>


(gdb)
0x00007f027c56c6f7      207 if(!IsAllowAutoStart(modeid))
1: x/i $pc
=> 0x7f027c56c6f7 <CBiPlayer::_CanAutoStart(int)+343>:  je     0x7f027c56c738 <CBiPlayer::_CanAutoStart(int)+408>
(gdb)
210 return mng->CanStartGame(param);
1: x/i $pc
=> 0x7f027c56c6f9 <CBiPlayer::_CanAutoStart(int)+345>:  mov    rax,QWORD PTR [r12]
(gdb) b 0x00007f027c56c738
Function "0x00007f027c56c738" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n


#======= 6. 从上面分析,return 都是最后跳转到相同的指令,可以在该指令处设置断点。然后会发现,这次断点成功设置在了 第 200 行。(一行高级语言汇编后可能对应多行指令)


(gdb) b *0x00007f027c56c738
Breakpoint 1 at 0x7f027c56c738: file /home/workspace/bi/core/bi_player.cpp, line 200.
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00007f027c56c6b1 in CBiPlayer::_CanAutoStart(int) at /home/workspace/bi/core/bi_player.cpp:199
        stop only if !bAutoStart
2       breakpoint     keep y   0x00007f027c56c6b9 in CBiPlayer::_CanAutoStart(int) at /home/workspace/bi/core/bi_player.cpp:202
        stop only if mng->GetActorNumber() < AutoStartMinPlayerCount()
3       breakpoint     keep y   0x00007f027c56c6e8 in CBiPlayer::_CanAutoStart(int) at /home/workspace/bi/core/bi_player.cpp:207
        stop only if !IsAllowAutoStart(modeid)
7       breakpoint     keep y   <MULTIPLE>
        breakpoint already hit 2 times
7.1                         y   0x00007f0279068a30 in std::string::_M_rep() const at /opt/rh/devtoolset-9/root/usr/include/c++/9/bits/basic_string.h:3366
7.2                         y   0x00007f027c56c5a0 in CBiPlayer::_CanAutoStart(int) at /home/workspace/bi/core/bi_player.cpp:189
8       breakpoint     keep y   0x00007f027c56c738 in CBiPlayer::_CanAutoStart(int) at /home/workspace/bi/core/bi_player.cpp:200

再来看看反汇编 0x00007f027c56c738 附近的指令:

   0x00007f027c56c730 <+400>:   pop    r15
   0x00007f027c56c732 <+402>:   ret
   0x00007f027c56c733 <+403>:   nop    DWORD PTR [rax+rax*1+0x0]
   0x00007f027c56c738 <+408>:   mov    r12d,0x1
   0x00007f027c56c73e <+414>:   mov    rdi,QWORD PTR [rsp+0x18]
   0x00007f027c56c743 <+419>:   test   rdi,rdi

把枚举值0x1设置给r12d作为返回值。

好了,简单总结下,优化后的代码如何在return语句设置断点:

1. 在return前一条语句设置断点;

2. 调试,命中断点后,采用指令级调试,si/ni;

3. 分析return语句最后的跳转目标指令;

4. 在跳转目标指令设置断点;

5. 继续调试,命中跳转目标指令处断点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值