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));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值