GDB:暂时重定向目标标准输出

时间:2013-12-31 16:41:37

标签: linux debugging gdb stdout

当我启动GDB时,目标进程会打印大量数据,因此我想将其重定向到NULL,直到某个时间点。

到目前为止我发现的唯一两种方法是:

  1. 运行>文件名

  2. tty filename

  3. 问题是我无法找到恢复劣质stdout恢复正常的方法。

    没有“tty默认”或“默认tty”

    谢谢,

    伊泰

2 个答案:

答案 0 :(得分:3)

  

我无法找到一种方法将下级的stdout恢复正常

以下是如何做到这一点:

Reading symbols from /tmp/./a.out...done.
(gdb) list main
1   #include <stdio.h>
2
3   int main() {
4     int i;
5
6     for (i = 0; i < 1000; ++i) {
7       printf("A line we don't care about: %d\n", i);
8     }
9     printf("An important line\n");
10    return 0;
11  }
(gdb) b 9
Breakpoint 1 at 0x400579: file t.c, line 9.
(gdb) run > /dev/null
Starting program: /tmp/./a.out > /dev/null

Breakpoint 1, main () at t.c:9
9     printf("An important line\n");
(gdb) call fflush(0)
$1 = 0

由于我们即将切换输出,我们希望确保刷新任何缓冲数据。

接下来我们致电open("/dev/tty", O_WRONLY)。您可以在O_WRONLY中通过grep ping找到/usr/include的值。

(gdb) shell grep WRONLY /usr/include/bits/*.h
/usr/include/bits/fcntl.h:#define O_WRONLY       01
(gdb) p open("/dev/tty", 1)
$2 = 3

所以我们现在有了一个新的文件描述符3,它将输出到当前终端。最后,我们将STDOUT_FILENO切换到它,就像这样:

(gdb) call dup2(3, 1)
$3 = 1
(gdb) c
Continuing.
An important line
[Inferior 1 (process 22625) exited normally]

Voilà:终端上印有“重要的一条线”。

答案 1 :(得分:0)

详细阐述了使用俄语的解决方案,我已经编写了一个独立的GDB-python脚本,可以切换到stdout和活动终端(TTY)的重定向。如果程序输出没有重定向到以(run > /dev/null)开头,则脚本无效。

要激活脚本,请使用source命令:

(gdb) b 10
Breakpoint 1 at 0x5555555547a8: file gdbtest.c, line 10.
(gdb) run > /dev/null
Starting program: /home/gdbtest > /dev/null

Breakpoint 1, main () at gdbtest.c:10
10    printf("An important line\n");
(gdb) list
5   
6     setbuf(stdout, NULL);
7     for (i = 0; i < 1000; ++i) {
8       printf("A line we don't care about: %d\n", i);
9     }
10    printf("An important line\n");
11    for (i = 0; i < 1000; ++i) {
12      printf("A line we don't care about: %d\n", i);
13    }
14    //fflush(stdout);
(gdb) source redir-stdout.py 
(gdb) redir-stdout 
Inferior PID: 20749
Redirecting stdout (fd:4) to TTY (fd:3)
(gdb) n
An important line
11    for (i = 0; i < 1000; ++i) {
(gdb) n
12      printf("A line we don't care about: %d\n", i);
(gdb) n
A line we don't care about: 0
11    for (i = 0; i < 1000; ++i) {
(gdb) redir-stdout 
Inferior PID: 20749
Redirecting TTY (fd:3) back to stdout (fd:4)
(gdb) n
12      printf("A line we don't care about: %d\n", i);
(gdb) n
11    for (i = 0; i < 1000; ++i) {
(gdb) n
12      printf("A line we don't care about: %d\n", i);
(gdb) 

这是脚本(我将其命名为redir-stdout.py):

import gdb

class RedirectStdout(gdb.Command):
    def __init__(self):
        super(RedirectStdout, self).__init__("redir-stdout", gdb.COMMAND_USER)
        self.tty = None
        self.stdout = None
        self.redir = False
        gdb.events.exited.connect(self.exit_handler)

    def invoke(self, arg, from_tty):
        print("Inferior PID: %s" % gdb.selected_inferior().pid)
        if(gdb.selected_inferior().pid == 0):
            raise gdb.GdbError ("Error: must have an active debuggee")

        out = gdb.execute("call fflush(0)", to_string=True)
        if(self.tty is None):
            # or just /dev/tty, as shown (the 1 means WRONLY)
            out = gdb.execute("p open(\"/dev/tty\", 1)", to_string=True)
            self.tty = out.split('=')[-1].strip()

        if(self.stdout is None):
            out = gdb.execute("p open(\"/proc/self/fd/1\", 1)", to_string=True)
            self.stdout = out.split('=')[-1].strip()

        if(not self.redir):
            print("Redirecting stdout (fd:{}) to TTY (fd:{})".format(self.stdout, self.tty))
            out = gdb.execute("call dup2({}, 1)".format(self.tty), to_string=True)
            ret = out.split('=')[-1].strip()
            #print("dup2 returns: " + ret)
            self.redir = True
        else:
            print("Redirecting TTY (fd:{}) back to stdout (fd:{})".format(self.tty, self.stdout))
            out = gdb.execute("call dup2({}, 1)".format(self.stdout), to_string=True)
            ret = out.split('=')[-1].strip()
            #print("dup2 returns: " + ret)
            self.redir = False

    def exit_handler(self, event):
        self.tty = None
        self.stdout = None
        self.redir = False

instance = RedirectStdout()

def exit_handler (event):
    print("Exit event received")
    instance.exit_handler(event)

注意:脚本可以从当前目录中的本地.gdbinit或主目录中轻松获取。