1204335Sjkim/* GNU/FreeBSD/amd64 specific low level interface, for the remote server for GDB.
2204335Sjkim   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
3204335Sjkim   Free Software Foundation, Inc.
4204335Sjkim
5204335Sjkim   This file is part of GDB.
6204335Sjkim
7204335Sjkim   This program is free software; you can redistribute it and/or modify
8204335Sjkim   it under the terms of the GNU General Public License as published by
9204335Sjkim   the Free Software Foundation; either version 2 of the License, or
10204335Sjkim   (at your option) any later version.
11204335Sjkim
12204335Sjkim   This program is distributed in the hope that it will be useful,
13204335Sjkim   but WITHOUT ANY WARRANTY; without even the implied warranty of
14204335Sjkim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15204335Sjkim   GNU General Public License for more details.
16204335Sjkim
17204335Sjkim   You should have received a copy of the GNU General Public License
18204335Sjkim   along with this program; if not, write to the Free Software
19204335Sjkim   Foundation, Inc., 59 Temple Place - Suite 330,
20204335Sjkim   Boston, MA 02111-1307, USA.  */
21204335Sjkim
22204335Sjkim#include <sys/cdefs.h>
23204335Sjkim__FBSDID("$FreeBSD$");
24204335Sjkim
25204335Sjkim#include "server.h"
26204335Sjkim#include "fbsd-low.h"
27204335Sjkim#include "i387-fp.h"
28204335Sjkim
29204335Sjkim#include <sys/stddef.h>
30204335Sjkim#include <sys/types.h>
31204335Sjkim#include <sys/ptrace.h>
32204335Sjkim#include <machine/reg.h>
33204335Sjkim
34204335Sjkim/* Mapping between the general-purpose registers in `struct user'
35204335Sjkim   format and GDB's register array layout.  */
36204335Sjkimstatic int amd64_regmap[] = {
37204335Sjkim	offsetof(struct reg, r_rax),
38204335Sjkim	offsetof(struct reg, r_rbx),
39204335Sjkim	offsetof(struct reg, r_rcx),
40204335Sjkim	offsetof(struct reg, r_rdx),
41204335Sjkim	offsetof(struct reg, r_rsi),
42204335Sjkim	offsetof(struct reg, r_rdi),
43204335Sjkim	offsetof(struct reg, r_rbp),
44204335Sjkim	offsetof(struct reg, r_rsp),
45204335Sjkim	offsetof(struct reg, r_r8),
46204335Sjkim	offsetof(struct reg, r_r9),
47204335Sjkim	offsetof(struct reg, r_r10),
48204335Sjkim	offsetof(struct reg, r_r11),
49204335Sjkim	offsetof(struct reg, r_r12),
50204335Sjkim	offsetof(struct reg, r_r13),
51204335Sjkim	offsetof(struct reg, r_r14),
52204335Sjkim	offsetof(struct reg, r_r15),
53204335Sjkim	offsetof(struct reg, r_rip),
54204335Sjkim	offsetof(struct reg, r_rflags),	/* XXX 64-bit */
55204335Sjkim	offsetof(struct reg, r_cs),
56204335Sjkim	offsetof(struct reg, r_ss),
57204335Sjkim	offsetof(struct reg, r_ds),
58204335Sjkim	offsetof(struct reg, r_es),
59204335Sjkim	offsetof(struct reg, r_fs),
60204335Sjkim	offsetof(struct reg, r_gs),
61204335Sjkim};
62204335Sjkim#define	AMD64_NUM_REGS	(sizeof(amd64_regmap) / sizeof(amd64_regmap[0]))
63204335Sjkim
64204335Sjkimstatic const char amd64_breakpoint[] = { 0xCC };
65204335Sjkim#define	AMD64_BP_LEN	1
66204335Sjkim
67204335Sjkimextern int debug_threads;
68204335Sjkim
69204335Sjkimstatic int
70204335Sjkimamd64_cannot_store_register(int regno)
71204335Sjkim{
72204335Sjkim
73204335Sjkim	return (regno >= AMD64_NUM_REGS);
74204335Sjkim}
75204335Sjkim
76204335Sjkimstatic int
77204335Sjkimamd64_cannot_fetch_register(int regno)
78204335Sjkim{
79204335Sjkim
80204335Sjkim	return (regno >= AMD64_NUM_REGS);
81204335Sjkim}
82204335Sjkim
83204335Sjkimstatic void
84204335Sjkimamd64_fill_gregset(void *buf)
85204335Sjkim{
86204335Sjkim	int i;
87204335Sjkim
88204335Sjkim	for (i = 0; i < AMD64_NUM_REGS; i++)
89204335Sjkim		collect_register(i, ((char *)buf) + amd64_regmap[i]);
90204335Sjkim}
91204335Sjkim
92204335Sjkimstatic void
93204335Sjkimamd64_store_gregset(const void *buf)
94204335Sjkim{
95204335Sjkim	int i;
96204335Sjkim
97204335Sjkim	for (i = 0; i < AMD64_NUM_REGS; i++)
98204335Sjkim		supply_register(i, ((char *)buf) + amd64_regmap[i]);
99204335Sjkim}
100204335Sjkim
101204335Sjkimstatic void
102204335Sjkimamd64_fill_fpregset(void *buf)
103204335Sjkim{
104204335Sjkim
105204335Sjkim	i387_cache_to_fsave(buf);
106204335Sjkim}
107204335Sjkim
108204335Sjkimstatic void
109204335Sjkimamd64_store_fpregset(const void *buf)
110204335Sjkim{
111204335Sjkim
112204335Sjkim	i387_fsave_to_cache(buf);
113204335Sjkim}
114204335Sjkim
115204335Sjkimstatic void
116204335Sjkimamd64_fill_fpxregset(void *buf)
117204335Sjkim{
118204335Sjkim
119204335Sjkim	i387_cache_to_fxsave(buf);
120204335Sjkim}
121204335Sjkim
122204335Sjkimstatic void
123204335Sjkimamd64_store_fpxregset(const void *buf)
124204335Sjkim{
125204335Sjkim
126204335Sjkim	i387_fxsave_to_cache(buf);
127204335Sjkim}
128204335Sjkim
129204335Sjkim
130204335Sjkimstruct regset_info target_regsets[] = {
131204335Sjkim	{
132204335Sjkim		PT_GETREGS,
133204335Sjkim		PT_SETREGS,
134204335Sjkim		sizeof(struct reg),
135204335Sjkim		GENERAL_REGS,
136204335Sjkim		amd64_fill_gregset,
137204335Sjkim		amd64_store_gregset,
138204335Sjkim	},
139204335Sjkim#ifdef HAVE_PTRACE_GETFPXREGS
140204335Sjkim	{
141204335Sjkim		PTRACE_GETFPXREGS,
142204335Sjkim		PTRACE_SETFPXREGS,
143204335Sjkim		sizeof(elf_fpxregset_t),
144204335Sjkim		EXTENDED_REGS,
145204335Sjkim		amd64_fill_fpxregset,
146204335Sjkim		amd64_store_fpxregset,
147204335Sjkim	},
148204335Sjkim#endif
149204335Sjkim	{
150204335Sjkim		PT_GETFPREGS,
151204335Sjkim		PT_SETFPREGS,
152204335Sjkim		sizeof(struct fpreg),
153204335Sjkim		FP_REGS,
154204335Sjkim		amd64_fill_fpregset,
155204335Sjkim		amd64_store_fpregset,
156204335Sjkim	},
157204335Sjkim	{
158204335Sjkim		0,
159204335Sjkim		0,
160204335Sjkim		-1,
161204335Sjkim		-1,
162204335Sjkim		NULL,
163204335Sjkim		NULL,
164204335Sjkim	}
165204335Sjkim};
166204335Sjkim
167204335Sjkimstatic CORE_ADDR
168204335Sjkimamd64_get_pc(void)
169204335Sjkim{
170204335Sjkim	unsigned long pc;
171204335Sjkim
172204335Sjkim	collect_register_by_name("rip", &pc);
173204335Sjkim
174204335Sjkim	if (debug_threads)
175204335Sjkim		fprintf(stderr, "stop pc (before any decrement) is %016lx\n", pc);
176204335Sjkim
177204335Sjkim	return (pc);
178204335Sjkim}
179204335Sjkim
180204335Sjkimstatic void
181204335Sjkimamd64_set_pc(CORE_ADDR newpc)
182204335Sjkim{
183204335Sjkim
184204335Sjkim	if (debug_threads)
185204335Sjkim		fprintf(stderr, "set pc to %016lx\n", (long)newpc);
186204335Sjkim	supply_register_by_name("rip", &newpc);
187204335Sjkim}
188204335Sjkim
189204335Sjkimstatic int
190204335Sjkimamd64_breakpoint_at(CORE_ADDR pc)
191204335Sjkim{
192204335Sjkim	unsigned char c;
193204335Sjkim
194204335Sjkim	read_inferior_memory(pc, &c, 1);
195204335Sjkim	if (c == 0xCC)
196204335Sjkim		return (1);
197204335Sjkim
198204335Sjkim	return (0);
199204335Sjkim}
200204335Sjkim
201204335Sjkimstruct fbsd_target_ops the_low_target = {
202204335Sjkim	AMD64_NUM_REGS,
203204335Sjkim	amd64_regmap,
204204335Sjkim	amd64_cannot_fetch_register,
205204335Sjkim	amd64_cannot_store_register,
206204335Sjkim	amd64_get_pc,
207204335Sjkim	amd64_set_pc,
208204335Sjkim	amd64_breakpoint,
209204335Sjkim	AMD64_BP_LEN,
210204335Sjkim	NULL,
211204335Sjkim	1,
212204335Sjkim	amd64_breakpoint_at,
213204335Sjkim};
214