1132624Smarcel/*
2132624Smarcel * Copyright (c) 2004 Marcel Moolenaar
3132624Smarcel * All rights reserved.
4132624Smarcel *
5132624Smarcel * Redistribution and use in source and binary forms, with or without
6132624Smarcel * modification, are permitted provided that the following conditions
7132624Smarcel * are met:
8132624Smarcel *
9132624Smarcel * 1. Redistributions of source code must retain the above copyright
10132624Smarcel *    notice, this list of conditions and the following disclaimer.
11132624Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12132624Smarcel *    notice, this list of conditions and the following disclaimer in the
13132624Smarcel *    documentation and/or other materials provided with the distribution.
14132624Smarcel *
15132624Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16132624Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17132624Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18132624Smarcel * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19132624Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20132624Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21132624Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22132624Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23132624Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24132624Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25132624Smarcel */
26132624Smarcel
27132624Smarcel#include <sys/cdefs.h>
28132624Smarcel__FBSDID("$FreeBSD$");
29132624Smarcel
30173681Sjhb#include <sys/param.h>
31173681Sjhb#include <sys/proc.h>
32132624Smarcel#include <machine/pcb.h>
33149955Smarcel#include <machine/frame.h>
34173681Sjhb#include <machine/segments.h>
35173681Sjhb#include <machine/tss.h>
36132624Smarcel#include <err.h>
37132624Smarcel#include <kvm.h>
38132624Smarcel#include <string.h>
39132624Smarcel
40132624Smarcel#include <defs.h>
41132624Smarcel#include <target.h>
42132624Smarcel#include <gdbthread.h>
43132624Smarcel#include <inferior.h>
44132624Smarcel#include <regcache.h>
45149954Smarcel#include <frame-unwind.h>
46149955Smarcel#include <i386-tdep.h>
47132624Smarcel
48149954Smarcel#include "kgdb.h"
49149954Smarcel
50178670Sjhbstatic int ofs_fix;
51178670Sjhb
52132624Smarcelvoid
53132624Smarcelkgdb_trgt_fetch_registers(int regno __unused)
54132624Smarcel{
55132624Smarcel	struct kthr *kt;
56132624Smarcel	struct pcb pcb;
57132624Smarcel
58178713Sjhb	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
59132624Smarcel	if (kt == NULL)
60132624Smarcel		return;
61132624Smarcel	if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
62132624Smarcel		warnx("kvm_read: %s", kvm_geterr(kvm));
63132624Smarcel		memset(&pcb, 0, sizeof(pcb));
64132624Smarcel	}
65149955Smarcel	supply_register(I386_EBX_REGNUM, (char *)&pcb.pcb_ebx);
66149955Smarcel	supply_register(I386_ESP_REGNUM, (char *)&pcb.pcb_esp);
67149955Smarcel	supply_register(I386_EBP_REGNUM, (char *)&pcb.pcb_ebp);
68149955Smarcel	supply_register(I386_ESI_REGNUM, (char *)&pcb.pcb_esi);
69149955Smarcel	supply_register(I386_EDI_REGNUM, (char *)&pcb.pcb_edi);
70149955Smarcel	supply_register(I386_EIP_REGNUM, (char *)&pcb.pcb_eip);
71132624Smarcel}
72132624Smarcel
73132624Smarcelvoid
74132624Smarcelkgdb_trgt_store_registers(int regno __unused)
75132624Smarcel{
76132624Smarcel	fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
77132624Smarcel}
78149954Smarcel
79178670Sjhbvoid
80178670Sjhbkgdb_trgt_new_objfile(struct objfile *objfile)
81178670Sjhb{
82178670Sjhb
83178670Sjhb	/*
84178670Sjhb	 * In revision 1.117 of i386/i386/exception.S trap handlers
85178670Sjhb	 * were changed to pass trapframes by reference rather than
86178670Sjhb	 * by value.  Detect this by seeing if the first instruction
87178670Sjhb	 * at the 'calltrap' label is a "push %esp" which has the
88178670Sjhb	 * opcode 0x54.
89178670Sjhb	 */
90178670Sjhb	if (kgdb_parse("((char *)calltrap)[0]") == 0x54)
91178670Sjhb		ofs_fix = 4;
92178670Sjhb	else
93178670Sjhb		ofs_fix = 0;
94178670Sjhb}
95178670Sjhb
96173681Sjhbstruct kgdb_tss_cache {
97173681Sjhb	CORE_ADDR	pc;
98173681Sjhb	CORE_ADDR	sp;
99173681Sjhb	CORE_ADDR	tss;
100173681Sjhb};
101173681Sjhb
102173681Sjhbstatic int kgdb_trgt_tss_offset[15] = {
103173681Sjhb	offsetof(struct i386tss, tss_eax),
104173681Sjhb	offsetof(struct i386tss, tss_ecx),
105173681Sjhb	offsetof(struct i386tss, tss_edx),
106173681Sjhb	offsetof(struct i386tss, tss_ebx),
107173681Sjhb	offsetof(struct i386tss, tss_esp),
108173681Sjhb	offsetof(struct i386tss, tss_ebp),
109173681Sjhb	offsetof(struct i386tss, tss_esi),
110173681Sjhb	offsetof(struct i386tss, tss_edi),
111173681Sjhb	offsetof(struct i386tss, tss_eip),
112173681Sjhb	offsetof(struct i386tss, tss_eflags),
113173681Sjhb	offsetof(struct i386tss, tss_cs),
114173681Sjhb	offsetof(struct i386tss, tss_ss),
115173681Sjhb	offsetof(struct i386tss, tss_ds),
116173681Sjhb	offsetof(struct i386tss, tss_es),
117173681Sjhb	offsetof(struct i386tss, tss_fs)
118173681Sjhb};
119173681Sjhb
120173681Sjhb/*
121173681Sjhb * If the current thread is executing on a CPU, fetch the common_tss
122173681Sjhb * for that CPU.
123173681Sjhb *
124173681Sjhb * This is painful because 'struct pcpu' is variant sized, so we can't
125173681Sjhb * use it.  Instead, we lookup the GDT selector for this CPU and
126173681Sjhb * extract the base of the TSS from there.
127173681Sjhb */
128173681Sjhbstatic CORE_ADDR
129173681Sjhbkgdb_trgt_fetch_tss(void)
130173681Sjhb{
131173681Sjhb	struct kthr *kt;
132173681Sjhb	struct segment_descriptor sd;
133173681Sjhb	uintptr_t addr, cpu0prvpage, tss;
134173681Sjhb
135178713Sjhb	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
136173681Sjhb	if (kt == NULL || kt->cpu == NOCPU)
137173681Sjhb		return (0);
138173681Sjhb
139210852Sjhb	addr = kgdb_lookup("gdt");
140173681Sjhb	if (addr == 0)
141173681Sjhb		return (0);
142173681Sjhb	addr += (kt->cpu * NGDT + GPROC0_SEL) * sizeof(sd);
143173681Sjhb	if (kvm_read(kvm, addr, &sd, sizeof(sd)) != sizeof(sd)) {
144173681Sjhb		warnx("kvm_read: %s", kvm_geterr(kvm));
145173681Sjhb		return (0);
146173681Sjhb	}
147173681Sjhb	if (sd.sd_type != SDT_SYS386BSY) {
148173681Sjhb		warnx("descriptor is not a busy TSS");
149173681Sjhb		return (0);
150173681Sjhb	}
151173681Sjhb	tss = sd.sd_hibase << 24 | sd.sd_lobase;
152173681Sjhb
153173681Sjhb	/*
154173681Sjhb	 * In SMP kernels, the TSS is stored as part of the per-CPU
155173681Sjhb	 * data.  On older kernels, the CPU0's private page
156173681Sjhb	 * is stored at an address that isn't mapped in minidumps.
157173681Sjhb	 * However, the data is mapped at the alternate cpu0prvpage
158173681Sjhb	 * address.  Thus, if the TSS is at the invalid address,
159173681Sjhb	 * change it to be relative to cpu0prvpage instead.
160173681Sjhb	 */
161173681Sjhb	if (trunc_page(tss) == 0xffc00000) {
162210852Sjhb		addr = kgdb_lookup("cpu0prvpage");
163210852Sjhb		if (addr == 0)
164173681Sjhb			return (0);
165173681Sjhb		if (kvm_read(kvm, addr, &cpu0prvpage, sizeof(cpu0prvpage)) !=
166173681Sjhb		    sizeof(cpu0prvpage)) {
167173681Sjhb			warnx("kvm_read: %s", kvm_geterr(kvm));
168173681Sjhb			return (0);
169173681Sjhb		}
170173681Sjhb		tss = cpu0prvpage + (tss & PAGE_MASK);
171173681Sjhb	}
172173681Sjhb	return ((CORE_ADDR)tss);
173173681Sjhb}
174173681Sjhb
175173681Sjhbstatic struct kgdb_tss_cache *
176173681Sjhbkgdb_trgt_tss_cache(struct frame_info *next_frame, void **this_cache)
177173681Sjhb{
178173681Sjhb	char buf[MAX_REGISTER_SIZE];
179173681Sjhb	struct kgdb_tss_cache *cache;
180173681Sjhb
181173681Sjhb	cache = *this_cache;
182173681Sjhb	if (cache == NULL) {
183173681Sjhb		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_tss_cache);
184173681Sjhb		*this_cache = cache;
185173681Sjhb		cache->pc = frame_func_unwind(next_frame);
186173681Sjhb		frame_unwind_register(next_frame, SP_REGNUM, buf);
187173681Sjhb		cache->sp = extract_unsigned_integer(buf,
188173681Sjhb		    register_size(current_gdbarch, SP_REGNUM));
189173681Sjhb		cache->tss = kgdb_trgt_fetch_tss();
190173681Sjhb	}
191173681Sjhb	return (cache);
192173681Sjhb}
193173681Sjhb
194173681Sjhbstatic void
195173681Sjhbkgdb_trgt_dblfault_this_id(struct frame_info *next_frame, void **this_cache,
196173681Sjhb    struct frame_id *this_id)
197173681Sjhb{
198173681Sjhb	struct kgdb_tss_cache *cache;
199173681Sjhb
200173681Sjhb	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
201173681Sjhb	*this_id = frame_id_build(cache->sp, cache->pc);
202173681Sjhb}
203173681Sjhb
204173681Sjhbstatic void
205173681Sjhbkgdb_trgt_dblfault_prev_register(struct frame_info *next_frame,
206173681Sjhb    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
207173681Sjhb    CORE_ADDR *addrp, int *realnump, void *valuep)
208173681Sjhb{
209173681Sjhb	char dummy_valuep[MAX_REGISTER_SIZE];
210173681Sjhb	struct kgdb_tss_cache *cache;
211173681Sjhb	int ofs, regsz;
212173681Sjhb
213173681Sjhb	regsz = register_size(current_gdbarch, regnum);
214173681Sjhb
215173681Sjhb	if (valuep == NULL)
216173681Sjhb		valuep = dummy_valuep;
217173681Sjhb	memset(valuep, 0, regsz);
218173681Sjhb	*optimizedp = 0;
219173681Sjhb	*addrp = 0;
220173681Sjhb	*lvalp = not_lval;
221173681Sjhb	*realnump = -1;
222173681Sjhb
223173681Sjhb	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
224173681Sjhb	    ? kgdb_trgt_tss_offset[regnum] : -1;
225173681Sjhb	if (ofs == -1)
226173681Sjhb		return;
227173681Sjhb
228173681Sjhb	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
229173681Sjhb	if (cache->tss == 0)
230173681Sjhb		return;
231173681Sjhb	*addrp = cache->tss + ofs;
232173681Sjhb	*lvalp = lval_memory;
233173681Sjhb	target_read_memory(*addrp, valuep, regsz);
234173681Sjhb}
235173681Sjhb
236173681Sjhbstatic const struct frame_unwind kgdb_trgt_dblfault_unwind = {
237173681Sjhb        UNKNOWN_FRAME,
238173681Sjhb        &kgdb_trgt_dblfault_this_id,
239173681Sjhb        &kgdb_trgt_dblfault_prev_register
240173681Sjhb};
241173681Sjhb
242149955Smarcelstruct kgdb_frame_cache {
243183414Skib	int		frame_type;
244149955Smarcel	CORE_ADDR	pc;
245149955Smarcel	CORE_ADDR	sp;
246149955Smarcel};
247183414Skib#define	FT_NORMAL		1
248183414Skib#define	FT_INTRFRAME		2
249183414Skib#define	FT_INTRTRAPFRAME	3
250183414Skib#define	FT_TIMERFRAME		4
251149955Smarcel
252149955Smarcelstatic int kgdb_trgt_frame_offset[15] = {
253149955Smarcel	offsetof(struct trapframe, tf_eax),
254149955Smarcel	offsetof(struct trapframe, tf_ecx),
255149955Smarcel	offsetof(struct trapframe, tf_edx),
256149955Smarcel	offsetof(struct trapframe, tf_ebx),
257149955Smarcel	offsetof(struct trapframe, tf_esp),
258149955Smarcel	offsetof(struct trapframe, tf_ebp),
259149955Smarcel	offsetof(struct trapframe, tf_esi),
260149955Smarcel	offsetof(struct trapframe, tf_edi),
261149955Smarcel	offsetof(struct trapframe, tf_eip),
262149955Smarcel	offsetof(struct trapframe, tf_eflags),
263149955Smarcel	offsetof(struct trapframe, tf_cs),
264149955Smarcel	offsetof(struct trapframe, tf_ss),
265149955Smarcel	offsetof(struct trapframe, tf_ds),
266149955Smarcel	offsetof(struct trapframe, tf_es),
267149955Smarcel	offsetof(struct trapframe, tf_fs)
268149955Smarcel};
269149955Smarcel
270149955Smarcelstatic struct kgdb_frame_cache *
271149955Smarcelkgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
272149955Smarcel{
273149955Smarcel	char buf[MAX_REGISTER_SIZE];
274149955Smarcel	struct kgdb_frame_cache *cache;
275149975Smarcel	char *pname;
276149955Smarcel
277149955Smarcel	cache = *this_cache;
278149955Smarcel	if (cache == NULL) {
279149955Smarcel		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
280149955Smarcel		*this_cache = cache;
281149955Smarcel		cache->pc = frame_func_unwind(next_frame);
282149975Smarcel		find_pc_partial_function(cache->pc, &pname, NULL, NULL);
283183414Skib		if (pname[0] != 'X')
284183414Skib			cache->frame_type = FT_NORMAL;
285183414Skib		else if (strcmp(pname, "Xtimerint") == 0)
286183414Skib			cache->frame_type = FT_TIMERFRAME;
287183414Skib		else if (strcmp(pname, "Xcpustop") == 0 ||
288183414Skib		    strcmp(pname, "Xrendezvous") == 0 ||
289183414Skib		    strcmp(pname, "Xipi_intr_bitmap_handler") == 0 ||
290183414Skib		    strcmp(pname, "Xlazypmap") == 0)
291183414Skib			cache->frame_type = FT_INTRTRAPFRAME;
292183414Skib		else
293183414Skib			cache->frame_type = FT_INTRFRAME;
294149955Smarcel		frame_unwind_register(next_frame, SP_REGNUM, buf);
295149955Smarcel		cache->sp = extract_unsigned_integer(buf,
296149955Smarcel		    register_size(current_gdbarch, SP_REGNUM));
297149955Smarcel	}
298149955Smarcel	return (cache);
299149955Smarcel}
300149955Smarcel
301149954Smarcelstatic void
302149954Smarcelkgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
303149954Smarcel    struct frame_id *this_id)
304149954Smarcel{
305149955Smarcel	struct kgdb_frame_cache *cache;
306149955Smarcel
307149955Smarcel	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
308149955Smarcel	*this_id = frame_id_build(cache->sp, cache->pc);
309149954Smarcel}
310149954Smarcel
311149954Smarcelstatic void
312149954Smarcelkgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
313149954Smarcel    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
314149954Smarcel    CORE_ADDR *addrp, int *realnump, void *valuep)
315149954Smarcel{
316149955Smarcel	char dummy_valuep[MAX_REGISTER_SIZE];
317149955Smarcel	struct kgdb_frame_cache *cache;
318149955Smarcel	int ofs, regsz;
319149955Smarcel
320149955Smarcel	regsz = register_size(current_gdbarch, regnum);
321149955Smarcel
322149955Smarcel	if (valuep == NULL)
323149955Smarcel		valuep = dummy_valuep;
324149955Smarcel	memset(valuep, 0, regsz);
325149955Smarcel	*optimizedp = 0;
326149955Smarcel	*addrp = 0;
327149955Smarcel	*lvalp = not_lval;
328149955Smarcel	*realnump = -1;
329149955Smarcel
330149955Smarcel	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
331167143Skib	    ? kgdb_trgt_frame_offset[regnum] + ofs_fix : -1;
332149955Smarcel	if (ofs == -1)
333149955Smarcel		return;
334149955Smarcel
335149955Smarcel	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
336183414Skib	switch (cache->frame_type) {
337183414Skib	case FT_NORMAL:
338183414Skib		break;
339183414Skib	case FT_INTRFRAME:
340183414Skib		ofs += 4;
341183414Skib		break;
342183414Skib	case FT_TIMERFRAME:
343183414Skib		break;
344183414Skib	case FT_INTRTRAPFRAME:
345183414Skib		ofs -= ofs_fix;
346183414Skib		break;
347183414Skib	default:
348183414Skib		fprintf_unfiltered(gdb_stderr, "Correct FT_XXX frame offsets "
349183414Skib		   "for %d\n", cache->frame_type);
350183414Skib		break;
351183414Skib	}
352183414Skib	*addrp = cache->sp + ofs;
353149955Smarcel	*lvalp = lval_memory;
354149955Smarcel	target_read_memory(*addrp, valuep, regsz);
355149954Smarcel}
356149954Smarcel
357149954Smarcelstatic const struct frame_unwind kgdb_trgt_trapframe_unwind = {
358149954Smarcel        UNKNOWN_FRAME,
359149954Smarcel        &kgdb_trgt_trapframe_this_id,
360149954Smarcel        &kgdb_trgt_trapframe_prev_register
361149954Smarcel};
362149954Smarcel
363149954Smarcelconst struct frame_unwind *
364149954Smarcelkgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
365149954Smarcel{
366149955Smarcel	char *pname;
367149955Smarcel	CORE_ADDR pc;
368149954Smarcel
369149955Smarcel	pc = frame_pc_unwind(next_frame);
370149955Smarcel	pname = NULL;
371149955Smarcel	find_pc_partial_function(pc, &pname, NULL, NULL);
372149955Smarcel	if (pname == NULL)
373149955Smarcel		return (NULL);
374173681Sjhb	if (strcmp(pname, "dblfault_handler") == 0)
375173681Sjhb		return (&kgdb_trgt_dblfault_unwind);
376149975Smarcel	if (strcmp(pname, "calltrap") == 0 ||
377149975Smarcel	    (pname[0] == 'X' && pname[1] != '_'))
378149955Smarcel		return (&kgdb_trgt_trapframe_unwind);
379149955Smarcel	/* printf("%s: %llx =%s\n", __func__, pc, pname); */
380149975Smarcel	return (NULL);
381149954Smarcel}
382