PTRACE
Section: Linux Programmer's Manual (2)
Updated: 2006-03-24
Index
JM Home Page
roff page
名前
ptrace - プロセスのトレース
書式
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,
void *addr, void *data);
説明
ptrace()
システムコールは、親プロセスが、別のプロセスの実行の監視/制御を
行ったり、コアイメージ (core image) やレジスタの調査/変更を
行ったりする手段を提供する。
ptrace()
は、主にブレークポイントによるデバッグやシステムコールのトレースを
実装するのに用いられる。
トレースを開始するには、まず親プロセスで
fork(2)
を呼び出す。生成された子プロセスで
PTRACE_TRACEME
を行い、続いて (典型的には)
exec(3)
を行なう。
別の方法としては、
親プロセスが既存のプロセスに対して
PTRACE_ATTACH
を使用し、トレースを開始する。
トレースの実行中、子プロセスはシグナルが配送されるたびに、
たとえそのシグナルが無視すべきものであっても停止する
(SIGKILL
は例外で、通常どおりの効果をもたらす)。
親プロセスには次の
wait(2)
で通知され、停止している間に子プロセスを調べたり修正したりすることができる。
そして親プロセスは子プロセスの実行を再開させるが、配送された
シグナルを無視することもできる (あるいは代わりに別のシグナルを
配送することもできる) 。
親プロセスがトレースを終了する際には、
PTRACE_KILL
を使用して子プロセスを終了させることもできるし、
PTRACE_DETACH
を用いて通常のトレースなしのモードにして、
実行を継続させることもできる。
request の値がこのシステムコールの動作を決定する:
- PTRACE_TRACEME
-
このプロセスが親プロセスによってトレースされることを表す。
このプロセスに
(SIGKILL
以外の) シグナルが配送されると、
プロセスは停止し、親プロセスに
wait(2)
を通じて通知される。
また、これ以降はこのプロセスが
execve(2)
を呼び出す度に
SIGTRAP
が送信されるようになる。
これによって、親プロセスは
新しいプログラムが実行を開始する前に制御することができる。
親プロセスが自プロセスをトレースするつもりがない場合には、
おそらくこのプロセスは本要求を行うべきではないだろう。
(pid, addr, data は無視される。)
上記の要求は子プロセスだけが行なうものである。
残りは親プロセスだけが行なうものである。
以下の要求では、pid で操作の対象となる
子プロセスを指定する。
PTRACE_KILL
を除き、要求を行なうためには
子プロセスは停止していなければならない。
- PTRACE_PEEKTEXT, PTRACE_PEEKDATA
-
子プロセスのメモリの
addr
の位置から 1 ワードを読み出す。読み出したワードは
ptrace()
の返り値として返される。 Linux ではテキスト (text) とデータ (data) で
同じアドレス空間を使用するため、この 2 つの要求は現在のところ
同じものである。 (引き数 data は無視される。)
- PTRACE_PEEKUSR
-
子プロセスの USER 領域のオフセット
addr
の位置から 1 ワードを読み込む。USER 領域にはそのプロセスの
レジスタ (registers) などの情報が保持されている。
(<linux/user.h> と <sys/user.h>
を参照)。読み込んだワードは
ptrace()
コールの結果として返される。
たいていはオフセットはワード境界になければならないが、
アーキテクチャによってはその必要はない。
(data は無視される。 )
- PTRACE_POKETEXT, PTRACE_POKEDATA
-
ワード
data
を子プロセスのメモリの
addr
の位置へコピーする。上と同様に、現在のところ二つの
要求は同じものである。
- PTRACE_POKEUSR
-
ワード
data
を子プロセスの USER 領域のオフセット
addr
の位置にコピーする。
上と同様に、通常、オフセットはワード境界になければならない。
カーネルの完全性 (integrity) を維持するため、
変更内容によっては USER 領域の変更は禁止されている。
- PTRACE_GETREGS, PTRACE_GETFPREGS
-
それぞれ、子プロセスの汎用レジスタ、浮動小数点レジスタを親プロセスの
data の位置にコピーする。この data の書式に関しては
<linux/user.h> を参照すること。(addr は無視される。)
- PTRACE_GETSIGINFO (Linux 2.3.99-pre6 以降)
-
停止の原因となったシグナルに関する情報を取得する。
siginfo_t 構造体
(sigaction(2)
参照) を子プロセスから親プロセスの data の位置にコピーする。
(addr は無視される。)
- PTRACE_SETREGS, PTRACE_SETFPREGS
-
それぞれ、子プロセスの汎用レジスタ、浮動小数点レジスタに
親プロセスの date の位置からコピーする。
PTRACE_POKEUSER
と同様に、汎用レジスタによっては
変更が禁止されている場合がある。 (addr は無視される。)
- PTRACE_SETSIGINFO (Linux 2.3.99-pre6 以降)
-
シグナル情報を設定する。
siginfo_t 構造体を親プロセスのデータ data の位置から
子プロセスにコピーする。
この処理を行うことができるのは、子プロセスに通常は配送されるはずで
トレーサに捕捉されたシグナルについてだけである。
これらの通常のシグナルと
ptrace()
自身が発生するシグナルを見分けるのは難しいかもしれない。
(addr は無視される。)
- PTRACE_SETOPTIONS (Linux 2.4.6 以降; バグの章にある警告も参照)
-
親プロセスの data に基づいて ptrace のオプションを設定する
(addr は無視される)。
data はオプションのビットマスクとして解釈され、
オプションには以下のフラグを指定できる:
-
- PTRACE_O_TRACESYSGOOD (Linux 2.4.6 以降)
-
システムコールのトラップが配送されたときに、シグナル番号のビット 7
を設定する (すなわち、(SIGTRAP | 0x80) を配送する)。
これにより、トレーサが通常のトラップとシステムコールによるトラップを
区別しやすくなる。
(PTRACE_O_TRACESYSGOOD
はどのアーキテクチャでも動作しない可能性がある。)
- PTRACE_O_TRACEFORK (Linux 2.5.46 以降)
-
次の
fork(2)
呼び出し時に SIGTRAP | PTRACE_EVENT_FORK << 8 で
子プロセスの動作を停止させ、
新たに fork されたプロセスのトレースを自動的に開始し、
SIGSTOP
でそのプロセスの実行を開始する。
新しいプロセスの PID は
PTRACE_GETEVENTMSG
で取得できる。
- PTRACE_O_TRACEVFORK (Linux 2.5.46 以降)
-
次の
vfork(2)
呼び出し時に SIGTRAP | PTRACE_EVENT_VFORK << 8 で
子プロセスの動作を停止させ、
新たに vfork されたプロセスのトレースを自動的に開始し、
SIGSTOP
でそのプロセスの実行を開始する。
新しいプロセスの PID は
PTRACE_GETEVENTMSG
で取得できる。
- PTRACE_O_TRACECLONE (Linux 2.5.46 以降)
-
次の
clone(2)
呼び出し時に SIGTRAP | PTRACE_EVENT_CLONE << 8 で
子プロセスの動作を停止させ、
新たに clone で作成されたプロセスのトレースを自動的に開始し、
SIGSTOP
でプロセスの実行を開始する。
新しいプロセスの PID は
PTRACE_GETEVENTMSG
で取得できる。
このオプションで全ての
clone(2)
コールを捕まえられるわけではない。
子プロセスが
CLONE_VFORK
フラグ付きで
clone(2)
を呼び出した場合、
PTRACE_O_TRACEVFORK
が設定されていれば代わりに
PTRACE_EVENT_VFORK
が配送される。
また、子プロセスが終了シグナルを
SIGCHLD
に設定して
clone(2)
を呼び出した場合は、
PTRACE_O_TRACEFORK
が設定されていれば
PTRACE_EVENT_FORK
が配送される。
- PTRACE_O_TRACEEXEC (Linux 2.5.46 以降)
-
次の
execve(2)
呼び出し時に
SIGTRAP | PTRACE_EVENT_EXEC << 8
で子プロセスの動作を停止させる。
- PTRACE_O_TRACEVFORKDONE (Linux 2.5.60 以降)
-
次の
vfork(2)
呼び出し時に
SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8
で子プロセスの動作を停止させる。
- PTRACE_O_TRACEEXIT (Linux 2.5.60 以降)
-
終了 (exit) 時に SIGTRAP | PTRACE_EVENT_EXIT << 8
で子プロセスの動作を停止させる。子プロセスの終了ステータスは
PTRACE_GETEVENTMSG
で取得できる。
この停止はレジスタがまだ参照可能であるプロセス終了処理の初期に行われ、
トレーサはどこで終了が発生したかを知ることができる。
通常の終了通知 (exit notification) はプロセスの終了処理が完了した後に
行われる。コンテキストを参照することはできるにも関わらず、
トレーサはこの時点から終了を止めることはできない。
- PTRACE_GETEVENTMSG (Linux 2.5.46 以降)
-
発生したばかりの ptrace イベントに関するメッセージを
(unsigned long
型で) 取得する。
取得したメッセージは親プロセスの data の位置に格納される。
得られる内容は、
PTRACE_EVENT_EXIT
の場合は子プロセスの終了ステータスであり、
PTRACE_EVENT_FORK,
PTRACE_EVENT_VFORK,
PTRACE_EVENT_CLONE
の場合は新しいプロセスの PID である。
Linux 2.6.18 以降では、新しいプロセスの PID は
PTRACE_EVENT_VFORK_DONE
で入手できる。
(addr は無視される。)
- PTRACE_CONT
-
停止した子プロセスの実行を再開させる。
data がゼロでなく、
SIGSTOP
でもなければ、
子プロセスに配送されるシグナルと解釈される。
ゼロや
SIGSTOP
の場合はシグナルは配送されない。
これを使うと、例えば、親プロセスは
子プロセスに送られたシグナルを実際に配送するかどうかを
制御することができる。(addr は無視される。)
- PTRACE_SYSCALL, PTRACE_SINGLESTEP
-
PTRACE_CONT
と同様に停止した子プロセスを再開する。ただし、
PTRACE_SYSCALL
の場合は子プロセスが
次にシステムコールに入るかシステムコールから抜けるかする時に、
PTRACE_SINGLESTEP
の場合は 1 命令 (instruction) 実行した後に停止させる
(通常どおり、子プロセスはシグナルを受け取った場合にも停止する)。
親プロセスから見ると、子プロセスは
SIGTRAP
を受信して停止したように見える。そのため、例えば
PTRACE_SYSCALL
を使うと、1回目の停止で引き数を調べて
PTRACE_SYSCALL
を実行し、 2回目の停止でシステムコールの返り値を調べる、
というようなことができる。(addr は無視される。)
- PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP (Linux 2.6.14 以降)
-
PTRACE_SYSEMU
は、実行を再開し、次のシステムコールに入る時に停止させる。
システムコールは実行されない。
PTRACE_SYSEMU_SINGLESTEP
も同様だが、システムコールでない場合には
1 命令 (singlestep) だけ実行した時点でも停止させる。
このコールは User Mode Linux のように子プロセスのシステムコールを全て
エミュレートしようとするプログラムで使用される。
(addr と data は無視される。
全てのアーキテクチャでサポートされているわけではない。)
- PTRACE_KILL
-
子プロセスに
SIGKILL
を送り終了させる。(addr と data は無視される。)
- PTRACE_ATTACH
-
pid
で指定されたプロセスに接続 (attach) し、それを現在のプロセスの
子プロセスとしてトレースできるようにする。子プロセスは
PTRACE_TRACEME
したかのように振舞う。現在のプロセスはそのほとんどの目的において、
その子プロセスの実際の親になる (例えば、子プロセスのイベントの
通知を受けとったり、
ps(1)
で親として表示されたりする)。しかし、子プロセスで
getppid(2)
を実行した場合には元の親プロセスの PID が返される。
子プロセスには
SIGSTOP
が送られるが、この呼び出しが完了するまでに
必ずしも停止するとは限らない。子プロセスの停止を待つには
wait(2)
を使用すること。(addr と data は無視される。)
- PTRACE_DETACH
-
PTRACE_CONT
と同様に停止した子プロセスを再開する。ただし
まずそのプロセスからの分離 (detach) を行い、
PTRACE_ATTACH
での親の切り換えによる効果と
PTRACE_TRACEME
の効果を取り消す。意図したものではないだろうが、
Linux では、トレースされている子プロセスはどのような方法でトレースを
開始されたとしても、この方法で分離 (detach) することができる。
(addr は無視される。)
返り値
成功すると、
PTRACE_PEEK*
の場合は要求したデータを返し、
それ以外の場合は 0 を返す。
エラーの場合は -1 を返し、
errno
が適切に設定される。
PTRACE_PEEK*
が成功して返す値も -1 になることがあるため、
そのような要求の場合には、呼び出し元は
errno
を調べ、エラーか発生したのかどうかを判断しなければならない。
エラー
- EBUSY
-
(i386 のみ) デバッグレジスタの確保または解放でエラーが発生した。
- EFAULT
-
親プロセスまたは子プロセスのメモリの不正な領域に読み書きしようとした。
おそらくその領域がマッピングされていないか、
その領域へのアクセスが許されていないかである。
不運なことに、Linux ではこのようなエラーの場合、多かれ少なかれ
恣意的に
EIO
を返したり
EFAULT
を返したりすることがある。
- EINVAL
-
不正なオプションを設定しようとした。
- EIO
-
request が不正である。
または、親プロセスまたは子プロセスのメモリの
不正な領域に読み書きしようとした。
または、ワード境界違反があった。
または、実行再開の要求で不正なシグナルを指定した。
- EPERM
-
指定したプロセスをトレースすることができない。これは親プロセスが
必要な権限 (必要なケーパビリティは
CAP_SYS_PTRACE)
を持っていないことが原因の場合がある。
分かりやすい理由を挙げるなら、
ルートでないプロセスはシグナルを送れないプロセスはトレースできないし、
set-user-ID/set-group-ID プログラムを実行しているプロセスはトレースできない。
または、プロセスはすでにトレース中である、
または
init(8)
プロセス (PID が 1) である。
- ESRCH
-
指定したプロセスが存在しない。
または、指定したプロセスは呼び出したプロセスが
現在トレース中の子プロセスではない。
または、指定したプロセスが停止していない (停止していることが必要な要求の場合)。
準拠
SVr4, 4.3BSD
注意
ptrace()
の引き数は上のようなプロトタイプに基づいて解釈されるが、
glibc では、現在のところ
ptrace()
は request 引き数だけが固定の可変長引き数関数として
宣言されている。
これは必要なければ残りの引き数は省略可能であることを意味するが、
それは
gcc(1)
の明文化されていない動作を利用していることになる。
init(8)
すなわち PID が 1 のプロセスはトレースすることができない。
メモリや USER 領域の内容や配置は OS ごと、アーキテクチャごとに
非常に依存する。
「ワード (word) 」の大きさは OS によって決まる。
(例えば、32 ビットの Linux では 32 ビットである、など。)
トレースすることによってトレースされるプロセスの動作に些細な違いが
起こることがある。例えば、プロセスが
PTRACE_ATTACH
によって接続された場合には、そのプロセスが停止した時でも本来の親は
wait(2)
を使って通知を受けることができず、新しい親が効率よく
この通知を真似る方法もない。
親プロセスが
PTRACE_EVENT_*
がセットされたイベントを受信した場合、
子プロセスは通常通りのシグナル配送が行われる状態にない。
つまり、親プロセスが、
シグナルにより
ptrace(PTRACE_CONT)
を行ったり、
ptrace(PTRACE_KILL)
を行ったりできないということである。
こららのメッセージの受信後は、子プロセスを終了 (kill) するのに、
シグナル
SIGKILL
を指定して
kill(2)
を行う方法を代わりに使用できる。
このマニュアルは現在の Linux における
ptrace()
コールの動作について記述している。他の Unix では
その動作は著しく異なる。
いかなる場合も
ptrace()
を使うと OS やアーキテクチャに非常に依存したものになる。
SunOS のマニュアル・ページには
ptrace()
は「独特で不可解」と記述されており、まさしくそうである。
Solaris 2 では proc ベースの
デバッグのインターフェースとして
ptrace()
の上位互換関数が実装され、より強力で一貫性のあるものとなっている。
バグ
カーネル 2.6 のヘッダがインストールされたホストでは、
PTRACE_SETOPTIONS
はカーネル 2.4 のヘッダとは異なる値で宣言される。
このため、カーネル 2.6 のヘッダでコンパイルされたアプリケーションは
カーネル 2.4 では正しく動作しない。
この問題は、
PTRACE_SETOPTIONS
が定義されていた際は、
PTRACE_SETOPTIONS
を
PTRACE_OLDSETOPTIONS
に定義し直すことで対処できる。
関連項目
gdb(1),
strace(1),
execve(2),
fork(2),
signal(2),
wait(2),
exec(3),
capabilities(7)
Index
- 名前
-
- 書式
-
- 説明
-
- 返り値
-
- エラー
-
- 準拠
-
- 注意
-
- バグ
-
- 関連項目
-
This document was created by
man2html,
using the manual pages.
Time: 04:31:56 GMT, November 19, 2007