让 GDB 打印调用函数的控制流程

发布于 2024-07-09 10:49:17 字数 428 浏览 9 评论 0原文

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

我希望能够这样说(编造):

(gdb) trace Foo* Bar* printf

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

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

通配符(或等效的)是必不可少的,因为有很多 Foo 和 Bar 函数。 尽管我愿意记录所有功能。 或者,也许告诉 gdb 记录特定库中的所有函数。

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

How do I make gdb print functions of interest as they are called, indented according to how deep in the stack they are?

I want to be able to say something like (made up):

(gdb) trace Foo* Bar* printf

And have gdb print all functions which begin with Foo or Bar, as they are called. Kind of like gnu cflow, except using the debugging symbols and only printing functions which actually get called, not all possible call flows.

Tools which won't help include cachegrind, callgrind and oprofile, which order the results by which functions were called most often. I need the order of calling preserved.

The wildcarding (or equivalent) is essential, as there are a lot of Foo and Bar funcs. Although I would settle for recording absolutely every function. Or, perhaps telling gdb to record all functions in a particular library.

Some GDB wizard must have a script for this common job!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北凤男飞 2024-07-16 10:49:17

对于您的情况,我会转向 gdb 中的 define 命令,它允许您定义一个函数,该函数最多可以接受 10 个参数。

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

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

if $arg1
...

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

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

In your case I would turn to the define command in gdb, which allows you to define a function, which can take up to 10 arguments.

You can pass in the names of functions to "trace" as arguments to the function you define, or record them all in the function itself. I'd do something like the following

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

if $arg1
...

Arguments to a user-defined function in gdb are referenced as $arg0-$arg9. Alternatively, you could just record every function you wanted to trace in the function, instead of using $arg0-9.

Note: this will not indent as to depth in the stack trace, but will print the stack trace every time the function is called. I find this approach more useful than strace etc... because it will log any function you want, system, library, local, or otherwise.

甜警司 2024-07-16 10:49:17

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

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

请参阅此了解详细信息在断点上。

然后使用 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 打印回溯的最后一帧(即它是当前函数)c的快捷方式>continue,继续执行,end只是命令列表的分隔符。

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

There's rbreak cmd accepting regular expression for setting breakpoints. You can use:

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

See this for details on breakpoints.

Then use commands to print every function as it's called. E.g. let α = the number of the last breakpoint (you can check it with i br if you missed), then do:

(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) 

Some elaboration: silent suppresses unnecessary informational messages, bt 1 prints the last frame of backtrace (i.e. it's the current function), c is a shortcut for continue, to continue execution, and end is just the delimiter of command list.

NB: if you trace library functions, you may want to wait for lib to get loaded. E.g. set a break to main or whatever function, run app until that point, and only then set breakpoints you wanted.

临走之时 2024-07-16 10:49:17

您是否在此处看到了 litb 对类似帖子的出色回答 ?

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

基本上,您需要更改的是修改他的 gdb 命令脚本以从回溯中删除 1 深度以查看堆栈和过滤特定函数,并使用 awk/python/(...) 脚本重新格式化输出以将其呈现为树。 (我承认我现在懒得做……)

Did you see litb's excellent anwser to a similar post here ?

He uses readelf to get interesting symbols, gdb commands to get the trace, and awk to glue all that.

Basically what you have to change is to modify his gdb command script to remove the 1 depth from backtrace to see the stack and filter specific functions, and reformat the output with an awk/python/(...) script to present it as a tree. (I admit I'm too lazy to do it now...)

卖梦商人 2024-07-16 10:49:17

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

缩进更加困难,但是 bt 输出是有序的,因此当前函数位于跟踪的顶部,而 main 位于最底部。

因此,您使用命令创建文件:

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

然后运行 ​​gdb; -x

过滤以 # 开头的字符串 - 您将获得堆栈跟踪。

You may call gdb in batch mode (using -x option), break where you need and ask for backtrace (bt), then you filter the result using grep or egrep.

Indents are more difficult, however bt output is ordered so you have current function at the top of the trace and main at very bottom.

So you create file with commands:

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

then run gdb <program> -x<command file>

Filter strings that starts with #<digit> - you get stack trace.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文