Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2004 PathScale, Inc |
Jeff Dike | f0c4cad | 2007-10-16 01:27:18 -0700 | [diff] [blame] | 3 | * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | * Licensed under the GPL |
| 5 | */ |
| 6 | |
| 7 | #include <errno.h> |
Al Viro | 3787fa6 | 2008-05-21 06:32:11 +0100 | [diff] [blame] | 8 | #include <sys/ptrace.h> |
Richard Weinberger | 38b64ae | 2011-08-18 21:58:07 +0200 | [diff] [blame] | 9 | #ifdef __i386__ |
Jeff Dike | 14c8a77 | 2008-06-12 15:21:40 -0700 | [diff] [blame] | 10 | #include <sys/user.h> |
Richard Weinberger | 38b64ae | 2011-08-18 21:58:07 +0200 | [diff] [blame] | 11 | #endif |
Al Viro | 37185b3 | 2012-10-08 03:27:32 +0100 | [diff] [blame] | 12 | #include <longjmp.h> |
| 13 | #include <sysdep/ptrace_user.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | int save_fp_registers(int pid, unsigned long *fp_regs) |
| 16 | { |
Jeff Dike | f0c4cad | 2007-10-16 01:27:18 -0700 | [diff] [blame] | 17 | if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) |
Jeff Dike | 6c59e2f | 2007-02-10 01:44:26 -0800 | [diff] [blame] | 18 | return -errno; |
| 19 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | } |
| 21 | |
| 22 | int restore_fp_registers(int pid, unsigned long *fp_regs) |
| 23 | { |
Jeff Dike | f0c4cad | 2007-10-16 01:27:18 -0700 | [diff] [blame] | 24 | if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) |
Jeff Dike | 6c59e2f | 2007-02-10 01:44:26 -0800 | [diff] [blame] | 25 | return -errno; |
| 26 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | } |
| 28 | |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 29 | #ifdef __i386__ |
| 30 | int have_fpx_regs = 1; |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 31 | int save_fpx_registers(int pid, unsigned long *fp_regs) |
| 32 | { |
Jeff Dike | f0c4cad | 2007-10-16 01:27:18 -0700 | [diff] [blame] | 33 | if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 34 | return -errno; |
| 35 | return 0; |
| 36 | } |
| 37 | |
| 38 | int restore_fpx_registers(int pid, unsigned long *fp_regs) |
| 39 | { |
Jeff Dike | f0c4cad | 2007-10-16 01:27:18 -0700 | [diff] [blame] | 40 | if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 41 | return -errno; |
| 42 | return 0; |
| 43 | } |
| 44 | |
Jeff Dike | 2f56deb | 2008-02-23 15:23:49 -0800 | [diff] [blame] | 45 | int get_fp_registers(int pid, unsigned long *regs) |
| 46 | { |
| 47 | if (have_fpx_regs) |
| 48 | return save_fpx_registers(pid, regs); |
| 49 | else |
| 50 | return save_fp_registers(pid, regs); |
| 51 | } |
| 52 | |
| 53 | int put_fp_registers(int pid, unsigned long *regs) |
| 54 | { |
| 55 | if (have_fpx_regs) |
| 56 | return restore_fpx_registers(pid, regs); |
| 57 | else |
| 58 | return restore_fp_registers(pid, regs); |
| 59 | } |
| 60 | |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 61 | void arch_init_registers(int pid) |
| 62 | { |
Jeff Dike | 14c8a77 | 2008-06-12 15:21:40 -0700 | [diff] [blame] | 63 | struct user_fpxregs_struct fpx_regs; |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 64 | int err; |
| 65 | |
Jeff Dike | 47906dd | 2008-05-12 14:01:50 -0700 | [diff] [blame] | 66 | err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); |
Jeff Dike | 5134d8f | 2008-02-08 04:22:08 -0800 | [diff] [blame] | 67 | if (!err) |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 68 | return; |
| 69 | |
Jeff Dike | 5134d8f | 2008-02-08 04:22:08 -0800 | [diff] [blame] | 70 | if (errno != EIO) |
Jeff Dike | a5f6096c | 2007-10-16 01:27:15 -0700 | [diff] [blame] | 71 | panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", |
| 72 | errno); |
| 73 | |
| 74 | have_fpx_regs = 0; |
| 75 | } |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 76 | #else |
| 77 | |
| 78 | int get_fp_registers(int pid, unsigned long *regs) |
| 79 | { |
| 80 | return save_fp_registers(pid, regs); |
| 81 | } |
| 82 | |
| 83 | int put_fp_registers(int pid, unsigned long *regs) |
| 84 | { |
| 85 | return restore_fp_registers(pid, regs); |
| 86 | } |
| 87 | |
| 88 | #endif |
| 89 | |
| 90 | unsigned long get_thread_reg(int reg, jmp_buf *buf) |
| 91 | { |
| 92 | switch (reg) { |
| 93 | #ifdef __i386__ |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 94 | case HOST_IP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 95 | return buf[0]->__eip; |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 96 | case HOST_SP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 97 | return buf[0]->__esp; |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 98 | case HOST_BP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 99 | return buf[0]->__ebp; |
| 100 | #else |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 101 | case HOST_IP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 102 | return buf[0]->__rip; |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 103 | case HOST_SP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 104 | return buf[0]->__rsp; |
Al Viro | a10c95d | 2011-08-18 20:12:09 +0100 | [diff] [blame] | 105 | case HOST_BP: |
Al Viro | 51d3474 | 2011-08-18 20:03:49 +0100 | [diff] [blame] | 106 | return buf[0]->__rbp; |
| 107 | #endif |
| 108 | default: |
| 109 | printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", |
| 110 | reg); |
| 111 | return 0; |
| 112 | } |
| 113 | } |