我想将某个程序的内存段转储到文件中。因为我的程序的工作时间是毫秒,所以我使用命名管道停止其执行并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
}