首页 > *nix技术, 跟踪调试 > 如何对仅在指定调用路径下的函数断下断点

如何对仅在指定调用路径下的函数断下断点

2013年3月16日 发表评论 阅读评论 577 次浏览

举个例子,有示例代码如下:

[root@lenky test]# cat t.c
#include <stdio.h>

void foo()
{
    printf("foo\n");
}

void bar()
{
    foo();
}

void baz()
{
    foo();
}

int main()
{
    bar();
    baz();

    bar();
    baz();

    return 0;
}

对于函数foo()而言,有两条调用路径分别为:
1,main() -> bar() -> foo()
2,main() -> baz() -> foo()

那么如何仅在通过第2条路径执行到foo()函数时才断下来呢?办法是有的,演示如下:

[root@lenky test]# gcc -g t.c -o t
[root@lenky test]# gdb t -q
(gdb) source gdb_script
Breakpoint 1 at 0x80483ab: file t.c, line 15.
Breakpoint 2 at 0x804838a: file t.c, line 5.
(gdb) r
Starting program: /home/gqk/test/t
foo

Breakpoint 2, foo () at t.c:5
5           printf("foo\n");
(gdb) bt
#0  foo () at t.c:5
#1  0x080483b0 in baz () at t.c:15
#2  0x080483cd in main () at t.c:21
(gdb) c
Continuing.
foo
foo

Breakpoint 2, foo () at t.c:5
5           printf("foo\n");
(gdb) bt
#0  foo () at t.c:5
#1  0x080483b0 in baz () at t.c:15
#2  0x080483d7 in main () at t.c:24
(gdb) c
Continuing.
foo

Program exited normally.
(gdb) q
[root@lenky test]#

命令“source gdb_script”用于加载我的一个gdb脚本,根据显示来看,我在脚本里下了两个断点,其中Breakpoint 1在函数baz()处,而Breakpoint 2在函数foo()处。接着在通过命令r实际执行时,虽然函数foo()被调用了4次,但仅断下了2次,并且都是通过函数baz()调下来的路径被断了下来,达到了最初的设定目标。

下面再来解释我们是如何做的,很明显,这其中最重要的就是文件gdb_script:

[root@lenky test]# cat gdb_script

set breakpoint pending on

set $baz_enter = 0

b baz
commands
silent
set $baz_enter = 1
c
end

b foo if $baz_enter == 1
commands
set $baz_enter = 0
end

思路很简单,在执行到函数baz()时,设置变量$baz_enter为1,然后再执行到函数foo()时根据变量$baz_enter做条件断点。另外一些细节的处理无需多说。

可以将文件gdb_script改名为.gdbinit,这样gdb在启动时将自动读取和处理。

[root@lenky test]# mv gdb_script .gdbinit
[root@lenky test]# gdb t -q
Breakpoint 1 at 0x80483ab: file t.c, line 15.
Breakpoint 2 at 0x804838a: file t.c, line 5.
(gdb) q

本文介绍内容有什么实用场景?举个例子,比如内核代码中申请内存页面的逻辑有很多,但最终都会调入到__alloc_pages_nodemask()函数(以kernel 3.4.4为例),如果我只想断下从某条指定路径下来的情况,那么这里介绍的内容就有用了。

其它相关:

设置自动延后识别(避免提示“Make breakpoint pending on future shared library load?”):
set breakpoint pending on
也可以用
start
代替,即这样:
start # runs to main, so shared libraries are loaded
# after you reach main, GDB should have libc symbols, “puts” among them
break puts

设置屏幕大小(避免提示“gdb disable type return to continue or q return to quit”):
set width 0
set height 0
set verbose off

设置日志输出(转存调试日志):
set logging on #启用日志
set logging file /tmp/log.log #设置日志文件路径

参考资料:
http://sourceware.org/gdb/onlinedocs/gdb/Set-Breaks.html
http://sourceware.org/gdb/onlinedocs/gdb/Conditions.html#Conditions
http://sourceware.org/gdb/onlinedocs/gdb/Expressions.html#Expressions
http://sourceware.org/gdb/onlinedocs/gdb/Python.html#Python
http://stackoverflow.com/questions/10748501/automating-gdb-sessions

转载请保留地址:http://lenky.info/archives/2013/03/16/2244http://lenky.info/?p=2244


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.