linux 3.5.4 ptraceソース分析(シリーズ一)

3476 ワード

ptraceはlinuxシステムでデバッグのために特別に設定されたシステム呼び出しです.プロセスをデバッグするには、次の2つの方法があります.
PTRACE_TRACEMEとPTRACE_ATTACH.この2つの方法の主な違いは、次のように要約できます.
PTRACE_TRACEMEは、サブプロセスがTRACEによって自発的に申請される.PTRACE_ATTACHは親プロセス自身がattachをサブプロセスに必要とし,サブプロセスが受動的なtraceに相当する.
PTRACE_TRACEMEプログラムが設定するフレームワークは、次のようになります.
if(pid==0)//child
{
    ptrace(PTACE_TRACEME,0,NULL,NULL);
    exec(...);
}
else//parent
{
   wait(&status);
   if(WIFSTOPPED(status))
      fprintf(stderr,"%s
",WSTOPSIG(status);// 。 }
簡単なコードのように見えますが、カーネルは多くの作業をしています.ここで詳細な分析を行います.
プログラムがptraceシステム呼び出しを実行すると、PTRACE_に転送されます.TRACEME関数の場合、カーネルは次のコードセグメントを実行します.
static int ptrace_traceme(void)
{
	int ret = -EPERM;

	write_lock_irq(&tasklist_lock);
	/* Are we already being traced? */
	if (!current->ptrace) {
		ret = security_ptrace_traceme(current->parent);
		/*
		 * Check PF_EXITING to ensure ->real_parent has not passed
		 * exit_ptrace(). Otherwise we don't report the error but
		 * pretend ->real_parent untraces us right after return.
		 */
		if (!ret && !(current->real_parent->flags & PF_EXITING)) {
			current->ptrace = PT_PTRACED;
			__ptrace_link(current, current->real_parent);
		}
	}
	write_unlock_irq(&tasklist_lock);

	return ret;
}
上記のソースコードから、PTRACE_TRACEMEは、サブプロセスを停止させるのではなく、一連の判断を行った後(親プロセスがサブプロセスを追跡できるかどうかの正当性チェック)、サブプロセスを親プロセスのptraceチェーンテーブルにリンクします.
本当にサブプロセスが停止したのはexecシステム呼び出しで、このシステム呼び出しが成功した後、カーネルはプロセスがptraceによって追跡されたかどうかを判断し、追跡された場合、カーネルはプロセスにSIGTRAP信号を送信します.この信号は、現在のプロセスを停止させます.具体的なコードは以下の通りです.
static inline void ptrace_event(int event, unsigned long message)
{
	if (unlikely(ptrace_event_enabled(current, event))) {
		current->ptrace_message = message;
		ptrace_notify((event << 8) | SIGTRAP);
	} else if (event == PTRACE_EVENT_EXEC) {
		/* legacy EXEC report via SIGTRAP */
		if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)
			send_sig(SIGTRAP, current, 0);
	}
}
SIGTRAP信号はdebug専用に設計されており、カーネルがブレークポイントを踏むと(ブレークポイントはint 3であり、対応するコールバック関数はdo_trap)、この信号が送信されます.
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
{
	siginfo_t info;
	memset(&info, 0, sizeof(info));
	info.si_signo = SIGTRAP;
	info.si_code = TRAP_TRACE;
	info.si_addr = (void *)address;
	force_sig_info(SIGTRAP, &info, current);

	regs->pc += 4;
}

ここから,プロセスがtraceされた後,サブプロセスに対する多くの操作(特に親プロセスに興味のある操作)が変化し,親プロセスにこれらのイベントを感知させるためにexecが一例であることが分かる.
親プロセスのwait操作が呼び出されます.wait操作は親プロセスがサブプロセスの終了状況を検出するために使用されることを知っています.wait操作は3つの状況を返します.
1、サブプロセスが正常に終了
int status;
wait(&status);//statusはサブプロセスの現在の状態を保存します
WIFEXITED(status)://サブプロセスが正常に終了した場合は真
WEXITSTATUS://プロセスの終了コードを印刷
2、サブプロセスは信号を受け取って終了する
int status;
wait(&status);
WIFSIGNALED(status)://サブプロセスが正常に終了した場合は真
WTERMSIG(status)://プロセスの終了コードを印刷
3、サブプロセスは信号を受け取ったために一時停止する
int status;
wait(&status);
WIFSTOPED://サブプロセスが正常に終了した場合は真
WSTOPSIG(status)://印刷プロセスの終了コード明らかに、PTRACE_TRACEMEに対応するのが3つ目のケースです.信号に対応する記述文字列を出力するには、次のようにします.
sprintf(stderr,"%s",WSTOPSIG(status));