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>
86f602afdSThomas Meyer #include <stdlib.h>
95c48b108SAl Viro #include <sys/ptrace.h>
1038b64aedSRichard Weinberger #ifdef __i386__
115c48b108SAl Viro #include <sys/user.h>
1238b64aedSRichard Weinberger #endif
1337185b33SAl Viro #include <longjmp.h>
1437185b33SAl Viro #include <sysdep/ptrace_user.h>
15a78ff111SEli Cooper #include <sys/uio.h>
16a78ff111SEli Cooper #include <asm/sigcontext.h>
17a78ff111SEli Cooper #include <linux/elf.h>
18*dbba7f70SAl Viro #include <registers.h>
195c48b108SAl Viro
20a78ff111SEli Cooper int have_xstate_support;
21a78ff111SEli Cooper
save_i387_registers(int pid,unsigned long * fp_regs)22a78ff111SEli Cooper int save_i387_registers(int pid, unsigned long *fp_regs)
235c48b108SAl Viro {
245c48b108SAl Viro if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
255c48b108SAl Viro return -errno;
265c48b108SAl Viro return 0;
275c48b108SAl Viro }
285c48b108SAl Viro
save_fp_registers(int pid,unsigned long * fp_regs)29a78ff111SEli Cooper int save_fp_registers(int pid, unsigned long *fp_regs)
30a78ff111SEli Cooper {
310a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET
32a78ff111SEli Cooper struct iovec iov;
33a78ff111SEli Cooper
34a78ff111SEli Cooper if (have_xstate_support) {
35a78ff111SEli Cooper iov.iov_base = fp_regs;
366f602afdSThomas Meyer iov.iov_len = FP_SIZE * sizeof(unsigned long);
37a78ff111SEli Cooper if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
38a78ff111SEli Cooper return -errno;
39a78ff111SEli Cooper return 0;
400a987645SFlorian Fainelli } else
410a987645SFlorian Fainelli #endif
42a78ff111SEli Cooper return save_i387_registers(pid, fp_regs);
43a78ff111SEli Cooper }
44a78ff111SEli Cooper
restore_i387_registers(int pid,unsigned long * fp_regs)45a78ff111SEli Cooper int restore_i387_registers(int pid, unsigned long *fp_regs)
465c48b108SAl Viro {
475c48b108SAl Viro if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
485c48b108SAl Viro return -errno;
495c48b108SAl Viro return 0;
505c48b108SAl Viro }
515c48b108SAl Viro
restore_fp_registers(int pid,unsigned long * fp_regs)52a78ff111SEli Cooper int restore_fp_registers(int pid, unsigned long *fp_regs)
53a78ff111SEli Cooper {
540a987645SFlorian Fainelli #ifdef PTRACE_SETREGSET
55a78ff111SEli Cooper struct iovec iov;
56a78ff111SEli Cooper if (have_xstate_support) {
57a78ff111SEli Cooper iov.iov_base = fp_regs;
586f602afdSThomas Meyer iov.iov_len = FP_SIZE * sizeof(unsigned long);
59a78ff111SEli Cooper if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
60a78ff111SEli Cooper return -errno;
61a78ff111SEli Cooper return 0;
620a987645SFlorian Fainelli } else
630a987645SFlorian Fainelli #endif
64a78ff111SEli Cooper return restore_i387_registers(pid, fp_regs);
65a78ff111SEli Cooper }
66a78ff111SEli Cooper
675c48b108SAl Viro #ifdef __i386__
685c48b108SAl Viro int have_fpx_regs = 1;
save_fpx_registers(int pid,unsigned long * fp_regs)695c48b108SAl Viro int save_fpx_registers(int pid, unsigned long *fp_regs)
705c48b108SAl Viro {
715c48b108SAl Viro if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0)
725c48b108SAl Viro return -errno;
735c48b108SAl Viro return 0;
745c48b108SAl Viro }
755c48b108SAl Viro
restore_fpx_registers(int pid,unsigned long * fp_regs)765c48b108SAl Viro int restore_fpx_registers(int pid, unsigned long *fp_regs)
775c48b108SAl Viro {
785c48b108SAl Viro if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0)
795c48b108SAl Viro return -errno;
805c48b108SAl Viro return 0;
815c48b108SAl Viro }
825c48b108SAl Viro
get_fp_registers(int pid,unsigned long * regs)835c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs)
845c48b108SAl Viro {
855c48b108SAl Viro if (have_fpx_regs)
865c48b108SAl Viro return save_fpx_registers(pid, regs);
875c48b108SAl Viro else
885c48b108SAl Viro return save_fp_registers(pid, regs);
895c48b108SAl Viro }
905c48b108SAl Viro
put_fp_registers(int pid,unsigned long * regs)915c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs)
925c48b108SAl Viro {
935c48b108SAl Viro if (have_fpx_regs)
945c48b108SAl Viro return restore_fpx_registers(pid, regs);
955c48b108SAl Viro else
965c48b108SAl Viro return restore_fp_registers(pid, regs);
975c48b108SAl Viro }
985c48b108SAl Viro
arch_init_registers(int pid)995c48b108SAl Viro void arch_init_registers(int pid)
1005c48b108SAl Viro {
1015c48b108SAl Viro struct user_fpxregs_struct fpx_regs;
1025c48b108SAl Viro int err;
1035c48b108SAl Viro
1045c48b108SAl Viro err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
1055c48b108SAl Viro if (!err)
1065c48b108SAl Viro return;
1075c48b108SAl Viro
1085c48b108SAl Viro if (errno != EIO)
1095c48b108SAl Viro panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
1105c48b108SAl Viro errno);
1115c48b108SAl Viro
1125c48b108SAl Viro have_fpx_regs = 0;
1135c48b108SAl Viro }
1145c48b108SAl Viro #else
1155c48b108SAl Viro
get_fp_registers(int pid,unsigned long * regs)1165c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs)
1175c48b108SAl Viro {
1185c48b108SAl Viro return save_fp_registers(pid, regs);
1195c48b108SAl Viro }
1205c48b108SAl Viro
put_fp_registers(int pid,unsigned long * regs)1215c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs)
1225c48b108SAl Viro {
1235c48b108SAl Viro return restore_fp_registers(pid, regs);
1245c48b108SAl Viro }
1255c48b108SAl Viro
arch_init_registers(int pid)126a78ff111SEli Cooper void arch_init_registers(int pid)
127a78ff111SEli Cooper {
1280a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET
1296f602afdSThomas Meyer void * fp_regs;
130a78ff111SEli Cooper struct iovec iov;
131a78ff111SEli Cooper
1326f602afdSThomas Meyer fp_regs = malloc(FP_SIZE * sizeof(unsigned long));
1336f602afdSThomas Meyer if(fp_regs == NULL)
1346f602afdSThomas Meyer return;
1356f602afdSThomas Meyer
1366f602afdSThomas Meyer iov.iov_base = fp_regs;
1376f602afdSThomas Meyer iov.iov_len = FP_SIZE * sizeof(unsigned long);
138a78ff111SEli Cooper if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
139a78ff111SEli Cooper have_xstate_support = 1;
1406f602afdSThomas Meyer
1416f602afdSThomas Meyer free(fp_regs);
1420a987645SFlorian Fainelli #endif
143a78ff111SEli Cooper }
1445c48b108SAl Viro #endif
1455c48b108SAl Viro
get_thread_reg(int reg,jmp_buf * buf)1465c48b108SAl Viro unsigned long get_thread_reg(int reg, jmp_buf *buf)
1475c48b108SAl Viro {
1485c48b108SAl Viro switch (reg) {
1495c48b108SAl Viro #ifdef __i386__
150a10c95d8SAl Viro case HOST_IP:
1515c48b108SAl Viro return buf[0]->__eip;
152a10c95d8SAl Viro case HOST_SP:
1535c48b108SAl Viro return buf[0]->__esp;
154a10c95d8SAl Viro case HOST_BP:
1555c48b108SAl Viro return buf[0]->__ebp;
1565c48b108SAl Viro #else
157a10c95d8SAl Viro case HOST_IP:
1585c48b108SAl Viro return buf[0]->__rip;
159a10c95d8SAl Viro case HOST_SP:
1605c48b108SAl Viro return buf[0]->__rsp;
161a10c95d8SAl Viro case HOST_BP:
1625c48b108SAl Viro return buf[0]->__rbp;
1635c48b108SAl Viro #endif
1645c48b108SAl Viro default:
1655c48b108SAl Viro printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
1665c48b108SAl Viro reg);
1675c48b108SAl Viro return 0;
1685c48b108SAl Viro }
1695c48b108SAl Viro }
170