在 bash 脚本中使用 GDB 进行进程的内存转储 - 错误、问题

在 bash 脚本中使用 GDB 进行进程的内存转储 - 错误、问题

我想将某个程序的内存段转储到文件中。因为我的程序的工作时间是毫秒,所以我使用命名管道停止其执行并gdb同时转储其内存内容。该脚本在某些情况下有效,但在其他情况下无效:当我想将输出重定向到某些过滤程序以对其进行格式化时,以及添加--nw,选项时,会出现错误。--nh

问题:是什么导致这些错误以及为什么我无法让脚本使用添加的--nw选项--nh

我将用一个简化的例子来演示这个问题:

我的程序.c

#include <stdio.h>

int main() {
    puts("one two three");
    return 0;
}

脚本文件

function find_stack_addr {
    read stack_start stack_end <<< $(awk '
    /\[stack\]/ {split($1, stack_maps, "-")}

    END {
        stack_start = "0x" stack_maps[1]
        stack_end = "0x" stack_maps[2]

        print stack_start, stack_end
    }' $1)
}

function dump_mem {
    ./my_program y y y > named_pipe &
    pid=$!

    find_stack_addr "/proc/${pid}/maps"

    sudo gdb --batch --pid "$pid" -ex "dump memory dumps/stack_${1}.dump $stack_start $stack_end"
    echo "$pid $stack_start $stack_end"
}

mkfifo named_pipe

for i in {1..3}; do
   dump_mem "$i"
done

rm named_pipe

结果

12798 0x7ffc5a875000 0x7ffc5a896000
12806 0x7ffc5a875000 0x7ffc5a896000
12814 0x7ffc5a875000 0x7ffc5a896000

dumps/
├── stack_1.dump
├── stack_2.dump
└── stack_3.dump

我想将for循环输出重定向到column添加了标头的程序,因此我将for循环更改为:

for i in {1..3}; do
   dump_mem "$i"
done | sed '1  i\pid stack_start stack_end' | column -t

并出现错误(脚本也未完成):

/home/minimax/.gdbinit:4: Error in sourced command file:
Cannot enable the TUI when output is not a terminal
47  ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.

很明显,问题是由重定向到管道而不是stdin我的.gdbinit文件设置引起的,因此我向命令添加了两个选项gdb

  --nh               Do not read ~/.gdbinit.
  --nw               Do not use the GUI interface.

现在,gdb命令是:

sudo gdb --nw --nh --batch --pid "$pid" -ex "dump memory dumps/stack_${1}.dump $stack_start $stack_end"

然后,TUI错误消失了,但No such file or directory并没有:

47  ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.
47  ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.
47  ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.

for我尝试使用此gdb命令(添加选项)进行第一个循环--nw --nh,并且也收到错误,尽管脚本有效并且结果得到回显。

0x00007f4dab824d9e in __libc_open64 (file=0x55da21e2e9a0 "named_pipe", oflag=577) at ../sysdeps/unix/sysv/linux/open64.c:47
47  ../sysdeps/unix/sysv/linux/open64.c: No such file or directory.
13130 0x7ffcada58000 0x7ffcada79000      #<--- the script's output

答案1

我找到了一个解决方法 -GDB将 的输出重定向到/dev/stdout.逻辑如下 - 如果GDB在其输出连接到终端时工作正常,则需要为他提供此连接。在这种情况下,没有错误。

就我而言,/dev/stdout指向/dev/pts

$ ls -l /dev/stdout 
lrwxrwxrwx 1 root root 15 Oct  9 10:10 /dev/stdout -> /proc/self/fd/1

$ ls -l /proc/self/fd/1
lrwx------ 1 minimax minimax 64 Oct  9 15:00 /proc/self/fd/1 -> /dev/pts/11

固定代码

function dump_mem {
    ./my_program y y y > named_pipe &
    pid=$!

    find_stack_addr "/proc/${pid}/maps"

    sudo gdb --batch --pid "$pid" -ex "dump memory dumps/stack_${1}.dump $stack_start $stack_end" > /dev/stdout

    echo "$pid $stack_start $stack_end"
    cat named_pipe > /dev/null
}

相关内容