Linux では、ps
を使用 procps(-ng)
から :
ps -fwwp 2755
4.2 より前の Linux バージョンでは、まだ制限されています (カーネル (/proc/2755/cmdline
) から 4k) まで、プロセスに指示するか、デバッガを使用する以外に、それ以上の値を取得することはできません。
$ sh -c 'sleep 1000' $(seq 4000) &
[1] 31149
$ gdb -p $! /bin/sh
[...]
Attaching to program: /bin/dash, process 31149
[...]
(gdb) bt
#0 0x00007f40d11f40aa in wait4 () at ../sysdeps/unix/syscall-template.S:81
[...]
#7 0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
#8 0x00000000004024a5 in ?? ()
#9 0x00007fff5b9f5a78 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb) frame 7
#7 0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
(gdb) x/4003s *ubp_av
0x7fff5b9ff83e: "sh"
0x7fff5b9ff841: "-c"
0x7fff5b9ff844: "sleep 1000"
0x7fff5b9ff84f: "1"
0x7fff5b9ff851: "2"
[...]
0x7fff5ba04212: "3999"
0x7fff5ba04217: "4000"
4 番目の引数を最大 5000 文字で出力するには:
(gdb) set print elements 5000
(gdb) p ubp_av[3]
邪魔にならないものが必要な場合は、 /proc/2755/mem
から情報を取得してみてください (kernel.yama.ptrace_scope
が 0 に設定されていない場合、そのためにはスーパーユーザー権限が必要になります)。以下は私にとってはうまくいきます (すべての引数と環境変数を出力します) が、私が考える保証はあまりありません (エラーと予期しない入力処理は、読者への演習として残されています):
$ perl -e '$p=shift;open MAPS, "/proc/$p/maps";
($m)=grep /\[stack\]/, <MAPS>;
($a,$b)=map hex, $m =~ /[\da-f]+/g;
open MEM, "/proc/$p/mem" or die "open mem: $!";
seek MEM,$a,0; read MEM, $c,$b-$a;
print((split /\0{2,}/,$c)[-1])' "$!" | tr \\0 \\n | head
sh
-c
sleep 1000
1
2
3
4
5
6
7
("$!"
を置き換えます プロセス ID と一緒に)。上記は、Linux が argv[]
が指す文字列を置くという事実を利用しています。 、 envp[]
プロセスのスタックの一番下にある実行されたファイル名。
上記は、2 つ以上の連続した NUL バイトの 2 つのセットの間にある一番下の文字列のスタックを調べます。引数またはenv文字列のいずれかが空の場合、それらのargvまたはenvpの真ん中に2つのNULバイトのシーケンスがあるため、機能しません。また、argv 文字列がどこで停止し、envp 文字列がどこで開始するかはわかりません。
そのための回避策は、argv[]
の実際のコンテンツを逆に見て、そのヒューリスティックを改良することです。 (ポインター)。以下は、少なくとも ELF 実行可能ファイルの i386 および amd64 アーキテクチャで動作します:
perl -le '$p=shift;open MAPS, "/proc/$p/maps";
($m)=grep /\[stack\]/, <MAPS>;
($a,$b)=map hex, $m =~ /[\da-f]+/g;
open MEM, "/proc/$p/mem" or die "open mem: $!";
seek MEM,$a,0; read MEM, $c,$b-$a;
$c =~ /.*\0\0\K[^\0].*\0[^\0]*$/s;
@a=unpack"L!*",substr$c,0,$-[0];
for ($i = $#a; $i >=0 && $a[$i] != $a+$-[0];$i--) {}
for ($i--; $i >= 0 && ($a[$i]>$a || $a[$i]==0); $i--) {}
$argc=$a[$i++];
print for unpack"(Z*)$argc",substr$c,$a[$i]-$a;' "$!"
基本的には上記と同じですが、argv[]
の最初の文字列が見つかったら (または argv[]
の少なくとも 1 つ または envp[]
空がある場合は文字列)、そのアドレスを知っているので、スタックの一番上の残りを逆方向に検索して、同じ値を持つポインターを探します。次に、それらへのポインターにならない数値、つまり argc
が見つかるまで、逆方向に検索し続けます。 .次の整数は argv[0]
です .そしてargv[0]
を知る と argc
、引数のリストを表示できます。
プロセスが argv[]
に書き込んだ場合、それは機能しません おそらくいくつかの NUL 区切り文字をオーバーライドするか、または argc
の場合 0 (argc
通常、argv[0]
を含めるには少なくとも 1 です。 ) しかし、少なくとも ELF 実行可能ファイルの一般的なケースでは機能するはずです。
4.2 以降では、/proc/<pid>/cmdline
切り捨てられなくなりましたが、ps
それ自体の最大表示幅は 128K です。
1 つまたは 2 つの -w
を追加します フラグ。出力の幅が広がります。例えばps auxww
.
Linux カーネル 4.2 以降では、/proc/<pid>/cmdline
切り捨てられなくなり、次のようにうまく動作します:
xargs -0 printf '%s\n' < /proc/2755/cmdline