| Jeff Dike | 48b2018 | 2007-05-06 14:51:00 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 
|  | 3 | * Licensed under the GPL | 
|  | 4 | */ | 
|  | 5 |  | 
|  | 6 | #include <stdio.h> | 
| Jeff Dike | 54f9a39 | 2006-12-06 20:34:52 -0800 | [diff] [blame] | 7 | #include <stddef.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 8 | #include <errno.h> | 
|  | 9 | #include <unistd.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | #include "ptrace_user.h" | 
|  | 11 | /* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */ | 
|  | 12 | #include <asm/user.h> | 
|  | 13 | #include "kern_util.h" | 
|  | 14 | #include "sysdep/thread.h" | 
|  | 15 | #include "user.h" | 
|  | 16 | #include "os.h" | 
| Paolo 'Blaisorblade' Giarrusso | 972410b | 2006-03-31 02:30:21 -0800 | [diff] [blame] | 17 | #include "uml-config.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 |  | 
|  | 19 | int ptrace_getregs(long pid, unsigned long *regs_out) | 
|  | 20 | { | 
|  | 21 | if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) | 
|  | 22 | return -errno; | 
|  | 23 | return 0; | 
|  | 24 | } | 
|  | 25 |  | 
|  | 26 | int ptrace_setregs(long pid, unsigned long *regs) | 
|  | 27 | { | 
|  | 28 | if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) | 
|  | 29 | return -errno; | 
|  | 30 | return 0; | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | int ptrace_getfpregs(long pid, unsigned long *regs) | 
|  | 34 | { | 
|  | 35 | if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0) | 
|  | 36 | return -errno; | 
|  | 37 | return 0; | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | int ptrace_setfpregs(long pid, unsigned long *regs) | 
|  | 41 | { | 
|  | 42 | if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) | 
|  | 43 | return -errno; | 
|  | 44 | return 0; | 
|  | 45 | } | 
|  | 46 |  | 
| Jeff Dike | 48b2018 | 2007-05-06 14:51:00 -0700 | [diff] [blame] | 47 | #ifdef UML_CONFIG_MODE_TT | 
|  | 48 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | static void write_debugregs(int pid, unsigned long *regs) | 
|  | 50 | { | 
|  | 51 | struct user *dummy; | 
|  | 52 | int nregs, i; | 
|  | 53 |  | 
|  | 54 | dummy = NULL; | 
| Jeff Dike | 91b165c | 2006-09-25 23:33:00 -0700 | [diff] [blame] | 55 | nregs = ARRAY_SIZE(dummy->u_debugreg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | for(i = 0; i < nregs; i++){ | 
|  | 57 | if((i == 4) || (i == 5)) continue; | 
|  | 58 | if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], | 
|  | 59 | regs[i]) < 0) | 
|  | 60 | printk("write_debugregs - ptrace failed on " | 
| Paolo 'Blaisorblade' Giarrusso | 802e307 | 2006-04-10 22:53:32 -0700 | [diff] [blame] | 61 | "register %d, value = 0x%lx, errno = %d\n", i, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | regs[i], errno); | 
|  | 63 | } | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | static void read_debugregs(int pid, unsigned long *regs) | 
|  | 67 | { | 
|  | 68 | struct user *dummy; | 
|  | 69 | int nregs, i; | 
|  | 70 |  | 
|  | 71 | dummy = NULL; | 
| Jeff Dike | 91b165c | 2006-09-25 23:33:00 -0700 | [diff] [blame] | 72 | nregs = ARRAY_SIZE(dummy->u_debugreg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | for(i = 0; i < nregs; i++){ | 
|  | 74 | regs[i] = ptrace(PTRACE_PEEKUSR, pid, | 
|  | 75 | &dummy->u_debugreg[i], 0); | 
|  | 76 | } | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | /* Accessed only by the tracing thread */ | 
|  | 80 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | void arch_enter_kernel(void *task, int pid) | 
|  | 83 | { | 
|  | 84 | read_debugregs(pid, TASK_DEBUGREGS(task)); | 
|  | 85 | write_debugregs(pid, kernel_debugregs); | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | void arch_leave_kernel(void *task, int pid) | 
|  | 89 | { | 
|  | 90 | read_debugregs(pid, kernel_debugregs); | 
|  | 91 | write_debugregs(pid, TASK_DEBUGREGS(task)); | 
|  | 92 | } | 
|  | 93 |  | 
| Paolo 'Blaisorblade' Giarrusso | 972410b | 2006-03-31 02:30:21 -0800 | [diff] [blame] | 94 | #ifdef UML_CONFIG_PT_PROXY | 
|  | 95 | /* Accessed only by the tracing thread */ | 
|  | 96 | static int debugregs_seq; | 
|  | 97 |  | 
|  | 98 | /* Only called by the ptrace proxy */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | void ptrace_pokeuser(unsigned long addr, unsigned long data) | 
|  | 100 | { | 
|  | 101 | if((addr < offsetof(struct user, u_debugreg[0])) || | 
|  | 102 | (addr > offsetof(struct user, u_debugreg[7]))) | 
|  | 103 | return; | 
|  | 104 | addr -= offsetof(struct user, u_debugreg[0]); | 
|  | 105 | addr = addr >> 2; | 
|  | 106 | if(kernel_debugregs[addr] == data) return; | 
|  | 107 |  | 
|  | 108 | kernel_debugregs[addr] = data; | 
|  | 109 | debugregs_seq++; | 
|  | 110 | } | 
|  | 111 |  | 
|  | 112 | static void update_debugregs_cb(void *arg) | 
|  | 113 | { | 
|  | 114 | int pid = *((int *) arg); | 
|  | 115 |  | 
|  | 116 | write_debugregs(pid, kernel_debugregs); | 
|  | 117 | } | 
|  | 118 |  | 
| Paolo 'Blaisorblade' Giarrusso | 972410b | 2006-03-31 02:30:21 -0800 | [diff] [blame] | 119 | /* Optimized out in its header when not defined */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | void update_debugregs(int seq) | 
|  | 121 | { | 
|  | 122 | int me; | 
|  | 123 |  | 
|  | 124 | if(seq == debugregs_seq) return; | 
|  | 125 |  | 
|  | 126 | me = os_getpid(); | 
|  | 127 | initial_thread_cb(update_debugregs_cb, &me); | 
|  | 128 | } | 
| Paolo 'Blaisorblade' Giarrusso | 972410b | 2006-03-31 02:30:21 -0800 | [diff] [blame] | 129 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 |  | 
| Jeff Dike | 48b2018 | 2007-05-06 14:51:00 -0700 | [diff] [blame] | 131 | #endif |