当前位置:网站首页>GDB调试程序的核心技术-ptrace系统调用与使用示例
GDB调试程序的核心技术-ptrace系统调用与使用示例
2022-04-22 22:22:00 【InfoQ】
一,ptrace系统调用
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
- request:指定调试的指令,指令的类型很多,如:PTRACE_TRACEME、PTRACE_PEEKUSER、PTRACE_CONT、PTRACE_GETREGS等等,下面会介绍不同指令的作用。
- pid:进程的ID(这个不用解释了)。
- addr:进程的某个地址空间,可以通过这个参数对进程的某个地址进行读或写操作。
- data:根据不同的指令,有不同的用途,下面会介绍。
二,ptrace使用示例
#include <sys/ptrace.h>#include <sys/types.h>#include <sys/wait.h>#include
<unistd.h>#include <sys/user.h>#include <stdio.h>int main(){
pid_t child;struct user_regs_struct regs;
child = fork(); // 创建一个子进程
if(child == 0) { // 子进程
ptrace(PTRACE_TRACEME, 0, NULL, NULL); // 表示当前进程进入被追踪状态
execl("/bin/ls", "ls", NULL); // 执行 `/bin/ls` 程序
}
else { // 父进程
wait(NULL); // 等待子进程发送一个 SIGCHLD 信号
ptrace(PTRACE_GETREGS, child, NULL, ®s); // 获取子进程的各个寄存器的值
printf("Register: rdi[%ld], rsi[%ld], rdx[%ld], rax[%ld], orig_rax[%ld]\n",
regs.rdi, regs.rsi, regs.rdx,regs.rax, regs.orig_rax); // 打印寄存器的值
ptrace(PTRACE_CONT, child, NULL, NULL); // 继续运行子进程
sleep(1);
}
return 0;
}Register: rdi[0], rsi[0], rdx[0], rax[0], orig_rax[59]ptrace ptrace.c- 主进程调用 fork() 系统调用创建一个子进程。
- 的进程调用 ptrace(PTRACE_TRACEME,...) 把自己设置为被追踪状态,并且调用 execl() 执行 /bin/ls 程序。
- 被设置为追踪(TRACE)状态的子进程执行 execl() 的程序后,会向父进程发送 SIGCHLD 信号,并且暂停自身的执行。
- 父进程通过调用 wait() 接收子进程发送过来的信号,并且开始追踪子进程。
- 父进程通过调用 ptrace(PTRACE_GETREGS, child, ...) 来获取到子进程各个寄存器的值,并且打印寄存器的值。
- 父进程通过调用 ptrace(PTRACE_CONT, child, ...) 让子进程继续执行下去。
三,ptrace实现原理
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
struct user *dummy = NULL;
int i, ret;
...
read_lock(&tasklist_lock);
child = find_task_by_pid(pid); // 获取 pid 对应的进程 task_struct 对象
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child);
goto out_tsk;
}
...
switch (request) {
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
...
case PTRACE_PEEKUSR:
...
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
...
case PTRACE_POKEUSR:
...
case PTRACE_SYSCALL:
case PTRACE_CONT:
...
case PTRACE_KILL:
...
case PTRACE_SINGLESTEP:
...
case PTRACE_DETACH:
...
}
out_tsk:
free_task_struct(child);
out:
unlock_kernel();
return ret;
}#define PTRACE_TRACEME 0
#define PTRACE_PEEKTEXT 1
#define PTRACE_PEEKDATA 2
#define PTRACE_PEEKUSR 3
#define PTRACE_POKETEXT 4
#define PTRACE_POKEDATA 5
#define PTRACE_POKEUSR 6
#define PTRACE_CONT 7
#define PTRACE_KILL 8
#define PTRACE_SINGLESTEP 9
#define PTRACE_ATTACH 0x10
#define PTRACE_DETACH 0x11
#define PTRACE_SYSCALL 24
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
#define PTRACE_GETFPXREGS 18
#define PTRACE_SETFPXREGS 19
#define PTRACE_SETOPTIONS 21- 被调试的进程调用 ptrace(PTRACE_TRACEME, ...) 来使自己进入被追踪模式。
- 调试进程(如GDB)调用 ptrace(PTRACE_ATTACH, pid, ...) 来使指定的进程进入追踪模式。
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
...
if (request == PTRACE_TRACEME) {
if (current->ptrace & PT_PTRACED)
goto out;
current->ptrace |= PT_PTRACED; // 标志 PTRACE 状态
ret = 0;
goto out;
}
...
}static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
...
if (current->ptrace & PT_PTRACED)
send_sig(SIGTRAP, current, 0);
...
}int do_signal(struct pt_regs *regs, sigset_t *oldset)
{
for (;;) {
unsigned long signr;
spin_lock_irq(¤t->sigmask_lock);
signr = dequeue_signal(¤t->blocked, &info);
spin_unlock_irq(¤t->sigmask_lock);
// 如果进程被标记为 PTRACE 状态
if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
/* 让调试器运行 */
current->exit_code = signr;
current->state = TASK_STOPPED; // 让自己进入停止运行状态
notify_parent(current, SIGCHLD); // 发送 SIGCHLD 信号给父进程
schedule(); // 让出CPU的执行权限
...
}
}
}- 如果当前进程被标记为 PTRACE 状态,那么就使自己进入停止运行的状态。
- 发送 SIGCHLD 信号给父进程。
- 让出 CPU 的执行权限,使 CPU 执行其他进程。

asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
...
switch (request) {
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA: {
unsigned long tmp;
int copied;
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
ret = -EIO;
if (copied != sizeof(tmp))
break;
ret = put_user(tmp, (unsigned long *)data);
break;
}
...
}struct mm_struct {
...
pgd_t *pgd; /* 页目录指针 */
...
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
...
switch (request) {
case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp;
...
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
ret = 0;
break;
}
...
}
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
- 获取进程的 eflags 寄存器的值,并且设置 Trap Flag 标志。
- 把新的值设置到进程的 eflags 寄存器中。

四,小结
版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢
https://xie.infoq.cn/article/1467e9e7b6e04a124fceea49d
边栏推荐
- MTP管理课养成计划-第2天学习笔记
- 0-1背包问题讲解 & leetcode相关题目总结
- 行人重识别综述之Person Re-identification:Past, Present and Future
- GBase 8s V8.8 SQL 指南:教程-6.2.2(3)
- Pangolin installation error: Make: * * * there are no rules to create the target "pypangolin_pip_install". stop it.
- L1-066 猫是液体 (5 分)
- 外部中断---------stm32f407zet6
- fastadmin 动态赋值下拉框
- Knowledge map opening notes
- cluster_acc计算
猜你喜欢

0-1背包问题讲解 & leetcode相关题目总结

哪怕 30 年寒窗苦讀,也有可能離財富很遠……

External interrupt ------------ stm32f407zet6

How does alicloud server hide real IP

阿里云服务器如何隐藏真实ip

Advanced multithreading (6) -- locking mechanism

10万开发者涌入“酷应用”,钉钉押注场景化

GBase 8s V8. 8 SQL Guide: Tutorial - 6.2.1 (2)

LLVM 学习(一) -初识LLVM

How to use opcua protocol on appinventor?
随机推荐
Difference between ov code signature and ev code signature certificate
MySQL表的增删改查(进阶)
[in simple terms and reinforcement learning] 2 Markov decision process
LLVM 学习(一) -初识LLVM
LeetCode 199. 二叉树的右视图
How does alicloud server hide real IP
时间戳有什么作用,如何申请?
Shadowcaster shadowmask map of 0 basic unityurp rendering pipeline is indistinct (code direction)
GBase 8s V8. 8 SQL Guide: Tutorial - 6.2.1 (4)
Quickly calculate the number of divisors -- from basic to advanced
41.0:GemBox.Spreadsheet|.Document|.Pdf|.Presentation
0-1 knapsack problem explanation & leetcode related topic summary
[easy to understand and intensive learning] 1 Introduction
Person re identification: past, present and future
等价多米诺骨牌对的数量-c语言实现
How to judge how many levels of insurance the enterprise should do? What is the significance of waiting insurance?
Advanced multithreading (8) -- thread pool
阿里云服务器如何隐藏真实ip
GBase 8s V8. 8 SQL Guide: Tutorial - 6.1.2 (3)
GBase 8s V8.8 SQL 指南:教程-6.2.1(4)