xref: /linux/arch/x86/um/os-Linux/registers.c (revision ad73b9a17d66366d8c9198bc90f1ea99f24a912c)
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>
18dbba7f70SAl Viro #include <registers.h>
193f17fed2SBenjamin Berg #include <sys/mman.h>
205c48b108SAl Viro 
21*5298b7cfSBenjamin Berg static unsigned long ptrace_regset;
223f17fed2SBenjamin Berg unsigned long host_fp_size;
23a78ff111SEli Cooper 
get_fp_registers(int pid,unsigned long * regs)243f17fed2SBenjamin Berg int get_fp_registers(int pid, unsigned long *regs)
255c48b108SAl Viro {
263f17fed2SBenjamin Berg 	struct iovec iov = {
273f17fed2SBenjamin Berg 		.iov_base = regs,
283f17fed2SBenjamin Berg 		.iov_len = host_fp_size,
293f17fed2SBenjamin Berg 	};
305c48b108SAl Viro 
31*5298b7cfSBenjamin Berg 	if (ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov) < 0)
32a78ff111SEli Cooper 		return -errno;
33a78ff111SEli Cooper 	return 0;
34a78ff111SEli Cooper }
35a78ff111SEli Cooper 
put_fp_registers(int pid,unsigned long * regs)363f17fed2SBenjamin Berg int put_fp_registers(int pid, unsigned long *regs)
375c48b108SAl Viro {
383f17fed2SBenjamin Berg 	struct iovec iov = {
393f17fed2SBenjamin Berg 		.iov_base = regs,
403f17fed2SBenjamin Berg 		.iov_len = host_fp_size,
413f17fed2SBenjamin Berg 	};
425c48b108SAl Viro 
43*5298b7cfSBenjamin Berg 	if (ptrace(PTRACE_SETREGSET, pid, ptrace_regset, &iov) < 0)
44a78ff111SEli Cooper 		return -errno;
45a78ff111SEli Cooper 	return 0;
46a78ff111SEli Cooper }
47a78ff111SEli Cooper 
arch_init_registers(int pid)483f17fed2SBenjamin Berg int arch_init_registers(int pid)
495c48b108SAl Viro {
503f17fed2SBenjamin Berg 	struct iovec iov = {
513f17fed2SBenjamin Berg 		/* Just use plenty of space, it does not cost us anything */
523f17fed2SBenjamin Berg 		.iov_len = 2 * 1024 * 1024,
533f17fed2SBenjamin Berg 	};
543f17fed2SBenjamin Berg 	int ret;
553f17fed2SBenjamin Berg 
563f17fed2SBenjamin Berg 	iov.iov_base = mmap(NULL, iov.iov_len, PROT_WRITE | PROT_READ,
573f17fed2SBenjamin Berg 			    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
583f17fed2SBenjamin Berg 	if (iov.iov_base == MAP_FAILED)
593f17fed2SBenjamin Berg 		return -ENOMEM;
603f17fed2SBenjamin Berg 
613f17fed2SBenjamin Berg 	/* GDB has x86_xsave_length, which uses x86_cpuid_count */
62*5298b7cfSBenjamin Berg 	ptrace_regset = NT_X86_XSTATE;
63*5298b7cfSBenjamin Berg 	ret = ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov);
643f17fed2SBenjamin Berg 	if (ret)
653f17fed2SBenjamin Berg 		ret = -errno;
66*5298b7cfSBenjamin Berg 
67*5298b7cfSBenjamin Berg 	if (ret == -ENODEV) {
68*5298b7cfSBenjamin Berg #ifdef CONFIG_X86_32
69*5298b7cfSBenjamin Berg 		ptrace_regset = NT_PRXFPREG;
70*5298b7cfSBenjamin Berg #else
71*5298b7cfSBenjamin Berg 		ptrace_regset = NT_PRFPREG;
72*5298b7cfSBenjamin Berg #endif
73*5298b7cfSBenjamin Berg 		iov.iov_len = 2 * 1024 * 1024;
74*5298b7cfSBenjamin Berg 		ret = ptrace(PTRACE_GETREGSET, pid, ptrace_regset, &iov);
75*5298b7cfSBenjamin Berg 		if (ret)
76*5298b7cfSBenjamin Berg 			ret = -errno;
77*5298b7cfSBenjamin Berg 	}
78*5298b7cfSBenjamin Berg 
793f17fed2SBenjamin Berg 	munmap(iov.iov_base, 2 * 1024 * 1024);
803f17fed2SBenjamin Berg 
813f17fed2SBenjamin Berg 	host_fp_size = iov.iov_len;
823f17fed2SBenjamin Berg 
833f17fed2SBenjamin Berg 	return ret;
845c48b108SAl Viro }
855c48b108SAl Viro 
get_thread_reg(int reg,jmp_buf * buf)865c48b108SAl Viro unsigned long get_thread_reg(int reg, jmp_buf *buf)
875c48b108SAl Viro {
885c48b108SAl Viro 	switch (reg) {
895c48b108SAl Viro #ifdef __i386__
90a10c95d8SAl Viro 	case HOST_IP:
915c48b108SAl Viro 		return buf[0]->__eip;
92a10c95d8SAl Viro 	case HOST_SP:
935c48b108SAl Viro 		return buf[0]->__esp;
94a10c95d8SAl Viro 	case HOST_BP:
955c48b108SAl Viro 		return buf[0]->__ebp;
965c48b108SAl Viro #else
97a10c95d8SAl Viro 	case HOST_IP:
985c48b108SAl Viro 		return buf[0]->__rip;
99a10c95d8SAl Viro 	case HOST_SP:
1005c48b108SAl Viro 		return buf[0]->__rsp;
101a10c95d8SAl Viro 	case HOST_BP:
1025c48b108SAl Viro 		return buf[0]->__rbp;
1035c48b108SAl Viro #endif
1045c48b108SAl Viro 	default:
1055c48b108SAl Viro 		printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
1065c48b108SAl Viro 		       reg);
1075c48b108SAl Viro 		return 0;
1085c48b108SAl Viro 	}
1095c48b108SAl Viro }
110