【问题标题】:how can I put a breakpoint on "something is printed to the terminal" in gdb?如何在 gdb 中的“某些内容已打印到终端”上设置断点?
【发布时间】:2009-10-08 15:11:43
【问题描述】:

我想知道从巨大应用程序内部的哪个位置打印特定消息。该应用程序又大又旧,以至于它使用所有可以想象的方式将文本打印到终端;例如 printf()、fprintf(stdout, ...) 等。

我写是为了在 write() 系统调用上放置一个断点,但由于各种文件 I/O 操作也使用 write(),我被太多的断点停止所淹没。

所以基本上我希望 gdb 在程序向终端打印内容时停止,但同时我不希望 gdb 在程序向文件写入内容时停止。

【问题讨论】:

标签: gdb printf breakpoints conditional-breakpoint


【解决方案1】:

使用条件断点检查第一个参数。在 64 位 x86 系统上,条件是:

(gdb) b 写 if 1==$rdi

在 32 位系统上,它更复杂,因为参数在堆栈上,这意味着您需要将 $esp 转换为 int * 并索引 fd 参数。此时的堆栈有返回地址、长度、缓冲区,最后是 fd。

这在硬件平台之间差异很大。

【讨论】:

  • 我搞砸了一点,发现 FD 编号为“*(int)($esp+4)”,字符串长度为“(int)*(int)( $esp + 12)" 最后字符串数据为 "*(int)($esp + 8)"。因此,对于 STDOUT,您可以执行以下操作:break write if 1 == *(int)($esp+4) commands print (int)*(int)($esp + 12) x/s *(int)($esp + 8) end 但是当我尝试在一个 huge 应用程序上实际使用它时,结果证明这个方法不是万无一失的,因为它不处理重定向等,所以如果应用程序使用 dup2() on标准输出,你可能会错过一些打印到标准输出的东西。
  • 这里有一个更精细的尝试:
     break write commands quiet if !isatty(*(int)($esp + 4)) c end echo \ntty write(), size: x/ d (int)($esp + 12) echo tty write(), data: x/s *(int)($esp + 8) end 
  • 很好。对于阅读本文的任何人,请记住,如果您的输出被发送到 STDERR,那么应该是 ´(gdb) b write if 2==$rdi´
【解决方案2】:

使用 gdb 7.0,您可以在系统调用 write() 上设置条件断点:

(gdb) catch syscall write
Catchpoint 1 (syscall 'write' [4])
(gdb) condition 1 $ebx==1

$ebx 包含第一个系统调用参数 - 这里是 FD 编号

【讨论】:

  • 注意:printf 是缓冲的,因此您可能只看到第一个 printfwrite 在第二个 printf 调用连接起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多