1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > linux ptrace 内核源码分析 linux 3.5.4 ptrace源码分析分析(系列一)

linux ptrace 内核源码分析 linux 3.5.4 ptrace源码分析分析(系列一)

时间:2023-04-28 22:53:42

相关推荐

linux ptrace 内核源码分析 linux 3.5.4 ptrace源码分析分析(系列一)

ptrace是linux系统中为了调试专门设立的一种系统调用。要想调试调试一个进程,有两种方式:

PTRACE_TRACEME和PTRACE_ATTACH。这两种方式的主要区别可以概括为:

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\n",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操作返回有三种情况:

1、子进程正常退出

int status;

wait(&status);//status保存了子进程当前的状态

WIFEXITED(status)://如果子进程确实正常退出,则为真

WEXITSTATUS(status)://打印出进程的退出码

2、子进程因为收到信号而退出

int status;

wait(&status);

WIFSIGNALED(status)://如果子进程确实正常退出,则为真

WTERMSIG(status)://打印出进程的退出码

3、子进程因为收到信号而暂停

int status;

wait(&status);

WIFSTOPPED(status)://如果子进程确实正常退出,则为真

WSTOPSIG(status)://打印出进程的退出码 显然,PTRACE_TRACEME对应的就是第三种情况。如果想要输出信号对应的描述性字符串,可以这样操作:

sprintf(stderr,"%s\n",WSTOPSIG(status));

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。