【问题标题】:Make GDB print control flow of functions as they are called使 GDB 在调用函数时打印控制流
【发布时间】:2010-09-23 15:22:23
【问题描述】:

如何使 gdb 在调用时打印感兴趣的函数,根据它们在堆栈中的深度进行缩进?

我希望能够说出类似(编造)的话:

(gdb) trace Foo* Bar* printf

并让 gdb 打印所有以 Foo 或 Bar 开头的函数,因为它们被调用。有点像 gnu cflow,除了使用调试符号并且只打印实际调用的函数,而不是所有可能的调用流。

无法提供帮助的工具包括 cachegrind、callgrind 和 oprofile,它们对最常调用函数的结果进行排序。我需要保留调用顺序。

通配符(或等效的)是必不可少的,因为有很多 Foo 和 Bar funcs。虽然我会满足于记录每个功能。或者,也许告诉 gdb 记录特定库中的所有函数。

一些 GDB 向导必须有一个脚本来完成这个常见的工作!

【问题讨论】:

标签: c debugging dynamic gdb call-graph


【解决方案1】:

在你的情况下,我会求助于 gdb 中的 define 命令,它允许你定义一个函数,该函数最多可以接受 10 个参数。

您可以将函数的名称作为参数传递给您定义的函数以“跟踪”,或者将它们全部记录在函数本身中。我会做类似以下的事情

define functiontrace
if $arg0
    break $arg0
    commands
        where
        continue
        end
    end

if $arg1
...

gdb 中用户定义函数的参数引用为 $arg0-$arg9。或者,您可以只在函数中记录您想要跟踪的每个函数,而不是使用 $arg0-9。

注意:这不会缩进堆栈跟踪中的深度,但会在每次调用函数时打印堆栈跟踪。我发现这种方法比 strace 等更有用...因为它会记录您想要的 任何 函数、系统、库、本地或其他。

【讨论】:

    【解决方案2】:

    rbreak cmd 接受正则表达式来设置断点。您可以使用:

    (gdb) rbreak Foo.*
    (gdb) rbreak Bar.*
    (gdb) break printf
    

    See this 了解断点的详细信息。

    然后使用commands 打印调用的每个函数。例如。设 α = 最后一个断点的编号(如果错过了可以用i br查看),然后这样做:

    (gdb) commands 1-α
    Type commands for breakpoint(s) 1-α, one per line.
    End with a line saying just "end".
    >silent
    >bt 1
    >c
    >end
    (gdb) 
    

    一些详细说明:silent 抑制不必要的信息消息,bt 1 打印回溯的最后一帧(即它是当前函数)ccontinue 的快捷方式,以继续执行,end 只是命令列表的分隔符。

    注意:如果您跟踪库函数,您可能需要等待库被加载。例如。为main 或任何函数设置一个断点,运行应用程序直到该点,然后才设置你想要的断点。

    【讨论】:

    • 谢谢。关于我们如何在函数退出(返回)时进行跟踪的任何想法? (因为只跟踪调用了哪些函数,所以函数 A 调用 B 然后 C 与 A 调用 B 调用 C 的情况没有区别。)
    【解决方案3】:

    【讨论】:

    • 一个 GDB 脚本就足够了。
    【解决方案4】:

    您是否看到 litb 对类似帖子 here 的出色回答?

    他使用 readelf 获取有趣的符号,使用 gdb 命令获取跟踪,并使用 awk 粘合所有这些。

    基本上你需要改变的是修改他的 gdb 命令脚本以从回溯中删除 1 深度以查看堆栈和过滤特定功能,并使用 awk/python/(...) 脚本重新格式化输出以呈现它就像一棵树。 (我承认我现在懒得做……)

    【讨论】:

    • 这看起来是一个非常相似的问题,尽管更笼统的是我专门询问了 gdb(尽管我会对任何事情感到满意)。所有的答案似乎都是错误的。您指向的那个中断了一个特定的感兴趣的函数,并找到了它的所有调用者。我想要所有 func 调用。
    【解决方案5】:

    您可以在批处理模式下调用gdb(使用-x 选项),在需要的地方中断并请求回溯(bt),然后使用grepegrep 过滤结果。

    缩进更难,但是bt 输出是有序的,因此您在跟踪的顶部有当前函数,在最底部有main

    所以你用命令创建文件:

    br <function name where to break>
    run
    bt
    kill
    quit
    

    然后运行gdb &lt;program&gt; -x&lt;command file&gt;

    过滤以#&lt;digit&gt; 开头的字符串 - 你会得到堆栈跟踪。

    【讨论】:

    • 但这需要手动编写每个函数名,可能有数百个!
    猜你喜欢
    • 2022-11-27
    • 2012-01-24
    • 2012-01-12
    • 2014-02-01
    • 2022-01-24
    • 2014-01-20
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    相关资源
    最近更新 更多