1/*
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/types.h>
31#ifdef CROSS_DEBUGGER
32#include <sys/ia64/include/_regset.h>
33#include <sys/ia64/include/frame.h>
34#include <sys/ia64/include/md_var.h>
35#include <sys/ia64/include/pcb.h>
36#else
37#include <machine/frame.h>
38#include <machine/md_var.h>
39#include <machine/pcb.h>
40#endif
41#include <err.h>
42#include <kvm.h>
43#include <string.h>
44
45#include <defs.h>
46#include <target.h>
47#include <gdbthread.h>
48#include <inferior.h>
49#include <regcache.h>
50#include <frame-unwind.h>
51#include <ia64-tdep.h>
52
53#include "kgdb.h"
54
55void
56kgdb_trgt_fetch_registers(int regno __unused)
57{
58	struct kthr *kt;
59	struct pcb pcb;
60	uint64_t r;
61
62	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
63	if (kt == NULL)
64		return;
65	if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
66		warnx("kvm_read: %s", kvm_geterr(kvm));
67		memset(&pcb, 0, sizeof(pcb));
68	}
69
70	/* Registers 0-127: general registers. */
71	supply_register(IA64_GR1_REGNUM, (char *)&pcb.pcb_special.gp);
72	supply_register(IA64_GR4_REGNUM, (char *)&pcb.pcb_preserved.gr4);
73	supply_register(IA64_GR5_REGNUM, (char *)&pcb.pcb_preserved.gr5);
74	supply_register(IA64_GR6_REGNUM, (char *)&pcb.pcb_preserved.gr6);
75	supply_register(IA64_GR7_REGNUM, (char *)&pcb.pcb_preserved.gr7);
76	supply_register(IA64_GR12_REGNUM, (char *)&pcb.pcb_special.sp);
77	supply_register(IA64_GR12_REGNUM+1, (char *)&pcb.pcb_special.tp);
78
79	/* Registers 128-255: floating-point registers. */
80	supply_register(IA64_FR2_REGNUM, (char *)&pcb.pcb_preserved_fp.fr2);
81	supply_register(IA64_FR2_REGNUM+1, (char *)&pcb.pcb_preserved_fp.fr3);
82	supply_register(IA64_FR2_REGNUM+2, (char *)&pcb.pcb_preserved_fp.fr4);
83	supply_register(IA64_FR2_REGNUM+3, (char *)&pcb.pcb_preserved_fp.fr5);
84	supply_register(IA64_FR16_REGNUM, (char *)&pcb.pcb_preserved_fp.fr16);
85	supply_register(IA64_FR16_REGNUM+1, (char*)&pcb.pcb_preserved_fp.fr17);
86	supply_register(IA64_FR16_REGNUM+2, (char*)&pcb.pcb_preserved_fp.fr18);
87	supply_register(IA64_FR16_REGNUM+3, (char*)&pcb.pcb_preserved_fp.fr19);
88	supply_register(IA64_FR16_REGNUM+4, (char*)&pcb.pcb_preserved_fp.fr20);
89	supply_register(IA64_FR16_REGNUM+5, (char*)&pcb.pcb_preserved_fp.fr21);
90	supply_register(IA64_FR16_REGNUM+6, (char*)&pcb.pcb_preserved_fp.fr22);
91	supply_register(IA64_FR16_REGNUM+7, (char*)&pcb.pcb_preserved_fp.fr23);
92	supply_register(IA64_FR16_REGNUM+8, (char*)&pcb.pcb_preserved_fp.fr24);
93	supply_register(IA64_FR16_REGNUM+9, (char*)&pcb.pcb_preserved_fp.fr25);
94	supply_register(IA64_FR16_REGNUM+10,(char*)&pcb.pcb_preserved_fp.fr26);
95	supply_register(IA64_FR16_REGNUM+11,(char*)&pcb.pcb_preserved_fp.fr27);
96	supply_register(IA64_FR16_REGNUM+12,(char*)&pcb.pcb_preserved_fp.fr28);
97	supply_register(IA64_FR16_REGNUM+13,(char*)&pcb.pcb_preserved_fp.fr29);
98	supply_register(IA64_FR16_REGNUM+14,(char*)&pcb.pcb_preserved_fp.fr30);
99	supply_register(IA64_FR16_REGNUM+15,(char*)&pcb.pcb_preserved_fp.fr31);
100
101	/* Registers 320-327: branch registers. */
102	if (pcb.pcb_special.__spare == ~0UL)
103		supply_register(IA64_BR0_REGNUM, (char *)&pcb.pcb_special.rp);
104	supply_register(IA64_BR1_REGNUM, (char *)&pcb.pcb_preserved.br1);
105	supply_register(IA64_BR2_REGNUM, (char *)&pcb.pcb_preserved.br2);
106	supply_register(IA64_BR3_REGNUM, (char *)&pcb.pcb_preserved.br3);
107	supply_register(IA64_BR4_REGNUM, (char *)&pcb.pcb_preserved.br4);
108	supply_register(IA64_BR5_REGNUM, (char *)&pcb.pcb_preserved.br5);
109
110	/* Registers 328-333: misc. other registers. */
111	supply_register(IA64_PR_REGNUM, (char *)&pcb.pcb_special.pr);
112	if (pcb.pcb_special.__spare == ~0UL) {
113		r = pcb.pcb_special.iip + ((pcb.pcb_special.psr >> 41) & 3);
114		supply_register(IA64_IP_REGNUM, (char *)&r);
115		supply_register(IA64_CFM_REGNUM, (char *)&pcb.pcb_special.cfm);
116	} else {
117		supply_register(IA64_IP_REGNUM, (char *)&pcb.pcb_special.rp);
118		supply_register(IA64_CFM_REGNUM, (char *)&pcb.pcb_special.pfs);
119	}
120
121	/* Registers 334-461: application registers. */
122	supply_register(IA64_RSC_REGNUM, (char *)&pcb.pcb_special.rsc);
123	r = pcb.pcb_special.bspstore;
124	if (pcb.pcb_special.__spare == ~0UL)
125		r += pcb.pcb_special.ndirty;
126	else
127		r = ia64_bsp_adjust(r, IA64_CFM_SOF(pcb.pcb_special.pfs) -
128		    IA64_CFM_SOL(pcb.pcb_special.pfs));
129	supply_register(IA64_BSP_REGNUM, (char *)&r);
130	supply_register(IA64_BSPSTORE_REGNUM, (char *)&r);
131	supply_register(IA64_RNAT_REGNUM, (char *)&pcb.pcb_special.rnat);
132	supply_register(IA64_UNAT_REGNUM, (char *)&pcb.pcb_special.unat);
133	supply_register(IA64_FPSR_REGNUM, (char *)&pcb.pcb_special.fpsr);
134	if (pcb.pcb_special.__spare == ~0UL)
135		supply_register(IA64_PFS_REGNUM, (char *)&pcb.pcb_special.pfs);
136	supply_register(IA64_LC_REGNUM, (char *)&pcb.pcb_preserved.lc);
137}
138
139void
140kgdb_trgt_store_registers(int regno __unused)
141{
142	fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
143}
144
145void
146kgdb_trgt_new_objfile(struct objfile *objfile)
147{
148}
149
150struct kgdb_frame_cache {
151	CORE_ADDR	bsp;
152	CORE_ADDR	ip;
153	CORE_ADDR	sp;
154	CORE_ADDR	saved_bsp;
155};
156
157#define	SPECIAL(x)	offsetof(struct trapframe, tf_special)		\
158			+ offsetof(struct _special, x)
159#define	SCRATCH(x)	offsetof(struct trapframe, tf_scratch)		\
160			+ offsetof(struct _caller_saved, x)
161#define	SCRATCH_FP(x)	offsetof(struct trapframe, tf_scratch_fp)	\
162			+ offsetof(struct _caller_saved_fp, x)
163
164static int kgdb_trgt_frame_ofs_gr[32] = {
165	-1,					/* gr0 */
166	SPECIAL(gp),
167	SCRATCH(gr2),   SCRATCH(gr3),
168	-1, -1, -1, -1,				/* gr4-gr7 */
169	SCRATCH(gr8),   SCRATCH(gr9),   SCRATCH(gr10),  SCRATCH(gr11),
170	SPECIAL(sp),    SPECIAL(tp),
171	SCRATCH(gr14),  SCRATCH(gr15),  SCRATCH(gr16),  SCRATCH(gr17),
172	SCRATCH(gr18),  SCRATCH(gr19),  SCRATCH(gr20),  SCRATCH(gr21),
173	SCRATCH(gr22),  SCRATCH(gr23),  SCRATCH(gr24),  SCRATCH(gr25),
174	SCRATCH(gr26),  SCRATCH(gr27),  SCRATCH(gr28),  SCRATCH(gr29),
175	SCRATCH(gr30),  SCRATCH(gr31)
176};
177
178static int kgdb_trgt_frame_ofs_fr[32] = {
179	-1,					/* fr0: constant 0.0 */
180	-1,					/* fr1: constant 1.0 */
181	-1, -1, -1, -1,				/* fr2-fr5 */
182	SCRATCH_FP(fr6), SCRATCH_FP(fr7), SCRATCH_FP(fr8), SCRATCH_FP(fr9),
183	SCRATCH_FP(fr10), SCRATCH_FP(fr11), SCRATCH_FP(fr12), SCRATCH_FP(fr13),
184	SCRATCH_FP(fr14), SCRATCH_FP(fr15)
185};
186
187static int kgdb_trgt_frame_ofs_br[8] = {
188        SPECIAL(rp),
189	-1, -1, -1, -1, -1,			/* br1-br5 */
190	SCRATCH(br6), SCRATCH(br7)
191};
192
193static int kgdb_trgt_frame_ofs_ar[49] = {
194	/* ar0-ar15 */
195	SPECIAL(rsc),
196	-1,					/* ar.bsp */
197	SPECIAL(bspstore), SPECIAL(rnat),
198	-1, -1, -1, -1, -1,			/* ar20-ar24 */
199	SCRATCH(csd), SCRATCH(ssd),
200	-1, -1, -1, -1, -1,			/* ar27-ar31 */
201	SCRATCH(ccv),
202	-1, -1, -1,				/* ar33-ar35 */
203	SPECIAL(unat),
204	-1, -1, -1,				/* ar37-ar39 */
205	SPECIAL(fpsr),
206	-1, -1, -1, -1, -1, -1, -1,		/* ar41-ar47 */
207	-1, -1, -1, -1, -1, -1, -1, -1,		/* ar48-ar55 */
208	-1, -1, -1, -1, -1, -1, -1, -1,		/* ar56-ar63 */
209	SPECIAL(pfs)
210};
211
212static struct kgdb_frame_cache *
213kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
214{
215	char buf[MAX_REGISTER_SIZE];
216	struct kgdb_frame_cache *cache;
217
218	cache = *this_cache;
219	if (cache == NULL) {
220		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
221		*this_cache = cache;
222		frame_unwind_register(next_frame, IA64_BSP_REGNUM, buf);
223		cache->bsp = extract_unsigned_integer(buf,
224		    register_size(current_gdbarch, IA64_BSP_REGNUM));
225		cache->ip = frame_func_unwind(next_frame);
226		frame_unwind_register(next_frame, SP_REGNUM, buf);
227		cache->sp = extract_unsigned_integer(buf,
228		    register_size(current_gdbarch, SP_REGNUM));
229	}
230	return (cache);
231}
232
233static void
234kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
235    struct frame_id *this_id)
236{
237	struct kgdb_frame_cache *cache;
238
239	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
240	*this_id = frame_id_build_special(cache->sp, cache->ip, cache->bsp);
241}
242
243static void
244kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
245    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
246    CORE_ADDR *addrp, int *realnump, void *valuep)
247{
248	char buf[MAX_REGISTER_SIZE];
249	char dummy_valuep[MAX_REGISTER_SIZE];
250	struct kgdb_frame_cache *cache;
251	CORE_ADDR bsp;
252	int ofs, regsz;
253
254	regsz = register_size(current_gdbarch, regnum);
255
256	if (valuep == NULL)
257		valuep = dummy_valuep;
258	memset(valuep, 0, regsz);
259	*optimizedp = 0;
260	*addrp = 0;
261	*lvalp = not_lval;
262	*realnump = -1;
263
264	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
265
266	if (regnum == IA64_BSP_REGNUM) {
267		if (cache->saved_bsp == 0) {
268			target_read_memory(cache->sp + 16 + SPECIAL(bspstore),
269			    buf, regsz);
270			bsp = extract_unsigned_integer(buf, regsz);
271			target_read_memory(cache->sp + 16 + SPECIAL(ndirty),
272			    buf, regsz);
273			bsp += extract_unsigned_integer(buf, regsz);
274			cache->saved_bsp = bsp;
275		}
276		store_unsigned_integer(valuep, regsz, cache->saved_bsp);
277		return;
278	}
279	if (regnum == IA64_PR_REGNUM)
280		ofs = SPECIAL(pr);
281	else if (regnum == IA64_IP_REGNUM)
282		ofs = SPECIAL(iip);
283	else if (regnum == IA64_PSR_REGNUM)
284		ofs = SPECIAL(psr);
285	else if (regnum == IA64_CFM_REGNUM)
286		ofs = SPECIAL(cfm);
287	else if (regnum >= IA64_GR0_REGNUM && regnum <= IA64_GR31_REGNUM)
288		ofs = kgdb_trgt_frame_ofs_gr[regnum - IA64_GR0_REGNUM];
289	else if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR15_REGNUM)
290		ofs = kgdb_trgt_frame_ofs_fr[regnum - IA64_FR0_REGNUM];
291	else if (regnum >= IA64_BR0_REGNUM && regnum <= IA64_BR7_REGNUM)
292		ofs = kgdb_trgt_frame_ofs_br[regnum - IA64_BR0_REGNUM];
293	else if (regnum >= IA64_RSC_REGNUM && regnum <= IA64_PFS_REGNUM)
294		ofs = kgdb_trgt_frame_ofs_ar[regnum - IA64_RSC_REGNUM];
295	else
296		ofs = -1;
297	if (ofs == -1)
298		return;
299
300	*addrp = cache->sp + 16 + ofs;
301	*lvalp = lval_memory;
302	target_read_memory(*addrp, valuep, regsz);
303}
304
305static const struct frame_unwind kgdb_trgt_trapframe_unwind = {
306        UNKNOWN_FRAME,
307        &kgdb_trgt_trapframe_this_id,
308        &kgdb_trgt_trapframe_prev_register
309};
310
311const struct frame_unwind *
312kgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
313{
314	char *pname;
315	CORE_ADDR ip;
316
317	ip = frame_func_unwind(next_frame);
318	pname = NULL;
319	find_pc_partial_function(ip, &pname, NULL, NULL);
320	if (pname == NULL)
321		return (NULL);
322	if (strncmp(pname, "ivt_", 4) == 0)
323		return (&kgdb_trgt_trapframe_unwind);
324	/* printf("%s: %lx =%s\n", __func__, ip, pname); */
325	return (NULL);
326}
327