【问题标题】:How to tell GDB to flush the stdio of the program being debugged如何告诉 GDB 刷新被调试程序的 stdio
【发布时间】:2012-01-05 06:44:40
【问题描述】:

stdio 通常是缓冲的。当我打断点并且断点之前有一个 printf 时,打印的字符串可能还在缓冲区中,我看不到它。

我知道我可以通过在程序中添加一些刷新代码来刷新 stdio。 如果不这样做,有没有办法告诉 GDB 在 GDB 停止后刷新正在调试的程序的 stdio?这种方式在调试程序时更加友好。

【问题讨论】:

  • GDB好像没有这个机制。只有解决方法。

标签: debugging gdb buffer stdio


【解决方案1】:

如果您调用fflush(NULL),许多最近的 UNIX stdio 实现将刷新所有缓冲区:

(gdb) call fflush(0)

如果您没有安装libc 调试符号,您可能需要告诉 GDB fflush 的类型:

(gdb) call ((void(*)(int))fflush)(0)

但通常你不应该这样做:如果你调用printf(而不是fprintf),它会转到stdout,它会进入你的终端,这通常是行缓冲的。所以,只要你的printf 打印了一个新行,缓冲区就会在printf 返回后被刷新。

【讨论】:

  • fflush( NULL ) 的行为被明确定义为刷新所有输出流。任何这样做的实现都不符合标准。
  • 它在我的 WinXP + MinGW + GDB 中运行良好,谢谢。
  • 请确保您不要从可能在某些FILE 对象上持有锁的stdio 函数内部执行此操作,以避免死锁或损坏。 (即,您不能在程序运行时中断的任意点安全地执行此操作。)
  • 我得到:'fflush@plt' 的返回类型未知;将调用转换为其声明的返回类型
  • @Rebroad 所以它告诉你做什么?像call ((void(*)(int))fflush)(0) 这样的东西。或者安装 libc6-dbg 或类似的,让 GDB 知道fflush 的类型。
【解决方案2】:

GDB 允许您直接从命令行调用 C 函数。所以你可以这样做

(gdb) call setbuf(stdout, NULL)

现在,唯一的问题是我不知道如何在运行时“获取”stdoutreal 值。

编辑这可能会有所帮助(来自the docs):

call setbuf(fdopen(1, "w"), 0)

【讨论】:

  • @Yorkwar:找到了一种可能的“hacky”方式来让 setbuf 通过重复的流对象在 stdout fd 上工作。不知道副作用。你可以试一试吗?
  • (gdb) call setbuf(stdout, 0) 有效。我的问题是在 C 中。但解决方案是 gdb 告诉程序,而不是 gdb 自己做。并且 stdio 的缓冲区一直处于禁用状态,这会影响程序的性能。但是,这是一种解决方法。
【解决方案3】:

如果你在你的程序中定义了一个函数:

void flush_all(void) {
    fflush(NULL);
}

您可以在gdb(1) 中调用此函数:

call flush_all()

一个简短的演示:

$ cat cat.c
#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("this is a partial write");
    printf("this is a partial write");
    printf("this is a partial write");
    printf("this is a partial write");
    printf("this is a partial write");

    return 0;
}

void flush_all(void) {
    fflush(NULL);
}

$ gcc -g -o cat cat.c
$ gdb
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) file cat
Reading symbols from /home/sarnold/tmp/cat...done.
(gdb) break printf
Breakpoint 1 at 0x400428
(gdb) run
Starting program: /home/sarnold/tmp/cat 

Breakpoint 1, __printf (format=0x4006bc "this is a partial write") at printf.c:30
30  printf.c: No such file or directory.
    in printf.c
(gdb) cont
Continuing.

Breakpoint 1, __printf (format=0x4006bc "this is a partial write") at printf.c:30
30  in printf.c
(gdb) cont
Continuing.

Breakpoint 1, __printf (format=0x4006bc "this is a partial write") at printf.c:30
30  in printf.c
(gdb) call flush_all()
this is a partial writethis is a partial write(gdb) ^CQuit
(gdb) quit

【讨论】:

  • 我想到了一个使用 GDB 的“命令”的解决方法:(gdb) commands 1-N &gt;call flush_all() &gt;end 其中 N 是一个很大的数字,可以覆盖我所有的断点
【解决方案4】:

您可以像(gdb) display一样使用display命令,其详细信息可以在here中找到。一旦 GDB 遇到像 "\n" 这样的行尾字符,就会显示输出。您可以使用undisplay 关闭显示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多