📄 ptrace.c
字号:
/* ptrace.c: Sparc process tracing support. * * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, * and David Mosberger. * * Added Linux support -miguel (wierd, eh?, the orignal code was meant * to emulate SunOS). */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#define MAGIC_CONSTANT 0x80000000/* Returning from ptrace is a bit tricky because the syscall return * low level code assumes any value returned which is negative and * is a valid errno will mean setting the condition codes to indicate * an error return. This doesn't work, so we have this hook. */static inline void pt_error_return(struct pt_regs *regs, unsigned long error){ regs->u_regs[UREG_I0] = error; regs->psr |= PSR_C; regs->pc = regs->npc; regs->npc += 4;}static inline void pt_succ_return(struct pt_regs *regs, unsigned long value){ regs->u_regs[UREG_I0] = value; regs->psr &= ~PSR_C; regs->pc = regs->npc; regs->npc += 4;}static voidpt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr){ if(put_user(value, addr)) return pt_error_return(regs, EFAULT); regs->u_regs[UREG_I0] = 0; regs->psr &= ~PSR_C; regs->pc = regs->npc; regs->npc += 4;}static voidpt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr){ if (current->personality == PER_SUNOS) pt_succ_return (regs, val); else pt_succ_return_linux (regs, val, addr);}/* Fuck me gently with a chainsaw... */static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, struct task_struct *tsk, long *addr){ struct pt_regs *cregs = tsk->thread.kregs; struct thread_struct *t = &tsk->thread; int v; if(offset >= 1024) offset -= 1024; /* whee... */ if(offset & ((sizeof(unsigned long) - 1))) { pt_error_return(regs, EIO); return; } if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); return; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); return; } switch(offset) { case 0: v = t->ksp; break; case 4: v = t->kpc; break; case 8: v = t->kpsr; break; case 12: v = t->uwinmask; break; case 832: v = t->w_saved; break; case 896: v = cregs->u_regs[UREG_I0]; break; case 900: v = cregs->u_regs[UREG_I1]; break; case 904: v = cregs->u_regs[UREG_I2]; break; case 908: v = cregs->u_regs[UREG_I3]; break; case 912: v = cregs->u_regs[UREG_I4]; break; case 916: v = cregs->u_regs[UREG_I5]; break; case 920: v = cregs->u_regs[UREG_I6]; break; case 924: if(tsk->thread.flags & MAGIC_CONSTANT) v = cregs->u_regs[UREG_G1]; else v = 0; break; case 940: v = cregs->u_regs[UREG_I0]; break; case 944: v = cregs->u_regs[UREG_I1]; break; case 948: /* Isn't binary compatibility _fun_??? */ if(cregs->psr & PSR_C) v = cregs->u_regs[UREG_I0] << 24; else v = 0; break; /* Rest of them are completely unsupported. */ default: printk("%s [%d]: Wants to read user offset %ld\n", current->comm, current->pid, offset); pt_error_return(regs, EIO); return; } if (current->personality == PER_SUNOS) pt_succ_return (regs, v); else pt_succ_return_linux (regs, v, addr); return;}static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, struct task_struct *tsk){ struct pt_regs *cregs = tsk->thread.kregs; struct thread_struct *t = &tsk->thread; unsigned long value = regs->u_regs[UREG_I3]; if(offset >= 1024) offset -= 1024; /* whee... */ if(offset & ((sizeof(unsigned long) - 1))) goto failure; if(offset >= 16 && offset < 784) { offset -= 16; offset >>= 2; *(((unsigned long *)(&t->reg_window[0]))+offset) = value; goto success; } if(offset >= 784 && offset < 832) { offset -= 784; offset >>= 2; *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; goto success; } switch(offset) { case 896: cregs->u_regs[UREG_I0] = value; break; case 900: cregs->u_regs[UREG_I1] = value; break; case 904: cregs->u_regs[UREG_I2] = value; break; case 908: cregs->u_regs[UREG_I3] = value; break; case 912: cregs->u_regs[UREG_I4] = value; break; case 916: cregs->u_regs[UREG_I5] = value; break; case 920: cregs->u_regs[UREG_I6] = value; break; case 924: cregs->u_regs[UREG_I7] = value; break; case 940: cregs->u_regs[UREG_I0] = value; break; case 944: cregs->u_regs[UREG_I1] = value; break; /* Rest of them are completely unsupported or "no-touch". */ default: printk("%s [%d]: Wants to write user offset %ld\n", current->comm, current->pid, offset); goto failure; }success: pt_succ_return(regs, 0); return;failure: pt_error_return(regs, EIO); return;}/* #define ALLOW_INIT_TRACING *//* #define DEBUG_PTRACE */#ifdef DEBUG_PTRACEchar *pt_rq [] = {"TRACEME","PEEKTEXT","PEEKDATA","PEEKUSR","POKETEXT","POKEDATA","POKEUSR","CONT","KILL","SINGLESTEP","SUNATTACH","SUNDETACH","GETREGS","SETREGS","GETFPREGS","SETFPREGS","READDATA","WRITEDATA","READTEXT","WRITETEXT","GETFPAREGS","SETFPAREGS",""};#endifasmlinkage void do_ptrace(struct pt_regs *regs){ unsigned long request = regs->u_regs[UREG_I0]; unsigned long pid = regs->u_regs[UREG_I1]; unsigned long addr = regs->u_regs[UREG_I2]; unsigned long data = regs->u_regs[UREG_I3]; unsigned long addr2 = regs->u_regs[UREG_I4]; struct task_struct *child; lock_kernel();#ifdef DEBUG_PTRACE { char *s; if ((request > 0) && (request < 21)) s = pt_rq [request]; else s = "unknown"; if (request == PTRACE_POKEDATA && data == 0x91d02001){ printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n", pid, addr, addr2); } else printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n", s, (int) request, (int) pid, addr, data, addr2); }#endif if(request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); goto out; } /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; pt_succ_return(regs, 0); goto out; }#ifndef ALLOW_INIT_TRACING if(pid == 1) { /* Can't dork with init. */ pt_error_return(regs, EPERM); goto out; }#endif if(!(child = find_task_by_pid(pid))) { pt_error_return(regs, ESRCH); goto out; } if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) */ pt_error_return(regs, EPERM); goto out; } if((!child->dumpable || (current->uid != child->euid) || (current->uid != child->uid) || (current->uid != child->suid) || (current->gid != child->egid) || (current->gid != child->sgid) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -