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
55CORE_ADDR
56kgdb_trgt_core_pcb(u_int cpuid)
57{
58	CORE_ADDR addr;
59	char *expr;
60
61	asprintf(&expr, "&cpuid_to_pcpu[%d]->pc_md.pcb", cpuid);
62	addr = kgdb_parse(expr);
63	free(expr);
64	return (addr);
65}
66
67void
68kgdb_trgt_fetch_registers(int regno __unused)
69{
70	struct kthr *kt;
71	struct pcb pcb;
72	uint64_t r;
73
74	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
75	if (kt == NULL)
76		return;
77	if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
78		warnx("kvm_read: %s", kvm_geterr(kvm));
79		memset(&pcb, 0, sizeof(pcb));
80	}
81
82	/* Registers 0-127: general registers. */
83	supply_register(IA64_GR1_REGNUM, (char *)&pcb.pcb_special.gp);
84	supply_register(IA64_GR4_REGNUM, (char *)&pcb.pcb_preserved.gr4);
85	supply_register(IA64_GR5_REGNUM, (char *)&pcb.pcb_preserved.gr5);
86	supply_register(IA64_GR6_REGNUM, (char *)&pcb.pcb_preserved.gr6);
87	supply_register(IA64_GR7_REGNUM, (char *)&pcb.pcb_preserved.gr7);
88	supply_register(IA64_GR12_REGNUM, (char *)&pcb.pcb_special.sp);
89	supply_register(IA64_GR12_REGNUM+1, (char *)&pcb.pcb_special.tp);
90
91	/* Registers 128-255: floating-point registers. */
92	supply_register(IA64_FR2_REGNUM, (char *)&pcb.pcb_preserved_fp.fr2);
93	supply_register(IA64_FR2_REGNUM+1, (char *)&pcb.pcb_preserved_fp.fr3);
94	supply_register(IA64_FR2_REGNUM+2, (char *)&pcb.pcb_preserved_fp.fr4);
95	supply_register(IA64_FR2_REGNUM+3, (char *)&pcb.pcb_preserved_fp.fr5);
96	supply_register(IA64_FR16_REGNUM, (char *)&pcb.pcb_preserved_fp.fr16);
97	supply_register(IA64_FR16_REGNUM+1, (char*)&pcb.pcb_preserved_fp.fr17);
98	supply_register(IA64_FR16_REGNUM+2, (char*)&pcb.pcb_preserved_fp.fr18);
99	supply_register(IA64_FR16_REGNUM+3, (char*)&pcb.pcb_preserved_fp.fr19);
100	supply_register(IA64_FR16_REGNUM+4, (char*)&pcb.pcb_preserved_fp.fr20);
101	supply_register(IA64_FR16_REGNUM+5, (char*)&pcb.pcb_preserved_fp.fr21);
102	supply_register(IA64_FR16_REGNUM+6, (char*)&pcb.pcb_preserved_fp.fr22);
103	supply_register(IA64_FR16_REGNUM+7, (char*)&pcb.pcb_preserved_fp.fr23);
104	supply_register(IA64_FR16_REGNUM+8, (char*)&pcb.pcb_preserved_fp.fr24);
105	supply_register(IA64_FR16_REGNUM+9, (char*)&pcb.pcb_preserved_fp.fr25);
106	supply_register(IA64_FR16_REGNUM+10,(char*)&pcb.pcb_preserved_fp.fr26);
107	supply_register(IA64_FR16_REGNUM+11,(char*)&pcb.pcb_preserved_fp.fr27);
108	supply_register(IA64_FR16_REGNUM+12,(char*)&pcb.pcb_preserved_fp.fr28);
109	supply_register(IA64_FR16_REGNUM+13,(char*)&pcb.pcb_preserved_fp.fr29);
110	supply_register(IA64_FR16_REGNUM+14,(char*)&pcb.pcb_preserved_fp.fr30);
111	supply_register(IA64_FR16_REGNUM+15,(char*)&pcb.pcb_preserved_fp.fr31);
112
113	/* Registers 320-327: branch registers. */
114	if (pcb.pcb_special.__spare == ~0UL)
115		supply_register(IA64_BR0_REGNUM, (char *)&pcb.pcb_special.rp);
116	supply_register(IA64_BR1_REGNUM, (char *)&pcb.pcb_preserved.br1);
117	supply_register(IA64_BR2_REGNUM, (char *)&pcb.pcb_preserved.br2);
118	supply_register(IA64_BR3_REGNUM, (char *)&pcb.pcb_preserved.br3);
119	supply_register(IA64_BR4_REGNUM, (char *)&pcb.pcb_preserved.br4);
120	supply_register(IA64_BR5_REGNUM, (char *)&pcb.pcb_preserved.br5);
121
122	/* Registers 328-333: misc. other registers. */
123	supply_register(IA64_PR_REGNUM, (char *)&pcb.pcb_special.pr);
124	if (pcb.pcb_special.__spare == ~0UL) {
125		r = pcb.pcb_special.iip + ((pcb.pcb_special.psr >> 41) & 3);
126		supply_register(IA64_IP_REGNUM, (char *)&r);
127		supply_register(IA64_CFM_REGNUM, (char *)&pcb.pcb_special.cfm);
128	} else {
129		supply_register(IA64_IP_REGNUM, (char *)&pcb.pcb_special.rp);
130		supply_register(IA64_CFM_REGNUM, (char *)&pcb.pcb_special.pfs);
131	}
132
133	/* Registers 334-461: application registers. */
134	supply_register(IA64_RSC_REGNUM, (char *)&pcb.pcb_special.rsc);
135	r = pcb.pcb_special.bspstore;
136	if (pcb.pcb_special.__spare == ~0UL)
137		r += pcb.pcb_special.ndirty;
138	else
139		r = ia64_bsp_adjust(r, IA64_CFM_SOF(pcb.pcb_special.pfs) -
140		    IA64_CFM_SOL(pcb.pcb_special.pfs));
141	supply_register(IA64_BSP_REGNUM, (char *)&r);
142	supply_register(IA64_BSPSTORE_REGNUM, (char *)&r);
143	supply_register(IA64_RNAT_REGNUM, (char *)&pcb.pcb_special.rnat);
144	supply_register(IA64_UNAT_REGNUM, (char *)&pcb.pcb_special.unat);
145	supply_register(IA64_FPSR_REGNUM, (char *)&pcb.pcb_special.fpsr);
146	if (pcb.pcb_special.__spare == ~0UL)
147		supply_register(IA64_PFS_REGNUM, (char *)&pcb.pcb_special.pfs);
148	supply_register(IA64_LC_REGNUM, (char *)&pcb.pcb_preserved.lc);
149}
150
151void
152kgdb_trgt_store_registers(int regno __unused)
153{
154	fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
155}
156
157void
158kgdb_trgt_new_objfile(struct objfile *objfile)
159{
160}
161
162struct kgdb_frame_cache {
163	CORE_ADDR	bsp;
164	CORE_ADDR	ip;
165	CORE_ADDR	sp;
166	CORE_ADDR	saved_bsp;
167};
168
169#define	SPECIAL(x)	offsetof(struct trapframe, tf_special)		\
170			+ offsetof(struct _special, x)
171#define	SCRATCH(x)	offsetof(struct trapframe, tf_scratch)		\
172			+ offsetof(struct _caller_saved, x)
173#define	SCRATCH_FP(x)	offsetof(struct trapframe, tf_scratch_fp)	\
174			+ offsetof(struct _caller_saved_fp, x)
175
176static int kgdb_trgt_frame_ofs_gr[32] = {
177	-1,					/* gr0 */
178	SPECIAL(gp),
179	SCRATCH(gr2),   SCRATCH(gr3),
180	-1, -1, -1, -1,				/* gr4-gr7 */
181	SCRATCH(gr8),   SCRATCH(gr9),   SCRATCH(gr10),  SCRATCH(gr11),
182	SPECIAL(sp),    SPECIAL(tp),
183	SCRATCH(gr14),  SCRATCH(gr15),  SCRATCH(gr16),  SCRATCH(gr17),
184	SCRATCH(gr18),  SCRATCH(gr19),  SCRATCH(gr20),  SCRATCH(gr21),
185	SCRATCH(gr22),  SCRATCH(gr23),  SCRATCH(gr24),  SCRATCH(gr25),
186	SCRATCH(gr26),  SCRATCH(gr27),  SCRATCH(gr28),  SCRATCH(gr29),
187	SCRATCH(gr30),  SCRATCH(gr31)
188};
189
190static int kgdb_trgt_frame_ofs_fr[32] = {
191	-1,					/* fr0: constant 0.0 */
192	-1,					/* fr1: constant 1.0 */
193	-1, -1, -1, -1,				/* fr2-fr5 */
194	SCRATCH_FP(fr6), SCRATCH_FP(fr7), SCRATCH_FP(fr8), SCRATCH_FP(fr9),
195	SCRATCH_FP(fr10), SCRATCH_FP(fr11), SCRATCH_FP(fr12), SCRATCH_FP(fr13),
196	SCRATCH_FP(fr14), SCRATCH_FP(fr15)
197};
198
199static int kgdb_trgt_frame_ofs_br[8] = {
200        SPECIAL(rp),
201	-1, -1, -1, -1, -1,			/* br1-br5 */
202	SCRATCH(br6), SCRATCH(br7)
203};
204
205static int kgdb_trgt_frame_ofs_ar[49] = {
206	/* ar0-ar15 */
207	SPECIAL(rsc),
208	-1,					/* ar.bsp */
209	SPECIAL(bspstore), SPECIAL(rnat),
210	-1, -1, -1, -1, -1,			/* ar20-ar24 */
211	SCRATCH(csd), SCRATCH(ssd),
212	-1, -1, -1, -1, -1,			/* ar27-ar31 */
213	SCRATCH(ccv),
214	-1, -1, -1,				/* ar33-ar35 */
215	SPECIAL(unat),
216	-1, -1, -1,				/* ar37-ar39 */
217	SPECIAL(fpsr),
218	-1, -1, -1, -1, -1, -1, -1,		/* ar41-ar47 */
219	-1, -1, -1, -1, -1, -1, -1, -1,		/* ar48-ar55 */
220	-1, -1, -1, -1, -1, -1, -1, -1,		/* ar56-ar63 */
221	SPECIAL(pfs)
222};
223
224static struct kgdb_frame_cache *
225kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
226{
227	char buf[MAX_REGISTER_SIZE];
228	struct kgdb_frame_cache *cache;
229
230	cache = *this_cache;
231	if (cache == NULL) {
232		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
233		*this_cache = cache;
234		frame_unwind_register(next_frame, IA64_BSP_REGNUM, buf);
235		cache->bsp = extract_unsigned_integer(buf,
236		    register_size(current_gdbarch, IA64_BSP_REGNUM));
237		cache->ip = frame_func_unwind(next_frame);
238		frame_unwind_register(next_frame, SP_REGNUM, buf);
239		cache->sp = extract_unsigned_integer(buf,
240		    register_size(current_gdbarch, SP_REGNUM));
241	}
242	return (cache);
243}
244
245static void
246kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
247    struct frame_id *this_id)
248{
249	struct kgdb_frame_cache *cache;
250
251	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
252	*this_id = frame_id_build_special(cache->sp, cache->ip, cache->bsp);
253}
254
255static void
256kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
257    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
258    CORE_ADDR *addrp, int *realnump, void *valuep)
259{
260	char buf[MAX_REGISTER_SIZE];
261	char dummy_valuep[MAX_REGISTER_SIZE];
262	struct kgdb_frame_cache *cache;
263	CORE_ADDR bsp;
264	int ofs, regsz;
265
266	regsz = register_size(current_gdbarch, regnum);
267
268	if (valuep == NULL)
269		valuep = dummy_valuep;
270	memset(valuep, 0, regsz);
271	*optimizedp = 0;
272	*addrp = 0;
273	*lvalp = not_lval;
274	*realnump = -1;
275
276	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
277
278	if (regnum == IA64_BSP_REGNUM) {
279		if (cache->saved_bsp == 0) {
280			target_read_memory(cache->sp + 16 + SPECIAL(bspstore),
281			    buf, regsz);
282			bsp = extract_unsigned_integer(buf, regsz);
283			target_read_memory(cache->sp + 16 + SPECIAL(ndirty),
284			    buf, regsz);
285			bsp += extract_unsigned_integer(buf, regsz);
286			cache->saved_bsp = bsp;
287		}
288		store_unsigned_integer(valuep, regsz, cache->saved_bsp);
289		return;
290	}
291	if (regnum == IA64_PR_REGNUM)
292		ofs = SPECIAL(pr);
293	else if (regnum == IA64_IP_REGNUM)
294		ofs = SPECIAL(iip);
295	else if (regnum == IA64_PSR_REGNUM)
296		ofs = SPECIAL(psr);
297	else if (regnum == IA64_CFM_REGNUM)
298		ofs = SPECIAL(cfm);
299	else if (regnum >= IA64_GR0_REGNUM && regnum <= IA64_GR31_REGNUM)
300		ofs = kgdb_trgt_frame_ofs_gr[regnum - IA64_GR0_REGNUM];
301	else if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR15_REGNUM)
302		ofs = kgdb_trgt_frame_ofs_fr[regnum - IA64_FR0_REGNUM];
303	else if (regnum >= IA64_BR0_REGNUM && regnum <= IA64_BR7_REGNUM)
304		ofs = kgdb_trgt_frame_ofs_br[regnum - IA64_BR0_REGNUM];
305	else if (regnum >= IA64_RSC_REGNUM && regnum <= IA64_PFS_REGNUM)
306		ofs = kgdb_trgt_frame_ofs_ar[regnum - IA64_RSC_REGNUM];
307	else
308		ofs = -1;
309	if (ofs == -1)
310		return;
311
312	*addrp = cache->sp + 16 + ofs;
313	*lvalp = lval_memory;
314	target_read_memory(*addrp, valuep, regsz);
315}
316
317static const struct frame_unwind kgdb_trgt_trapframe_unwind = {
318        UNKNOWN_FRAME,
319        &kgdb_trgt_trapframe_this_id,
320        &kgdb_trgt_trapframe_prev_register
321};
322
323const struct frame_unwind *
324kgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
325{
326	char *pname;
327	CORE_ADDR ip;
328
329	ip = frame_func_unwind(next_frame);
330	pname = NULL;
331	find_pc_partial_function(ip, &pname, NULL, NULL);
332	if (pname == NULL)
333		return (NULL);
334	if (strncmp(pname, "ivt_", 4) == 0)
335		return (&kgdb_trgt_trapframe_unwind);
336	/* printf("%s: %lx =%s\n", __func__, ip, pname); */
337	return (NULL);
338}
339