15c48b108SAl Viro /* 25c48b108SAl Viro * Copyright (C) 2004 PathScale, Inc 35c48b108SAl Viro * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 45c48b108SAl Viro * Licensed under the GPL 55c48b108SAl Viro */ 65c48b108SAl Viro 75c48b108SAl Viro #include <errno.h> 85c48b108SAl Viro #include <sys/ptrace.h> 938b64aedSRichard Weinberger #ifdef __i386__ 105c48b108SAl Viro #include <sys/user.h> 1138b64aedSRichard Weinberger #endif 1237185b33SAl Viro #include <longjmp.h> 1337185b33SAl Viro #include <sysdep/ptrace_user.h> 14a78ff111SEli Cooper #include <sys/uio.h> 15a78ff111SEli Cooper #include <asm/sigcontext.h> 16a78ff111SEli Cooper #include <linux/elf.h> 175c48b108SAl Viro 18a78ff111SEli Cooper int have_xstate_support; 19a78ff111SEli Cooper 20a78ff111SEli Cooper int save_i387_registers(int pid, unsigned long *fp_regs) 215c48b108SAl Viro { 225c48b108SAl Viro if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) 235c48b108SAl Viro return -errno; 245c48b108SAl Viro return 0; 255c48b108SAl Viro } 265c48b108SAl Viro 27a78ff111SEli Cooper int save_fp_registers(int pid, unsigned long *fp_regs) 28a78ff111SEli Cooper { 290a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET 30a78ff111SEli Cooper struct iovec iov; 31a78ff111SEli Cooper 32a78ff111SEli Cooper if (have_xstate_support) { 33a78ff111SEli Cooper iov.iov_base = fp_regs; 34a78ff111SEli Cooper iov.iov_len = sizeof(struct _xstate); 35a78ff111SEli Cooper if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 36a78ff111SEli Cooper return -errno; 37a78ff111SEli Cooper return 0; 380a987645SFlorian Fainelli } else 390a987645SFlorian Fainelli #endif 40a78ff111SEli Cooper return save_i387_registers(pid, fp_regs); 41a78ff111SEli Cooper } 42a78ff111SEli Cooper 43a78ff111SEli Cooper int restore_i387_registers(int pid, unsigned long *fp_regs) 445c48b108SAl Viro { 455c48b108SAl Viro if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) 465c48b108SAl Viro return -errno; 475c48b108SAl Viro return 0; 485c48b108SAl Viro } 495c48b108SAl Viro 50a78ff111SEli Cooper int restore_fp_registers(int pid, unsigned long *fp_regs) 51a78ff111SEli Cooper { 520a987645SFlorian Fainelli #ifdef PTRACE_SETREGSET 53a78ff111SEli Cooper struct iovec iov; 54a78ff111SEli Cooper 55a78ff111SEli Cooper if (have_xstate_support) { 56a78ff111SEli Cooper iov.iov_base = fp_regs; 57a78ff111SEli Cooper iov.iov_len = sizeof(struct _xstate); 58a78ff111SEli Cooper if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 59a78ff111SEli Cooper return -errno; 60a78ff111SEli Cooper return 0; 610a987645SFlorian Fainelli } else 620a987645SFlorian Fainelli #endif 63a78ff111SEli Cooper return restore_i387_registers(pid, fp_regs); 64a78ff111SEli Cooper } 65a78ff111SEli Cooper 665c48b108SAl Viro #ifdef __i386__ 675c48b108SAl Viro int have_fpx_regs = 1; 685c48b108SAl Viro int save_fpx_registers(int pid, unsigned long *fp_regs) 695c48b108SAl Viro { 705c48b108SAl Viro if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) 715c48b108SAl Viro return -errno; 725c48b108SAl Viro return 0; 735c48b108SAl Viro } 745c48b108SAl Viro 755c48b108SAl Viro int restore_fpx_registers(int pid, unsigned long *fp_regs) 765c48b108SAl Viro { 775c48b108SAl Viro if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) 785c48b108SAl Viro return -errno; 795c48b108SAl Viro return 0; 805c48b108SAl Viro } 815c48b108SAl Viro 825c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs) 835c48b108SAl Viro { 845c48b108SAl Viro if (have_fpx_regs) 855c48b108SAl Viro return save_fpx_registers(pid, regs); 865c48b108SAl Viro else 875c48b108SAl Viro return save_fp_registers(pid, regs); 885c48b108SAl Viro } 895c48b108SAl Viro 905c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs) 915c48b108SAl Viro { 925c48b108SAl Viro if (have_fpx_regs) 935c48b108SAl Viro return restore_fpx_registers(pid, regs); 945c48b108SAl Viro else 955c48b108SAl Viro return restore_fp_registers(pid, regs); 965c48b108SAl Viro } 975c48b108SAl Viro 985c48b108SAl Viro void arch_init_registers(int pid) 995c48b108SAl Viro { 1005c48b108SAl Viro struct user_fpxregs_struct fpx_regs; 1015c48b108SAl Viro int err; 1025c48b108SAl Viro 1035c48b108SAl Viro err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); 1045c48b108SAl Viro if (!err) 1055c48b108SAl Viro return; 1065c48b108SAl Viro 1075c48b108SAl Viro if (errno != EIO) 1085c48b108SAl Viro panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 1095c48b108SAl Viro errno); 1105c48b108SAl Viro 1115c48b108SAl Viro have_fpx_regs = 0; 1125c48b108SAl Viro } 1135c48b108SAl Viro #else 1145c48b108SAl Viro 1155c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs) 1165c48b108SAl Viro { 1175c48b108SAl Viro return save_fp_registers(pid, regs); 1185c48b108SAl Viro } 1195c48b108SAl Viro 1205c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs) 1215c48b108SAl Viro { 1225c48b108SAl Viro return restore_fp_registers(pid, regs); 1235c48b108SAl Viro } 1245c48b108SAl Viro 125a78ff111SEli Cooper void arch_init_registers(int pid) 126a78ff111SEli Cooper { 1270a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET 128a78ff111SEli Cooper struct _xstate fp_regs; 129a78ff111SEli Cooper struct iovec iov; 130a78ff111SEli Cooper 131a78ff111SEli Cooper iov.iov_base = &fp_regs; 132a78ff111SEli Cooper iov.iov_len = sizeof(struct _xstate); 133a78ff111SEli Cooper if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) 134a78ff111SEli Cooper have_xstate_support = 1; 1350a987645SFlorian Fainelli #endif 136a78ff111SEli Cooper } 1375c48b108SAl Viro #endif 1385c48b108SAl Viro 1395c48b108SAl Viro unsigned long get_thread_reg(int reg, jmp_buf *buf) 1405c48b108SAl Viro { 1415c48b108SAl Viro switch (reg) { 1425c48b108SAl Viro #ifdef __i386__ 143a10c95d8SAl Viro case HOST_IP: 1445c48b108SAl Viro return buf[0]->__eip; 145a10c95d8SAl Viro case HOST_SP: 1465c48b108SAl Viro return buf[0]->__esp; 147a10c95d8SAl Viro case HOST_BP: 1485c48b108SAl Viro return buf[0]->__ebp; 1495c48b108SAl Viro #else 150a10c95d8SAl Viro case HOST_IP: 1515c48b108SAl Viro return buf[0]->__rip; 152a10c95d8SAl Viro case HOST_SP: 1535c48b108SAl Viro return buf[0]->__rsp; 154a10c95d8SAl Viro case HOST_BP: 1555c48b108SAl Viro return buf[0]->__rbp; 1565c48b108SAl Viro #endif 1575c48b108SAl Viro default: 1585c48b108SAl Viro printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", 1595c48b108SAl Viro reg); 1605c48b108SAl Viro return 0; 1615c48b108SAl Viro } 1625c48b108SAl Viro } 163