特定のプログラムのメモリセグメントをファイルにダンプしたいと思います。私のプログラムはミリ秒単位で動作するので、次のようにします。名前付きパイプ実行を停止し、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
ので、コマンドに2つのオプションを追加しました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
}