162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2004 PathScale, Inc
362306a36Sopenharmony_ci * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci * Licensed under the GPL
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <errno.h>
862306a36Sopenharmony_ci#include <stdlib.h>
962306a36Sopenharmony_ci#include <sys/ptrace.h>
1062306a36Sopenharmony_ci#ifdef __i386__
1162306a36Sopenharmony_ci#include <sys/user.h>
1262306a36Sopenharmony_ci#endif
1362306a36Sopenharmony_ci#include <longjmp.h>
1462306a36Sopenharmony_ci#include <sysdep/ptrace_user.h>
1562306a36Sopenharmony_ci#include <sys/uio.h>
1662306a36Sopenharmony_ci#include <asm/sigcontext.h>
1762306a36Sopenharmony_ci#include <linux/elf.h>
1862306a36Sopenharmony_ci#include <registers.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciint have_xstate_support;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciint save_i387_registers(int pid, unsigned long *fp_regs)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
2562306a36Sopenharmony_ci		return -errno;
2662306a36Sopenharmony_ci	return 0;
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciint save_fp_registers(int pid, unsigned long *fp_regs)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci#ifdef PTRACE_GETREGSET
3262306a36Sopenharmony_ci	struct iovec iov;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (have_xstate_support) {
3562306a36Sopenharmony_ci		iov.iov_base = fp_regs;
3662306a36Sopenharmony_ci		iov.iov_len = FP_SIZE * sizeof(unsigned long);
3762306a36Sopenharmony_ci		if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
3862306a36Sopenharmony_ci			return -errno;
3962306a36Sopenharmony_ci		return 0;
4062306a36Sopenharmony_ci	} else
4162306a36Sopenharmony_ci#endif
4262306a36Sopenharmony_ci		return save_i387_registers(pid, fp_regs);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint restore_i387_registers(int pid, unsigned long *fp_regs)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
4862306a36Sopenharmony_ci		return -errno;
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint restore_fp_registers(int pid, unsigned long *fp_regs)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci#ifdef PTRACE_SETREGSET
5562306a36Sopenharmony_ci	struct iovec iov;
5662306a36Sopenharmony_ci	if (have_xstate_support) {
5762306a36Sopenharmony_ci		iov.iov_base = fp_regs;
5862306a36Sopenharmony_ci		iov.iov_len = FP_SIZE * sizeof(unsigned long);
5962306a36Sopenharmony_ci		if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
6062306a36Sopenharmony_ci			return -errno;
6162306a36Sopenharmony_ci		return 0;
6262306a36Sopenharmony_ci	} else
6362306a36Sopenharmony_ci#endif
6462306a36Sopenharmony_ci		return restore_i387_registers(pid, fp_regs);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#ifdef __i386__
6862306a36Sopenharmony_ciint have_fpx_regs = 1;
6962306a36Sopenharmony_ciint save_fpx_registers(int pid, unsigned long *fp_regs)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0)
7262306a36Sopenharmony_ci		return -errno;
7362306a36Sopenharmony_ci	return 0;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciint restore_fpx_registers(int pid, unsigned long *fp_regs)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0)
7962306a36Sopenharmony_ci		return -errno;
8062306a36Sopenharmony_ci	return 0;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	if (have_fpx_regs)
8662306a36Sopenharmony_ci		return save_fpx_registers(pid, regs);
8762306a36Sopenharmony_ci	else
8862306a36Sopenharmony_ci		return save_fp_registers(pid, regs);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	if (have_fpx_regs)
9462306a36Sopenharmony_ci		return restore_fpx_registers(pid, regs);
9562306a36Sopenharmony_ci	else
9662306a36Sopenharmony_ci		return restore_fp_registers(pid, regs);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid arch_init_registers(int pid)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct user_fpxregs_struct fpx_regs;
10262306a36Sopenharmony_ci	int err;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
10562306a36Sopenharmony_ci	if (!err)
10662306a36Sopenharmony_ci		return;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (errno != EIO)
10962306a36Sopenharmony_ci		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
11062306a36Sopenharmony_ci		      errno);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	have_fpx_regs = 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci#else
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint get_fp_registers(int pid, unsigned long *regs)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return save_fp_registers(pid, regs);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciint put_fp_registers(int pid, unsigned long *regs)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return restore_fp_registers(pid, regs);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_civoid arch_init_registers(int pid)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci#ifdef PTRACE_GETREGSET
12962306a36Sopenharmony_ci	void * fp_regs;
13062306a36Sopenharmony_ci	struct iovec iov;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	fp_regs = malloc(FP_SIZE * sizeof(unsigned long));
13362306a36Sopenharmony_ci	if(fp_regs == NULL)
13462306a36Sopenharmony_ci		return;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	iov.iov_base = fp_regs;
13762306a36Sopenharmony_ci	iov.iov_len = FP_SIZE * sizeof(unsigned long);
13862306a36Sopenharmony_ci	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
13962306a36Sopenharmony_ci		have_xstate_support = 1;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	free(fp_regs);
14262306a36Sopenharmony_ci#endif
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci#endif
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciunsigned long get_thread_reg(int reg, jmp_buf *buf)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	switch (reg) {
14962306a36Sopenharmony_ci#ifdef __i386__
15062306a36Sopenharmony_ci	case HOST_IP:
15162306a36Sopenharmony_ci		return buf[0]->__eip;
15262306a36Sopenharmony_ci	case HOST_SP:
15362306a36Sopenharmony_ci		return buf[0]->__esp;
15462306a36Sopenharmony_ci	case HOST_BP:
15562306a36Sopenharmony_ci		return buf[0]->__ebp;
15662306a36Sopenharmony_ci#else
15762306a36Sopenharmony_ci	case HOST_IP:
15862306a36Sopenharmony_ci		return buf[0]->__rip;
15962306a36Sopenharmony_ci	case HOST_SP:
16062306a36Sopenharmony_ci		return buf[0]->__rsp;
16162306a36Sopenharmony_ci	case HOST_BP:
16262306a36Sopenharmony_ci		return buf[0]->__rbp;
16362306a36Sopenharmony_ci#endif
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
16662306a36Sopenharmony_ci		       reg);
16762306a36Sopenharmony_ci		return 0;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci}
170