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ので、コマンドに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.

forgdb最初のループでこのコマンド(オプションを追加)を試してみましたが、スクリプトが--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
}

おすすめ記事