Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Revise MIPS 64-bit ptrace interface Change the N32 debugging ABI to something more sane, and add support for o32 and n32 debuggers to trace n64 programs. Signed-off-by: Daniel Jacobowitz <dan@codesourcery.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Daniel Jacobowitz and committed by
Ralf Baechle
ea3d710f 9043f7e9

+222 -5
+129
arch/mips/kernel/ptrace.c
··· 38 38 #include <asm/system.h> 39 39 #include <asm/uaccess.h> 40 40 #include <asm/bootinfo.h> 41 + #include <asm/reg.h> 41 42 42 43 /* 43 44 * Called by kernel/ptrace.c when detaching.. ··· 48 47 void ptrace_disable(struct task_struct *child) 49 48 { 50 49 /* Nothing to do.. */ 50 + } 51 + 52 + /* 53 + * Read a general register set. We always use the 64-bit format, even 54 + * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. 55 + * Registers are sign extended to fill the available space. 56 + */ 57 + int ptrace_getregs (struct task_struct *child, __s64 __user *data) 58 + { 59 + struct pt_regs *regs; 60 + int i; 61 + 62 + if (!access_ok(VERIFY_WRITE, data, 38 * 8)) 63 + return -EIO; 64 + 65 + regs = (struct pt_regs *) ((unsigned long) child->thread_info + 66 + THREAD_SIZE - 32 - sizeof(struct pt_regs)); 67 + 68 + for (i = 0; i < 32; i++) 69 + __put_user (regs->regs[i], data + i); 70 + __put_user (regs->lo, data + EF_LO - EF_R0); 71 + __put_user (regs->hi, data + EF_HI - EF_R0); 72 + __put_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); 73 + __put_user (regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); 74 + __put_user (regs->cp0_status, data + EF_CP0_STATUS - EF_R0); 75 + __put_user (regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); 76 + 77 + return 0; 78 + } 79 + 80 + /* 81 + * Write a general register set. As for PTRACE_GETREGS, we always use 82 + * the 64-bit format. On a 32-bit kernel only the lower order half 83 + * (according to endianness) will be used. 84 + */ 85 + int ptrace_setregs (struct task_struct *child, __s64 __user *data) 86 + { 87 + struct pt_regs *regs; 88 + int i; 89 + 90 + if (!access_ok(VERIFY_READ, data, 38 * 8)) 91 + return -EIO; 92 + 93 + regs = (struct pt_regs *) ((unsigned long) child->thread_info + 94 + THREAD_SIZE - 32 - sizeof(struct pt_regs)); 95 + 96 + for (i = 0; i < 32; i++) 97 + __get_user (regs->regs[i], data + i); 98 + __get_user (regs->lo, data + EF_LO - EF_R0); 99 + __get_user (regs->hi, data + EF_HI - EF_R0); 100 + __get_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); 101 + 102 + /* badvaddr, status, and cause may not be written. */ 103 + 104 + return 0; 105 + } 106 + 107 + int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) 108 + { 109 + int i; 110 + 111 + if (!access_ok(VERIFY_WRITE, data, 33 * 8)) 112 + return -EIO; 113 + 114 + if (tsk_used_math(child)) { 115 + fpureg_t *fregs = get_fpu_regs(child); 116 + for (i = 0; i < 32; i++) 117 + __put_user (fregs[i], i + (__u64 __user *) data); 118 + } else { 119 + for (i = 0; i < 32; i++) 120 + __put_user ((__u64) -1, i + (__u64 __user *) data); 121 + } 122 + 123 + if (cpu_has_fpu) { 124 + unsigned int flags, tmp; 125 + 126 + __put_user (child->thread.fpu.hard.fcr31, data + 64); 127 + 128 + flags = read_c0_status(); 129 + __enable_fpu(); 130 + __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); 131 + write_c0_status(flags); 132 + __put_user (tmp, data + 65); 133 + } else { 134 + __put_user (child->thread.fpu.soft.fcr31, data + 64); 135 + __put_user ((__u32) 0, data + 65); 136 + } 137 + 138 + return 0; 139 + } 140 + 141 + int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) 142 + { 143 + fpureg_t *fregs; 144 + int i; 145 + 146 + if (!access_ok(VERIFY_READ, data, 33 * 8)) 147 + return -EIO; 148 + 149 + fregs = get_fpu_regs(child); 150 + 151 + for (i = 0; i < 32; i++) 152 + __get_user (fregs[i], i + (__u64 __user *) data); 153 + 154 + if (cpu_has_fpu) 155 + __get_user (child->thread.fpu.hard.fcr31, data + 64); 156 + else 157 + __get_user (child->thread.fpu.soft.fcr31, data + 64); 158 + 159 + /* FIR may not be written. */ 160 + 161 + return 0; 51 162 } 52 163 53 164 asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ··· 412 299 } 413 300 break; 414 301 } 302 + 303 + case PTRACE_GETREGS: 304 + ret = ptrace_getregs (child, (__u64 __user *) data); 305 + break; 306 + 307 + case PTRACE_SETREGS: 308 + ret = ptrace_setregs (child, (__u64 __user *) data); 309 + break; 310 + 311 + case PTRACE_GETFPREGS: 312 + ret = ptrace_getfpregs (child, (__u32 __user *) data); 313 + break; 314 + 315 + case PTRACE_SETFPREGS: 316 + ret = ptrace_setfpregs (child, (__u32 __user *) data); 317 + break; 415 318 416 319 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 417 320 case PTRACE_CONT: { /* restart after signal. */
+81
arch/mips/kernel/ptrace32.c
··· 35 35 #include <asm/uaccess.h> 36 36 #include <asm/bootinfo.h> 37 37 38 + int ptrace_getregs (struct task_struct *child, __s64 __user *data); 39 + int ptrace_setregs (struct task_struct *child, __s64 __user *data); 40 + 41 + int ptrace_getfpregs (struct task_struct *child, __u32 __user *data); 42 + int ptrace_setfpregs (struct task_struct *child, __u32 __user *data); 43 + 38 44 /* 39 45 * Tracing a 32-bit process with a 64-bit strace and vice versa will not 40 46 * work. I don't know how to fix this. ··· 102 96 if (copied != sizeof(tmp)) 103 97 break; 104 98 ret = put_user(tmp, (unsigned int *) (unsigned long) data); 99 + break; 100 + } 101 + 102 + /* 103 + * Read 4 bytes of the other process' storage 104 + * data is a pointer specifying where the user wants the 105 + * 4 bytes copied into 106 + * addr is a pointer in the user's storage that contains an 8 byte 107 + * address in the other process of the 4 bytes that is to be read 108 + * (this is run in a 32-bit process looking at a 64-bit process) 109 + * when I and D space are separate, these will need to be fixed. 110 + */ 111 + case PTRACE_PEEKTEXT_3264: 112 + case PTRACE_PEEKDATA_3264: { 113 + u32 tmp; 114 + int copied; 115 + u32 __user * addrOthers; 116 + 117 + ret = -EIO; 118 + 119 + /* Get the addr in the other process that we want to read */ 120 + if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) 121 + break; 122 + 123 + copied = access_process_vm(child, (u64)addrOthers, &tmp, 124 + sizeof(tmp), 0); 125 + if (copied != sizeof(tmp)) 126 + break; 127 + ret = put_user(tmp, (u32 __user *) (unsigned long) data); 105 128 break; 106 129 } 107 130 ··· 237 202 ret = -EIO; 238 203 break; 239 204 205 + /* 206 + * Write 4 bytes into the other process' storage 207 + * data is the 4 bytes that the user wants written 208 + * addr is a pointer in the user's storage that contains an 209 + * 8 byte address in the other process where the 4 bytes 210 + * that is to be written 211 + * (this is run in a 32-bit process looking at a 64-bit process) 212 + * when I and D space are separate, these will need to be fixed. 213 + */ 214 + case PTRACE_POKETEXT_3264: 215 + case PTRACE_POKEDATA_3264: { 216 + u32 __user * addrOthers; 217 + 218 + /* Get the addr in the other process that we want to write into */ 219 + ret = -EIO; 220 + if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) 221 + break; 222 + ret = 0; 223 + if (access_process_vm(child, (u64)addrOthers, &data, 224 + sizeof(data), 1) == sizeof(data)) 225 + break; 226 + ret = -EIO; 227 + break; 228 + } 229 + 240 230 case PTRACE_POKEUSR: { 241 231 struct pt_regs *regs; 242 232 ret = 0; ··· 336 276 break; 337 277 } 338 278 279 + case PTRACE_GETREGS: 280 + ret = ptrace_getregs (child, (__u64 __user *) (__u64) data); 281 + break; 282 + 283 + case PTRACE_SETREGS: 284 + ret = ptrace_setregs (child, (__u64 __user *) (__u64) data); 285 + break; 286 + 287 + case PTRACE_GETFPREGS: 288 + ret = ptrace_getfpregs (child, (__u32 __user *) (__u64) data); 289 + break; 290 + 291 + case PTRACE_SETFPREGS: 292 + ret = ptrace_setfpregs (child, (__u32 __user *) (__u64) data); 293 + break; 294 + 339 295 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 340 296 case PTRACE_CONT: { /* restart after signal. */ 341 297 ret = -EIO; ··· 394 318 case PTRACE_GETEVENTMSG: 395 319 ret = put_user(child->ptrace_message, 396 320 (unsigned int __user *) (unsigned long) data); 321 + break; 322 + 323 + case PTRACE_GET_THREAD_AREA_3264: 324 + ret = put_user(child->thread_info->tp_value, 325 + (unsigned long __user *) (unsigned long) data); 397 326 break; 398 327 399 328 default:
+1 -1
arch/mips/kernel/scall64-n32.S
··· 216 216 PTR compat_sys_getrusage 217 217 PTR sys32_sysinfo 218 218 PTR compat_sys_times 219 - PTR sys_ptrace 219 + PTR sys32_ptrace 220 220 PTR sys_getuid /* 6100 */ 221 221 PTR sys_syslog 222 222 PTR sys_getgid
+11 -4
include/asm-mips/ptrace.h
··· 48 48 }; 49 49 50 50 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ 51 - /* #define PTRACE_GETREGS 12 */ 52 - /* #define PTRACE_SETREGS 13 */ 53 - /* #define PTRACE_GETFPREGS 14 */ 54 - /* #define PTRACE_SETFPREGS 15 */ 51 + #define PTRACE_GETREGS 12 52 + #define PTRACE_SETREGS 13 53 + #define PTRACE_GETFPREGS 14 54 + #define PTRACE_SETFPREGS 15 55 55 /* #define PTRACE_GETFPXREGS 18 */ 56 56 /* #define PTRACE_SETFPXREGS 19 */ 57 57 ··· 59 59 60 60 #define PTRACE_GET_THREAD_AREA 25 61 61 #define PTRACE_SET_THREAD_AREA 26 62 + 63 + /* Calls to trace a 64bit program from a 32bit program. */ 64 + #define PTRACE_PEEKTEXT_3264 0xc0 65 + #define PTRACE_PEEKDATA_3264 0xc1 66 + #define PTRACE_POKETEXT_3264 0xc2 67 + #define PTRACE_POKEDATA_3264 0xc3 68 + #define PTRACE_GET_THREAD_AREA_3264 0xc4 62 69 63 70 #ifdef __KERNEL__ 64 71