开始,让我们先研究它怎样才会不工作。它不能通过阅读和分析程序的二进制信息来模拟程序的运行。它其实能做,而那应该能起作用(Valgrind 内存调试器就是这样工作的),但是这样的话会很慢。Valgrind会让程序慢1000倍,但是GDB不会。它的工作机制与Qemu虚拟机一样。
首先,关于Linux的进程机制需要了解一件事:父进程可以获得子进程的附加信息,也能够ptrace它们。并且你可以猜到的是,调试器是被调试的进程的父进程(或者它会变成父进程,在Linux中进程可以将一个进程变为自己子进程:-))
Linux Ptrace API
Linux Ptrace API 允许一个(调试器)进程来获取低等级的其他(被调试的)进程的信息。特别的,这个调试器可以:
读写被调试进程的内存 :PTRACE_PEEKTEXT、PTRACE_PEEKUSER、PTRACE_POKE……
读写被调试进程的CPU寄存器 PTRACE_GETREGSET、PTRACE_SETREGS
因系统活动而被提醒:PTRACE_O_TRACEEXEC, PTRACE_O_TRACECLONE, PTRACE_O_EXITKILL, PTRACE_SYSCALL(你可以通过这些标识区分exec syscall、clone、exit以及其他系统调用)
控制它的执行:PTRACE_SINGLESTEP、PTRACE_KILL、PTRACE_INTERRUPT、PTRACE_CONT (注意,CPU在这里是单步执行)
修改它的信号处理:PTRACE_GETSIGINFO、PTRACE_SETSIGINFO
Ptrace是如何实现的?
Ptrace的实现不在本文讨论的范围内,所以我不想进一步讨论,只是简单地解释它是如何工作的(我不是内核专家,如果我说错了请一定指出来,并原谅我过分简化:-))
Ptrace 是Linux内核的一部分,所以它能够获取进程所有内核级信息:
读写数据?Linux有copy_to/from_user。
获取CPU寄存器?用copy_regset_to/from_user很轻松(这里没有什么复杂的,因为CPU寄存器在进程未被调度时保存在Linux的struct task_struct *调度结构中)。
修改信号处理?更新域last_siginfo
单步执行?在处理器出发执行前,设置进程task结构的right flag(ARM、x86)
Ptrace是在很多计划的操作中被Hooked(搜索 ptrace_event函数),所以它可以在被询问时(PTRACE_O_TRACEEXEC选项和与它相关的),向调试器发出一个SIGTRAP信号。
更多资讯:武汉软件开发培训学校