📄 ptrace.c
字号:
#ifdef CONFIG_S390_SUPPORT skip=8;#endif } else { copymax=PT_PSWMASK+8; } if(writingtouser) mask=PSW_MASK_DEBUGCHANGE; } else if(useraddr<(PT_PSWADDR+8)) { copymax=PT_PSWADDR+8; mask=PSW_ADDR_DEBUGCHANGE;#ifdef CONFIG_S390_SUPPORT if(parent_31bit) skip=4;#endif } else {#ifdef CONFIG_S390_SUPPORT if(parent_31bit && useraddr <= PT_GPR15+4) { copymax=useraddr+4; if(useraddr<PT_GPR15+4) skip=4; } else#endif copymax=PT_FPC; } } else if(useraddr<(PT_FPR15+sizeof(freg_t))) { copymax=(PT_FPR15+sizeof(freg_t)); realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]); } else if(useraddr<sizeof(struct user_regs_struct)) {#ifdef CONFIG_S390_SUPPORT if( parent_31bit && useraddr <= PT_IEEE_IP+4) { switch(useraddr) { case PT_CR_11+4: case U64OFFSETOF(per_info.ending_addr)+4: case U64OFFSETOF(per_info.lowcore.words.address)+4: copymax=useraddr+4; break; case PT_SINGLE_STEP: case U64OFFSETOF(per_info.lowcore.words.perc_atmid): /* We copy 2 bytes in excess for the atmid member this also gets around */ /* alignment for this member in 32 bit */ skip=8; copymax=useraddr+4; break; default: copymax=useraddr+4; skip=4; } } else#endif { copymax=sizeof(struct user_regs_struct); } realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]); } else { copymax=sizeof(struct user); realuseraddr=(addr_t)NULL; } copylen=copymax-useraddr; copylen=(copylen>len ? len:copylen); if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask)) return (-EIO); copyaddr+=copylen; len-=copylen; useraddr+=copylen#if CONFIG_S390_SUPPORT +skip#endif ; } FixPerRegisters(task); return(0);}/* * Called by kernel/ptrace.c when detaching.. * * Make sure single step bits etc are not set. */void ptrace_disable(struct task_struct *child){ /* make sure the single step bit is not set. */ clear_single_step(child);}typedef struct{__u32 len;__u32 kernel_addr;__u32 process_addr;} ptrace_area_emu31;asmlinkage int sys_ptrace(long request, long pid, long addr, long data){ struct task_struct *child; int ret = -EPERM; int copied;#ifdef CONFIG_S390_SUPPORT int parent_31bit; int sizeof_parent_long; u8 *dataptr;#else#define sizeof_parent_long 8#define dataptr (u8 *)&data#endif lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; goto out; } ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out_tsk; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; // printk("child=%lX child->flags=%lX",child,child->flags); /* I added child!=current line so we can get the */ /* ieee_instruction_pointer from the user structure DJB */ if(child!=current) { if (!(child->ptrace & PT_PTRACED)) goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) goto out_tsk; } if (child->p_pptr != current) goto out_tsk; }#ifdef CONFIG_S390_SUPPORT parent_31bit=(current->thread.flags & S390_FLAG_31BIT); sizeof_parent_long=(parent_31bit ? 4:8); dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);#endif switch (request) { /* If I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { u8 tmp[8]; copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0); ret = -EIO; if (copied != sizeof_parent_long) break; ret = copy_to_user((void *)data,tmp,sizeof_parent_long); ret = ret ? -EFAULT : 0; break; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: ret=copy_user(child,addr,data,sizeof_parent_long,1,0); break; /* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long) break; ret = -EIO; break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1); break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if ((unsigned long) data >= _NSIG) break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); ret = 0; break;/* * 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. */ case PTRACE_KILL: ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; clear_single_step(child); wake_up_process(child); /* make sure the single step bit is not set. */ break; case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; if ((unsigned long) data >= _NSIG) break; child->ptrace &= ~PT_TRACESYS; child->exit_code = data; set_single_step(child); /* give it a chance to run. */ wake_up_process(child); ret = 0; break; case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break; case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: if(parent_31bit) { ptrace_area_emu31 parea; if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0) ret=copy_user(child,parea.kernel_addr,parea.process_addr, parea.len,1,(request==PTRACE_POKEUSR_AREA)); else ret = -EFAULT; } else { ptrace_area parea; if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0) ret=copy_user(child,parea.kernel_addr,parea.process_addr, parea.len,1,(request==PTRACE_POKEUSR_AREA)); else ret = -EFAULT; } break; default: ret = -EIO; break; } out_tsk: free_task_struct(child); out: unlock_kernel(); return ret;}asmlinkage void syscall_trace(void){ lock_kernel(); if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) goto out; current->exit_code = SIGTRAP; set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); /* * 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; } out: unlock_kernel();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -