📄 ptrace.c
字号:
/* ptrace.c *//* By Ross Biro 1/23/92 *//* * Pentium III FXSR, SSE support * Gareth Hughes <gareth@valinux.com>, May 2000 */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/security.h>#include <linux/audit.h>#include <linux/seccomp.h>#include <linux/signal.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/i387.h>#include <asm/debugreg.h>#include <asm/ldt.h>#include <asm/desc.h>/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. *//* determines which flags the user has access to. *//* 1 = access 0 = no access *//******************LKRR start 0372180****************/#define FLAG_MASK 0x00044dd5/*** EFLAG访问权限设定 ***//* set's the trap flag. */#define TRAP_FLAG 0x100/*** 设置陷阱标志 ***//******************LKRR end 0372180****************//* * Offset of eflags on child stack.. */#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))/* 用于清除TF标志 */static inline struct pt_regs *get_child_regs(struct task_struct *task){ void *stack_top = (void *)task->thread.esp0; return stack_top - sizeof(struct pt_regs);}/* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the TSS. * this routine assumes that all the privileged stacks are in our * data space. */ /******************LKRR start 0372180****************/static inline int get_stack_long(struct task_struct *task, int offset){ unsigned char *stack; stack = (unsigned char *)task->thread.esp0;/* 获得ESP0寄存器值 */ stack += offset;/* 加偏移量 */ return (*((int *)stack));}/* * this routine will put a word on the processes privileged stack. * the offset is how far from the base addr as stored in the TSS. * this routine assumes that all the privileged stacks are in our * data space. */static inline int put_stack_long(struct task_struct *task, int offset, unsigned long data){ unsigned char * stack; stack = (unsigned char *) task->thread.esp0;/* 获得ESP0寄存器值 */ stack += offset;/* 加偏移量 */ *(unsigned long *) stack = data; return 0;}/***读写所有i386用户寄存器使用ptrace的PTRACE_GETFPREGS和PTRACE_PUTFPREGS读写所有i387浮点寄存器。***/static int putreg(struct task_struct *child, unsigned long regno, unsigned long value){ switch (regno >> 2) {//参数regno,表示寄存器的序号 case FS: if (value && (value & 3) != 3) return -EIO; child->thread.fs = value; return 0; case GS: if (value && (value & 3) != 3) return -EIO; child->thread.gs = value; return 0; case DS: case ES: if (value && (value & 3) != 3) return -EIO; value &= 0xffff; break; case SS: case CS: if ((value & 3) != 3) return -EIO; value &= 0xffff; break; case EFL: value &= FLAG_MASK;//函数get_stack_long()和put_stack_long()为对子进程核心堆栈的操作 value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; break; } if (regno > GS*4) regno -= 2*4; put_stack_long(child, regno - sizeof(struct pt_regs), value); return 0;}/***作用和putreg相仿,读写所有i386用户寄存器使用ptrace的PTRACE_GETFPREGS和PTRACE_PUTFPREGS读写所有i387浮点寄存器。***/static unsigned long getreg(struct task_struct *child, unsigned long regno){ unsigned long retval = ~0UL; switch (regno >> 2) { case FS: retval = child->thread.fs; break; case GS: retval = child->thread.gs; break; case DS: case ES: case SS: case CS: retval = 0xffff; /* fall through */ default: if (regno > GS*4) regno -= 2*4; regno = regno - sizeof(struct pt_regs);//函数get_stack_long()和put_stack_long()为对子进程核心堆栈的操作 retval &= get_stack_long(child, regno); } return retval;}/******************LKRR end 0372180****************/#define LDT_SEGMENT 4static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_regs *regs){ unsigned long addr, seg; addr = regs->eip; seg = regs->xcs & 0xffff; if (regs->eflags & VM_MASK) { addr = (addr & 0xffff) + (seg << 4); return addr; } /* * We'll assume that the code segments in the GDT * are all zero-based. That is largely true: the * TLS segments are used for data, and the PNPBIOS * and APM bios ones we just ignore here. */ if (seg & LDT_SEGMENT) { u32 *desc; unsigned long base; down(&child->mm->context.sem); desc = child->mm->context.ldt + (seg & ~7); base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000); /* 16-bit code segment? */ if (!((desc[1] >> 22) & 1)) addr &= 0xffff; addr += base; up(&child->mm->context.sem); } return addr;}static inline int is_at_popf(struct task_struct *child, struct pt_regs *regs){ int i, copied; unsigned char opcode[16]; unsigned long addr = convert_eip_to_linear(child, regs);//调用转换函数 copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); for (i = 0; i < copied; i++) { switch (opcode[i]) { /* popf */ case 0x9d: return 1; /* opcode and address size prefixes */ case 0x66: case 0x67: continue; /* irrelevant prefixes (segment overrides and repeats) */ case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x64: case 0x65: case 0xf0: case 0xf2: case 0xf3: continue; /* * pushf: NOTE! We should probably not let * the user see the TF bit being set. But * it's more pain than it's worth to avoid * it, and a debugger could emulate this * all in user space if it _really_ cares. */ case 0x9c: default: return 0; } } return 0;}/******************LKRR start 0372180****************//***在处理器状态字(PSW)中设置Trace bit位,让子进程单步执行***/static void set_singlestep(struct task_struct *child){ struct pt_regs *regs = get_child_regs(child);//调用函数获取子函数标志 /* * Always set TIF_SINGLESTEP - this guarantees that * we single-step system calls etc.. This will also * cause us to set TF when returning to user mode. */ set_tsk_thread_flag(child, TIF_SINGLESTEP);//设置标志函数 /* * If TF was already set, don't do anything else */ if (regs->eflags & TRAP_FLAG) return; /* Set TF on the kernel stack.. */ regs->eflags |= TRAP_FLAG; /* * ..but if TF is changed by the instruction we will trace, * don't mark it as being "us" that set it, so that we * won't clear it by hand later. */ if (is_at_popf(child, regs))//进行判断,如果在栈顶需要进行pop操作,则返回 return; child->ptrace |= PT_DTRACE;}static void clear_singlestep(struct task_struct *child)//用于清楚状态字的设置{ /* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* But touch TF only if it was set by us.. */ if (child->ptrace & PT_DTRACE) { struct pt_regs *regs = get_child_regs(child); regs->eflags &= ~TRAP_FLAG; child->ptrace &= ~PT_DTRACE; }}/******************LKRR end 0372180****************//* * Called by kernel/ptrace.c when detaching.. * * Make sure the single step bit is not set. */void ptrace_disable(struct task_struct *child){ clear_singlestep(child);}/* * Perform get_thread_area on behalf of the traced child. */static int/******************LKRR start 0372180****************//***此函数负责对线程空间的传递操作***/ptrace_get_thread_area(struct task_struct *child, int idx, struct user_desc __user *user_desc){ struct user_desc info; struct desc_struct *desc;/* * Get the current Thread-Local Storage area: */#define GET_BASE(desc) ( \ (((desc)->a >> 16) & 0x0000ffff) | \ (((desc)->b << 16) & 0x00ff0000) | \ ( (desc)->b & 0xff000000) )#define GET_LIMIT(desc) ( \ ((desc)->a & 0x0ffff) | \ ((desc)->b & 0xf0000) )#define GET_32BIT(desc) (((desc)->b >> 22) & 1)#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3)#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1)#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1)#define GET_PRESENT(desc) (((desc)->b >> 15) & 1)#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; info.entry_number = idx; info.base_addr = GET_BASE(desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); info.read_exec_only = !GET_WRITABLE(desc); info.limit_in_pages = GET_LIMIT_PAGES(desc); info.seg_not_present = !GET_PRESENT(desc); info.useable = GET_USEABLE(desc); if (copy_to_user(user_desc, &info, sizeof(info))) return -EFAULT; return 0;}/* * Perform set_thread_area on behalf of the traced child. */static intptrace_set_thread_area(struct task_struct *child, int idx, struct user_desc __user *user_desc){ struct user_desc info; struct desc_struct *desc; if (copy_from_user(&info, user_desc, sizeof(info))) return -EFAULT; if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; if (LDT_empty(&info)) { desc->a = 0; desc->b = 0; } else { desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } return 0;}/***************LKRR end 0372180*************//***************LKRR end 0372180*************//***接下来,就进入ptrace最为关键的函数部分,其核心函数sys_ptrace函叔: sys_ptrace函数,完成ptrace系统调用的代码。 为完成sys_ptrace功能所需调用的一些辅助 函数 寄存器读写函数和内存读写函数。 信号处理函数中,对被调试进程的处
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -