static void fetch_regs (void) { int ret, regno, tid; struct pt_regs regs; /* Get the thread id for the ptrace call. */ tid = GET_THREAD_ID (inferior_ptid); ret = ptrace (PTRACE_GETREGS, tid, 0, ®s); if (ret < 0) { warning ("Unable to fetch general registers."); return; } for (regno = A1_REGNUM; regno < PC_REGNUM; regno++) supply_register (regno, (char *) ®s.uregs[regno]); if (arm_apcs_32) supply_register (PS_REGNUM, (char *) ®s.uregs[CPSR_REGNUM]); else supply_register (PS_REGNUM, (char *) ®s.uregs[PC_REGNUM]); regs.uregs[PC_REGNUM] = ADDR_BITS_REMOVE (regs.uregs[PC_REGNUM]); supply_register (PC_REGNUM, (char *) ®s.uregs[PC_REGNUM]); }
static void store_regs (void) { struct reg inferior_registers; int ret; int regno; for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) regcache_collect (regno, (char *) &inferior_registers.r[regno]); regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); if (arm_apcs_32) { regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr); } else { unsigned pc_val; unsigned psr_val; regcache_collect (ARM_PC_REGNUM, (char *) &pc_val); regcache_collect (ARM_PS_REGNUM, (char *) &psr_val); pc_val = ADDR_BITS_REMOVE (pc_val); psr_val ^= ADDR_BITS_REMOVE (psr_val); inferior_registers.r_pc = pc_val | psr_val; } #ifndef CROSS_DEBUGGER ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) &inferior_registers, 0); if (ret < 0) warning ("unable to store general registers"); #endif }
void supply_gregset (gdb_gregset_t *gregsetp) { int regno, reg_pc; for (regno = A1_REGNUM; regno < PC_REGNUM; regno++) supply_register (regno, (char *) &(*gregsetp)[regno]); if (arm_apcs_32) supply_register (PS_REGNUM, (char *) &(*gregsetp)[CPSR_REGNUM]); else supply_register (PS_REGNUM, (char *) &(*gregsetp)[PC_REGNUM]); reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[PC_REGNUM]); supply_register (PC_REGNUM, (char *) ®_pc); }
static void fetch_register (int regno) { struct reg inferior_registers; #ifndef CROSS_DEBUGGER int ret; ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) &inferior_registers, 0); if (ret < 0) { warning ("unable to fetch general register"); return; } #endif switch (regno) { case ARM_SP_REGNUM: supply_register (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); break; case ARM_LR_REGNUM: supply_register (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); break; case ARM_PC_REGNUM: /* This is ok: we're running native... */ inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc); supply_register (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); break; case ARM_PS_REGNUM: if (arm_apcs_32) supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr); else supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_pc); break; default: supply_register (regno, (char *) &inferior_registers.r[regno]); break; } }
static void store_register (int regno) { struct reg inferior_registers; #ifndef CROSS_DEBUGGER int ret; ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) &inferior_registers, 0); if (ret < 0) { warning ("unable to fetch general registers"); return; } #endif switch (regno) { case ARM_SP_REGNUM: regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); break; case ARM_LR_REGNUM: regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); break; case ARM_PC_REGNUM: if (arm_apcs_32) regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); else { unsigned pc_val; regcache_collect (ARM_PC_REGNUM, (char *) &pc_val); pc_val = ADDR_BITS_REMOVE (pc_val); inferior_registers.r_pc ^= ADDR_BITS_REMOVE (inferior_registers.r_pc); inferior_registers.r_pc |= pc_val; } break; case ARM_PS_REGNUM: if (arm_apcs_32) regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr); else { unsigned psr_val; regcache_collect (ARM_PS_REGNUM, (char *) &psr_val); psr_val ^= ADDR_BITS_REMOVE (psr_val); inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc); inferior_registers.r_pc |= psr_val; } break; default: regcache_collect (regno, (char *) &inferior_registers.r[regno]); break; } #ifndef CROSS_DEBUGGER ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) &inferior_registers, 0); if (ret < 0) warning ("unable to write register %d to inferior", regno); #endif }
asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int ret = -EPERM; unsigned long tmp; int copied; ptrace_area parea; 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; } 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: copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0); ret = -EIO; if (copied != sizeof(tmp)) break; ret = put_user(tmp,(unsigned long *) data); break; /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: ret=copy_user(child,addr,data,sizeof(unsigned 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_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data)) break; ret = -EIO; break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned 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(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; }