From: Dave A. <ai...@us...> - 2001-10-28 23:54:21
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel In directory usw-pr-cvs1:/tmp/cvs-serv8312 Modified Files: process.c interrupt.c interrupt.h Makefile Added Files: ptrace.c Log Message: DA: add initial ptrace support --- NEW FILE --- /* $Id: ptrace.c,v 1.1 2001/10/28 23:54:18 airlied Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992 Ross Biro * Copyright (C) Linus Torvalds * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle * Copyright (C) 1996 David S. Miller */ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/user.h> #if 0 #include <asm/fp.h> #include <asm/mipsregs.h> #endif #include <asm/pgtable.h> #include <asm/page.h> #include <asm/system.h> #include <asm/uaccess.h> static int putreg(struct task_struct *child, unsigned long regno, unsigned long value) { printk("putreg called with regno %d\n", regno); switch(regno >> 2) { case 0 ... 13: *(unsigned long *)((&child->thread.pcb)+4+(regno>>2))=value; break; case PT_SP: child->thread.pcb.usp=value; break; case PT_PC: child->thread.pcb.pc=value; break; default: printk("putreg for %d failed\n", regno); break; } return 0; } static unsigned long getreg(struct task_struct *child, unsigned long regno) { unsigned long retval = ~0UL; /* this code takes the register from the PCB for the process. PC is reg 15 but 14'th after R0 in the pcb so it is special cased. have to add some stack pointers at some stage */ switch(regno >> 2) { case 0 ... 13: retval = (unsigned long)*(unsigned long *)((&child->thread.pcb)+4+(regno>>2)); break; case PT_SP: retval = child->thread.pcb.usp; case PT_PC: retval = child->thread.pcb.pc; break; default: printk("getreg for %d failed\n", regno); retval=0; break; } printk("getreg returning %8lX\n", retval); return retval; } asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int res; extern void save_fp(void*); lock_kernel(); #if 1 printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", (int) request, (int) pid, (unsigned long) addr, (unsigned long) data); #endif if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { res = -EPERM; goto out; } /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; res = 0; goto out; } res = -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; res = -EPERM; if (pid == 1) /* you may not mess with init */ goto out; if (request == PTRACE_ATTACH) { if (child == current) goto out_tsk; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || (current->gid != child->gid) || (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) goto out_tsk; child->ptrace |= PT_PTRACED; write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } write_unlock_irq(&tasklist_lock); send_sig(SIGSTOP, child, 1); res = 0; goto out_tsk; } res = -ESRCH; 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) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; int copied; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); res = -EIO; if (copied != sizeof(tmp)) break; res = put_user(tmp,(unsigned long *) data); goto out; } /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; res = -EIO; printk("Addr is %8lX, sizeof is %8lX\n", addr, sizeof(struct user)); if ((addr & 3) || addr < 0 || addr > sizeof(struct user)-3) break; tmp=0; if (addr < 16*sizeof(unsigned long)) tmp = getreg(child, addr); res = put_user(tmp, (unsigned long *) data); goto out; } case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: res = 0; if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; res = -EIO; goto out; case PTRACE_POKEUSR: { struct pt_regs *regs; int res = 0; res = -EIO; if ((addr & 3) || addr < 0 || addr > sizeof(struct user) - 3) break; if (addr < 17*sizeof(long)) { res = putreg(child, addr, data); break; } /* We need to be very careful here. We implicitly want to modify a portion of the task_struct, and we have to be selective about what portions we allow someone to modify. */ break; } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ res = -EIO; if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process(child); res = 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: res = 0; if (child->state != TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; wake_up_process(child); break; case PTRACE_DETACH: /* detach a process that was attached. */ res = -EIO; if ((unsigned long) data > _NSIG) break; child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); write_unlock_irq(&tasklist_lock); wake_up_process(child); res = 0; break; default: res = -EIO; goto out; } out_tsk: free_task_struct(child); out: unlock_kernel(); return res; } asmlinkage void syscall_trace(void) { if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; 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; } } Index: process.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/process.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- process.c 2001/09/22 19:44:18 1.14 +++ process.c 2001/10/28 23:54:18 1.15 @@ -122,7 +122,6 @@ // printk("copy_thread: pid %d, task 0x%08lx, kstack_top 0x%8lx, usp 0x%08lx, ksp 0x%08lx\n", // p->pid, (unsigned long)p, stack_top, usp, child_stack); - child_regs = &child_stack->regs; *child_regs = *regs; @@ -217,11 +216,6 @@ int sys_vfork(struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0); -} - -int sys_ptrace(long request, long pid, long addr, long data) -{ - return -ENOSYS; } /* Index: interrupt.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/interrupt.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- interrupt.c 2001/09/16 15:23:20 1.20 +++ interrupt.c 2001/10/28 23:54:18 1.21 @@ -192,6 +192,10 @@ printk("Panic: unable to register arithmetic fault handler\n"); machine_halt(); } + if (register_excep_handler(SCB_BPT,"Breakpoint fault (bpt_handler)", bpt_handler, 0, 0)) { + printk("Panic: unable to register breakpoint handler\n"); + machine_halt(); + } } @@ -249,6 +253,26 @@ machine_halt(); } +/* This is the handler for break points */ +void bpt_handler(struct pt_regs *regs, void *unused) +{ + printk("\nbp sending SIGTRAP\n"); +#if 0 + printk("\nBreakpoint at PC=%08lx\n", regs->pc); + + printk("\nStack dump\n"); + hex_dump((void *)(regs->sp), 256); + show_regs(regs); + show_cpu_regs(); + + if (user_mode(regs)) { + force_sig(SIGTRAP,current); + return; + } + machine_halt(); +#endif + force_sig(SIGTRAP, current); +} /* This is the handler for reserved addressing mode exceptions. Eventually this will have to check if the fault was from user @@ -300,8 +324,7 @@ }; void arith_handler(struct pt_regs *regs, void *excep_info) -{ - int code = *(unsigned int *)(excep_info); +{ int code = *(unsigned int *)(excep_info); printk("Arithmetic Fault at PC=%8lx, %s, (code=%x)\n",regs->pc,arith_faults[code],code); /* FIXME: need to code up the info for user handler */ if (user_mode(regs)) { Index: interrupt.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/interrupt.h,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- interrupt.h 2001/09/06 23:39:42 1.6 +++ interrupt.h 2001/10/28 23:54:18 1.7 @@ -67,3 +67,4 @@ extern void syscall_handler(struct pt_regs *regs, void *excep_info); extern void resam_handler(struct pt_regs *regs, void *unused); extern void arith_handler(struct pt_regs *regs, void *excep_info); +extern void bpt_handler(struct pt_regs *regs, void *excep_info); Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/Makefile,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- Makefile 2001/03/04 23:44:42 1.7 +++ Makefile 2001/10/28 23:54:18 1.8 @@ -13,7 +13,7 @@ O_TARGET := kernel.o -obj-y := process.o setup.o regdump.o interrupt.o entry.o time.o \ +obj-y := ptrace.o process.o setup.o regdump.o interrupt.o entry.o time.o \ syscall.o signal.o semaphore.o vax_dev_init.o\ init_task.o reboot.o cpu_generic.o \ cpu_ka630.o cpu_ka640.o cpu_ka650.o cpu_ka660.o \ |