18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2004 PathScale, Inc
38c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
48c2ecf20Sopenharmony_ci * Licensed under the GPL
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <stdlib.h>
98c2ecf20Sopenharmony_ci#include <sys/ptrace.h>
108c2ecf20Sopenharmony_ci#ifdef __i386__
118c2ecf20Sopenharmony_ci#include <sys/user.h>
128c2ecf20Sopenharmony_ci#endif
138c2ecf20Sopenharmony_ci#include <longjmp.h>
148c2ecf20Sopenharmony_ci#include <sysdep/ptrace_user.h>
158c2ecf20Sopenharmony_ci#include <sys/uio.h>
168c2ecf20Sopenharmony_ci#include <asm/sigcontext.h>
178c2ecf20Sopenharmony_ci#include <linux/elf.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciint have_xstate_support;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciint save_i387_registers(int pid, unsigned long *fp_regs)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
248c2ecf20Sopenharmony_ci		return -errno;
258c2ecf20Sopenharmony_ci	return 0;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciint save_fp_registers(int pid, unsigned long *fp_regs)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci#ifdef PTRACE_GETREGSET
318c2ecf20Sopenharmony_ci	struct iovec iov;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (have_xstate_support) {
348c2ecf20Sopenharmony_ci		iov.iov_base = fp_regs;
358c2ecf20Sopenharmony_ci		iov.iov_len = FP_SIZE * sizeof(unsigned long);
368c2ecf20Sopenharmony_ci		if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
378c2ecf20Sopenharmony_ci			return -errno;
388c2ecf20Sopenharmony_ci		return 0;
398c2ecf20Sopenharmony_ci	} else
408c2ecf20Sopenharmony_ci#endif
418c2ecf20Sopenharmony_ci		return save_i387_registers(pid, fp_regs);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint restore_i387_registers(int pid, unsigned long *fp_regs)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
478c2ecf20Sopenharmony_ci		return -errno;
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint restore_fp_registers(int pid, unsigned long *fp_regs)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci#ifdef PTRACE_SETREGSET
548c2ecf20Sopenharmony_ci	struct iovec iov;
558c2ecf20Sopenharmony_ci	if (have_xstate_support) {
568c2ecf20Sopenharmony_ci		iov.iov_base = fp_regs;
578c2ecf20Sopenharmony_ci		iov.iov_len = FP_SIZE * sizeof(unsigned long);
588c2ecf20Sopenharmony_ci		if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
598c2ecf20Sopenharmony_ci			return -errno;
608c2ecf20Sopenharmony_ci		return 0;
618c2ecf20Sopenharmony_ci	} else
628c2ecf20Sopenharmony_ci#endif
638c2ecf20Sopenharmony_ci		return restore_i387_registers(pid, fp_regs);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#ifdef __i386__
678c2ecf20Sopenharmony_ciint have_fpx_regs = 1;
688c2ecf20Sopenharmony_ciint save_fpx_registers(int pid, unsigned long *fp_regs)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0)
718c2ecf20Sopenharmony_ci		return -errno;
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint restore_fpx_registers(int pid, unsigned long *fp_regs)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0)
788c2ecf20Sopenharmony_ci		return -errno;
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	if (have_fpx_regs)
858c2ecf20Sopenharmony_ci		return save_fpx_registers(pid, regs);
868c2ecf20Sopenharmony_ci	else
878c2ecf20Sopenharmony_ci		return save_fp_registers(pid, regs);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	if (have_fpx_regs)
938c2ecf20Sopenharmony_ci		return restore_fpx_registers(pid, regs);
948c2ecf20Sopenharmony_ci	else
958c2ecf20Sopenharmony_ci		return restore_fp_registers(pid, regs);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_civoid arch_init_registers(int pid)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct user_fpxregs_struct fpx_regs;
1018c2ecf20Sopenharmony_ci	int err;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
1048c2ecf20Sopenharmony_ci	if (!err)
1058c2ecf20Sopenharmony_ci		return;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (errno != EIO)
1088c2ecf20Sopenharmony_ci		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
1098c2ecf20Sopenharmony_ci		      errno);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	have_fpx_regs = 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci#else
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	return save_fp_registers(pid, regs);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return restore_fp_registers(pid, regs);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_civoid arch_init_registers(int pid)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci#ifdef PTRACE_GETREGSET
1288c2ecf20Sopenharmony_ci	void * fp_regs;
1298c2ecf20Sopenharmony_ci	struct iovec iov;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	fp_regs = malloc(FP_SIZE * sizeof(unsigned long));
1328c2ecf20Sopenharmony_ci	if(fp_regs == NULL)
1338c2ecf20Sopenharmony_ci		return;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	iov.iov_base = fp_regs;
1368c2ecf20Sopenharmony_ci	iov.iov_len = FP_SIZE * sizeof(unsigned long);
1378c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
1388c2ecf20Sopenharmony_ci		have_xstate_support = 1;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	free(fp_regs);
1418c2ecf20Sopenharmony_ci#endif
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci#endif
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciunsigned long get_thread_reg(int reg, jmp_buf *buf)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	switch (reg) {
1488c2ecf20Sopenharmony_ci#ifdef __i386__
1498c2ecf20Sopenharmony_ci	case HOST_IP:
1508c2ecf20Sopenharmony_ci		return buf[0]->__eip;
1518c2ecf20Sopenharmony_ci	case HOST_SP:
1528c2ecf20Sopenharmony_ci		return buf[0]->__esp;
1538c2ecf20Sopenharmony_ci	case HOST_BP:
1548c2ecf20Sopenharmony_ci		return buf[0]->__ebp;
1558c2ecf20Sopenharmony_ci#else
1568c2ecf20Sopenharmony_ci	case HOST_IP:
1578c2ecf20Sopenharmony_ci		return buf[0]->__rip;
1588c2ecf20Sopenharmony_ci	case HOST_SP:
1598c2ecf20Sopenharmony_ci		return buf[0]->__rsp;
1608c2ecf20Sopenharmony_ci	case HOST_BP:
1618c2ecf20Sopenharmony_ci		return buf[0]->__rbp;
1628c2ecf20Sopenharmony_ci#endif
1638c2ecf20Sopenharmony_ci	default:
1648c2ecf20Sopenharmony_ci		printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
1658c2ecf20Sopenharmony_ci		       reg);
1668c2ecf20Sopenharmony_ci		return 0;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
169