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

问题描述 投票:0回答:2

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

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

  1. 运行 > 文件名

  2. tty 文件名

问题是我无法找到一种方法将劣质的标准输出恢复到正常状态。

没有“tty default”或“default tty”

谢谢,

伊泰

linux debugging gdb stdout
2个回答
9
投票

我找不到方法将劣质的标准输出恢复到正常

您可以这样做:

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à:“重要的一行”被打印到终端。


2
投票

详细阐述采用俄罗斯的解决方案,我编写了一个独立的 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
获取。

© www.soinside.com 2019 - 2024. All rights reserved.