ptrace
プログラムによって生成されたプログラムがどのシステムコールを呼び出すかを確認するために使用したいと思います。以前の質問への回答で説明されていたので、このチュートリアルから始めました。使用しているプラットフォーム(SLES 11 64ビット)にコードを適合させてコードを変更し、生成されたプロセスが行うすべてのシステムコールを出力する次のテストコードをまとめました。
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
run();
}
return 0;
}
これは非常にうまく機能します。プログラムによって行われたシステムコールのIDを出力します(実際には、それぞれを2回出力します。1回は開始時、もう1回は終了時ですが、今は問題ではありません)。ただし、私のプログラムはシステムコールのチェック以外のことを行う必要があるため、チェックを別のスレッドに移動することにしました(CよりもC ++の方が快適なので、C ++の方法で行いましたが、それは重要だとは思わないでください)。もちろん、この最初のプログラムでは、スレッドを開始してから参加するだけです。
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
#include <boost/thread.hpp>
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
boost::thread t(run);
t.join();
}
return 0;
}
今回はエラーメッセージが表示されます。
Child process id = 24682.
Got event from 24682.
ptrace: No such process
どうしてこれなの?答えを探してみましたが、こんなものは見つかりませんでした。子プロセスによって開始されたスレッドをトレースしないことがわかりましたptrace
が、それは後で処理する必要がある別のことです。別のセラドから子プロセスをチェックすることさえ可能ですか?
もう1つの奇妙なことは、実際のアプリケーションでは基本的に同じことを実行し(ただし、クラス、ミューテックスなど、はるかに複雑なコンテキストから)、異なる種類のエラーが発生することです。ptrace
エラーで戻る代わりにwait
、子プロセスのシステムコールに対しても戻りません(そして子プロセスは停止しません)。一方、wait
子プロセスが終了すると、期待どおりに機能します。