📄 ptrace.c
字号:
char nat = 0; int i; if (!access_ok(VERIFY_WRITE, ppr, sizeof(struct pt_all_user_regs))) return -EIO; pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) { return -EIO; } if (((unsigned long) ppr & 0x7) != 0) { dprintk("ptrace:unaligned register address %p\n", ppr); return -EIO; } if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0 || access_uarea(child, PT_AR_EC, &ec, 0) < 0 || access_uarea(child, PT_AR_LC, &lc, 0) < 0 || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0 || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0 || access_uarea(child, PT_CFM, &cfm, 0) || access_uarea(child, PT_NAT_BITS, &nat_bits, 0)) return -EIO; /* control regs */ retval |= __put_user(pt->cr_iip, &ppr->cr_iip); retval |= __put_user(psr, &ppr->cr_ipsr); /* app regs */ retval |= __put_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); retval |= __put_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); retval |= __put_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); retval |= __put_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]); retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]); retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]); retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]); retval |= __put_user(cfm, &ppr->cfm); /* gr1-gr3 */ retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long)); retval |= __copy_to_user(&ppr->gr[2], &pt->r2, sizeof(long) *2); /* gr4-gr7 */ for (i = 4; i < 8; i++) { if (unw_access_gr(&info, i, &val, &nat, 0) < 0) return -EIO; retval |= __put_user(val, &ppr->gr[i]); } /* gr8-gr11 */ retval |= __copy_to_user(&ppr->gr[8], &pt->r8, sizeof(long) * 4); /* gr12-gr15 */ retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 2); retval |= __copy_to_user(&ppr->gr[14], &pt->r14, sizeof(long)); retval |= __copy_to_user(&ppr->gr[15], &pt->r15, sizeof(long)); /* gr16-gr31 */ retval |= __copy_to_user(&ppr->gr[16], &pt->r16, sizeof(long) * 16); /* b0 */ retval |= __put_user(pt->b0, &ppr->br[0]); /* b1-b5 */ for (i = 1; i < 6; i++) { if (unw_access_br(&info, i, &val, 0) < 0) return -EIO; __put_user(val, &ppr->br[i]); } /* b6-b7 */ retval |= __put_user(pt->b6, &ppr->br[6]); retval |= __put_user(pt->b7, &ppr->br[7]); /* fr2-fr5 */ for (i = 2; i < 6; i++) { if (unw_get_fr(&info, i, &fpval) < 0) return -EIO; retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fr6-fr11 */ retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 6); /* fp scratch regs(12-15) */ retval |= __copy_to_user(&ppr->fr[12], &sw->f12, sizeof(struct ia64_fpreg) * 4); /* fr16-fr31 */ for (i = 16; i < 32; i++) { if (unw_get_fr(&info, i, &fpval) < 0) return -EIO; retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } /* fph */ ia64_flush_fph(child); retval |= __copy_to_user(&ppr->fr[32], &child->thread.fph, sizeof(ppr->fr[32]) * 96); /* preds */ retval |= __put_user(pt->pr, &ppr->pr); /* nat bits */ retval |= __put_user(nat_bits, &ppr->nat); ret = retval ? -EIO : 0; return ret;}static longptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr){ unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; struct unw_frame_info info; struct switch_stack *sw; struct ia64_fpreg fpval; struct pt_regs *pt; long ret, retval = 0; int i; memset(&fpval, 0, sizeof(fpval)); if (!access_ok(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs))) return -EIO; pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); unw_init_from_blocked_task(&info, child); if (unw_unwind_to_user(&info) < 0) { return -EIO; } if (((unsigned long) ppr & 0x7) != 0) { dprintk("ptrace:unaligned register address %p\n", ppr); return -EIO; } /* control regs */ retval |= __get_user(pt->cr_iip, &ppr->cr_iip); retval |= __get_user(psr, &ppr->cr_ipsr); /* app regs */ retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]); retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]); retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]); retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]); retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]); retval |= __get_user(cfm, &ppr->cfm); /* gr1-gr3 */ retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long)); retval |= __copy_from_user(&pt->r2, &ppr->gr[2], sizeof(long) * 2); /* gr4-gr7 */ for (i = 4; i < 8; i++) { retval |= __get_user(val, &ppr->gr[i]); /* NaT bit will be set via PT_NAT_BITS: */ if (unw_set_gr(&info, i, val, 0) < 0) return -EIO; } /* gr8-gr11 */ retval |= __copy_from_user(&pt->r8, &ppr->gr[8], sizeof(long) * 4); /* gr12-gr15 */ retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 2); retval |= __copy_from_user(&pt->r14, &ppr->gr[14], sizeof(long)); retval |= __copy_from_user(&pt->r15, &ppr->gr[15], sizeof(long)); /* gr16-gr31 */ retval |= __copy_from_user(&pt->r16, &ppr->gr[16], sizeof(long) * 16); /* b0 */ retval |= __get_user(pt->b0, &ppr->br[0]); /* b1-b5 */ for (i = 1; i < 6; i++) { retval |= __get_user(val, &ppr->br[i]); unw_set_br(&info, i, val); } /* b6-b7 */ retval |= __get_user(pt->b6, &ppr->br[6]); retval |= __get_user(pt->b7, &ppr->br[7]); /* fr2-fr5 */ for (i = 2; i < 6; i++) { retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); if (unw_set_fr(&info, i, fpval) < 0) return -EIO; } /* fr6-fr11 */ retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 6); /* fp scratch regs(12-15) */ retval |= __copy_from_user(&sw->f12, &ppr->fr[12], sizeof(ppr->fr[12]) * 4); /* fr16-fr31 */ for (i = 16; i < 32; i++) { retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); if (unw_set_fr(&info, i, fpval) < 0) return -EIO; } /* fph */ ia64_sync_fph(child); retval |= __copy_from_user(&child->thread.fph, &ppr->fr[32], sizeof(ppr->fr[32]) * 96); /* preds */ retval |= __get_user(pt->pr, &ppr->pr); /* nat bits */ retval |= __get_user(nat_bits, &ppr->nat); retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); retval |= access_uarea(child, PT_AR_RSC, &rsc, 1); retval |= access_uarea(child, PT_AR_EC, &ec, 1); retval |= access_uarea(child, PT_AR_LC, &lc, 1); retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); retval |= access_uarea(child, PT_AR_BSP, &bsp, 1); retval |= access_uarea(child, PT_CFM, &cfm, 1); retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1); ret = retval ? -EIO : 0; return ret;}/* * Called by kernel/ptrace.c when detaching.. * * Make sure the single step bit is not set. */voidptrace_disable (struct task_struct *child){ struct ia64_psr *child_psr = ia64_psr(ia64_task_regs(child)); /* make sure the single step/taken-branch trap bits are not set: */ child_psr->ss = 0; child_psr->tb = 0;}asmlinkage longsys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data){ struct pt_regs *pt; unsigned long urbs_end, peek_or_poke; struct task_struct *child; struct switch_stack *sw; long ret; lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; ret = security_ptrace(current->parent, current); if (ret) goto out; current->ptrace |= PT_PTRACED; ret = 0; goto out; } peek_or_poke = (request == PTRACE_PEEKTEXT || request == PTRACE_PEEKDATA || request == PTRACE_POKETEXT || request == PTRACE_POKEDATA); ret = -ESRCH; read_lock(&tasklist_lock); { child = find_task_by_pid(pid); if (child) { if (peek_or_poke) child = find_thread_for_addr(child, addr); get_task_struct(child); } } read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out_tsk; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ urbs_end = ia64_get_user_rbs_end(child, pt, NULL); ret = ia64_peek(child, sw, urbs_end, addr, &data); if (ret == 0) { ret = data; /* ensure "ret" is not mistaken as an error code: */ force_successful_syscall_return(); } goto out_tsk; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ urbs_end = ia64_get_user_rbs_end(child, pt, NULL); ret = ia64_poke(child, sw, urbs_end, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ if (access_uarea(child, addr, &data, 0) < 0) { ret = -EIO; goto out_tsk; } ret = data; /* ensure "ret" is not mistaken as an error code */ force_successful_syscall_return(); goto out_tsk; case PTRACE_POKEUSR: /* write the word at addr in the USER area */ if (access_uarea(child, addr, &data, 1) < 0) { ret = -EIO; goto out_tsk; } ret = 0; goto out_tsk; case PTRACE_OLD_GETSIGINFO: /* for backwards-compatibility */ ret = ptrace_request(child, PTRACE_GETSIGINFO, addr, data); goto out_tsk; case PTRACE_OLD_SETSIGINFO: /* for backwards-compatibility */ ret = ptrace_request(child, PTRACE_SETSIGINFO, addr, data); goto out_tsk; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if (!valid_signal(data)) goto out_tsk; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* * Make sure the single step/taken-branch trap bits * are not set: */ ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; wake_up_process(child); ret = 0; goto out_tsk; case PTRACE_KILL: /* * Make the child exit. Best I can do is send it a * sigkill. Perhaps it should be put in the status * that it wants to exit. */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */ goto out_tsk; child->exit_code = SIGKILL; ptrace_disable(child); wake_up_process(child); ret = 0; goto out_tsk; case PTRACE_SINGLESTEP: /* let child execute for one instruction */ case PTRACE_SINGLEBLOCK: ret = -EIO; if (!valid_signal(data)) goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); if (request == PTRACE_SINGLESTEP) { ia64_psr(pt)->ss = 1; } else { ia64_psr(pt)->tb = 1; } child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); ret = 0; goto out_tsk; case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); goto out_tsk; case PTRACE_GETREGS: ret = ptrace_getregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; case PTRACE_SETREGS: ret = ptrace_setregs(child, (struct pt_all_user_regs __user *) data); goto out_tsk; default: ret = ptrace_request(child, request, addr, data); goto out_tsk; } out_tsk: put_task_struct(child); out: unlock_kernel(); return ret;}voidsyscall_trace (void){ if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) return; /* * The 0x80 provides a way for the tracing parent to * distinguish between a syscall stop and SIGTRAP delivery. */ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); /* * This isn't the same as continuing with a signal, but it * will do for normal use. strace only continues with a * signal if the stopping signal is not SIGTRAP. -brl */ if (current->exit_code) { send_sig(current->exit_code, current, 1); current->exit_code = 0; }}/* "asmlinkage" so the input arguments are preserved... */asmlinkage voidsyscall_trace_enter (long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, struct pt_regs regs){ if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) syscall_trace(); if (unlikely(current->audit_context)) { long syscall; int arch; if (IS_IA32_PROCESS(®s)) { syscall = regs.r1; arch = AUDIT_ARCH_I386; } else { syscall = regs.r15; arch = AUDIT_ARCH_IA64; } audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3); }}/* "asmlinkage" so the input arguments are preserved... */asmlinkage voidsyscall_trace_leave (long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, struct pt_regs regs){ if (unlikely(current->audit_context)) audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8); if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) syscall_trace();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -