ptrace
プロセスのシステムコールを追跡するために使用しています。プロセスをフォークした後、プロセスのPTRACE_TRACEME
トレースを開始するために使用します。コードは次のようになります。
while (true) {
int status;
int gotPid;
gotPid = waitpid(pid, &status, 0);
if (WIFEXITED(status) || WIFSIGNALED(status)) {
break;
}
if (WIFSTOPPED(status)) {
handleTrace();
}
}
次にhandleTrace
、次のような関数があります。
long syscall;
syscall = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
// do something with the syscall
// continue program
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
これで問題ありませんが、プログラムが分岐する (または新しいスレッドを作成する) 場合は、トレース対象のプロセスが作成する子プロセス (およびプロセスによって作成されるスレッド) もトレースしたいと考えています。PTRACE_O_TRACEFORK
、 、PTRACE_O_TRACEVFORK
およびを使用して実行できることは知っていますがPTRACE_O_TRACECLONE
、man
ドキュメントから、それがどのように正確に実行されるかを理解するのは非常に困難です。これについていくつかの例が必要です。
編集:
ここで同様の質問を見つけました:マルチスレッドアプリケーションをptraceする方法は? 以下のコードで試してみました。このコードは、開始されたプロセスのシステム コールを追跡し、フォークされたプロセスも追跡することになっています。fork()
親プロセスでa の後に実行されます (子は aPTRACE_TRACEME
および an を呼び出しますexec()
)。
編集2:
コードにさらにいくつかの変更を加え、さらに進歩しました。
long orig_eax;
int status;
int numPrograms = 1;
while(1) {
int pid;
CHECK_ERROR_VALUE(pid = waitpid(-1, &status, __WALL));
std::cout << pid << ": Got event." << std::endl;
if(WIFEXITED(status) || WIFSIGNALED(status)) {
std::cout << pid << ": Program exited." << std::endl;
if (--numPrograms == 0) {
break;
}
continue;
}
if (status >> 16 == PTRACE_EVENT_FORK || status >> 16 == PTRACE_EVENT_VFORK ||
status >> 16 == PTRACE_EVENT_CLONE) {
int newpid;
CHECK_ERROR_VALUE(ptrace(PTRACE_GETEVENTMSG, child, NULL, (long) &newpid));
std::cout << pid << ": Attached to offspring " << newpid << std::endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS,
newpid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE));
CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL, newpid, NULL, NULL));
++numPrograms;
} else {
CHECK_ERROR_VALUE(ptrace(PTRACE_SETOPTIONS,
pid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE));
CHECK_ERROR_VALUE(orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL));
std::cout << pid << ": Syscall called: " <<
SyscallMap::instance().get().right.at(orig_eax) <<
std::endl;
CHECK_ERROR_VALUE(ptrace(PTRACE_SYSCALL,
pid, NULL, NULL));
}
}
CHECK_ERROR_VALUE
結果コードをチェックし、その中に記述された例外をスローする単なるマクロですerrno
。
どうやら、フォーク/クローンのイベントを取得すると、新しいプロセスはまだ存在せず、ptrace しようとすると「プロセスが存在しません」というエラー メッセージが表示されます。新しいプロセスを ptrace しようとする前にスリープ状態にすると、エラー メッセージは表示されません。プログラムが fork/clone のポイントに到達すると、新しいプロセスのトレースが開始されますが、親プロセスの syscall の戻りポイントには到達しませんclone()
。つまり、子は正常に終了しますが、親はその分岐点。