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/param.h>
31#include <sys/proc.h>
32#include <vm/vm.h>
33#include <vm/pmap.h>
34#include <machine/pcb.h>
35#include <machine/frame.h>
36#include <machine/segments.h>
37#include <machine/tss.h>
38#include <err.h>
39#include <kvm.h>
40#include <string.h>
41
42#include <defs.h>
43#include <target.h>
44#include <gdbthread.h>
45#include <inferior.h>
46#include <regcache.h>
47#include <frame-unwind.h>
48#include <i386-tdep.h>
49
50#include "kgdb.h"
51
52static int ofs_fix;
53
54CORE_ADDR
55kgdb_trgt_core_pcb(u_int cpuid)
56{
57	return (kgdb_trgt_stop_pcb(cpuid, sizeof(struct pcb)));
58}
59
60void
61kgdb_trgt_fetch_registers(int regno __unused)
62{
63	struct kthr *kt;
64	struct pcb pcb;
65
66	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
67	if (kt == NULL)
68		return;
69	if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
70		warnx("kvm_read: %s", kvm_geterr(kvm));
71		memset(&pcb, 0, sizeof(pcb));
72	}
73	supply_register(I386_EBX_REGNUM, (char *)&pcb.pcb_ebx);
74	supply_register(I386_ESP_REGNUM, (char *)&pcb.pcb_esp);
75	supply_register(I386_EBP_REGNUM, (char *)&pcb.pcb_ebp);
76	supply_register(I386_ESI_REGNUM, (char *)&pcb.pcb_esi);
77	supply_register(I386_EDI_REGNUM, (char *)&pcb.pcb_edi);
78	supply_register(I386_EIP_REGNUM, (char *)&pcb.pcb_eip);
79}
80
81void
82kgdb_trgt_store_registers(int regno __unused)
83{
84	fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
85}
86
87void
88kgdb_trgt_new_objfile(struct objfile *objfile)
89{
90
91	/*
92	 * In revision 1.117 of i386/i386/exception.S trap handlers
93	 * were changed to pass trapframes by reference rather than
94	 * by value.  Detect this by seeing if the first instruction
95	 * at the 'calltrap' label is a "push %esp" which has the
96	 * opcode 0x54.
97	 */
98	if (kgdb_parse("((char *)calltrap)[0]") == 0x54)
99		ofs_fix = 4;
100	else
101		ofs_fix = 0;
102}
103
104struct kgdb_tss_cache {
105	CORE_ADDR	pc;
106	CORE_ADDR	sp;
107	CORE_ADDR	tss;
108};
109
110static int kgdb_trgt_tss_offset[15] = {
111	offsetof(struct i386tss, tss_eax),
112	offsetof(struct i386tss, tss_ecx),
113	offsetof(struct i386tss, tss_edx),
114	offsetof(struct i386tss, tss_ebx),
115	offsetof(struct i386tss, tss_esp),
116	offsetof(struct i386tss, tss_ebp),
117	offsetof(struct i386tss, tss_esi),
118	offsetof(struct i386tss, tss_edi),
119	offsetof(struct i386tss, tss_eip),
120	offsetof(struct i386tss, tss_eflags),
121	offsetof(struct i386tss, tss_cs),
122	offsetof(struct i386tss, tss_ss),
123	offsetof(struct i386tss, tss_ds),
124	offsetof(struct i386tss, tss_es),
125	offsetof(struct i386tss, tss_fs)
126};
127
128/*
129 * If the current thread is executing on a CPU, fetch the common_tss
130 * for that CPU.
131 *
132 * This is painful because 'struct pcpu' is variant sized, so we can't
133 * use it.  Instead, we lookup the GDT selector for this CPU and
134 * extract the base of the TSS from there.
135 */
136static CORE_ADDR
137kgdb_trgt_fetch_tss(void)
138{
139	struct kthr *kt;
140	struct segment_descriptor sd;
141	uintptr_t addr, cpu0prvpage, tss;
142
143	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
144	if (kt == NULL || kt->cpu == NOCPU || kt->cpu < 0)
145		return (0);
146
147	addr = kgdb_lookup("gdt");
148	if (addr == 0)
149		return (0);
150	addr += (kt->cpu * NGDT + GPROC0_SEL) * sizeof(sd);
151	if (kvm_read(kvm, addr, &sd, sizeof(sd)) != sizeof(sd)) {
152		warnx("kvm_read: %s", kvm_geterr(kvm));
153		return (0);
154	}
155	if (sd.sd_type != SDT_SYS386BSY) {
156		warnx("descriptor is not a busy TSS");
157		return (0);
158	}
159	tss = sd.sd_hibase << 24 | sd.sd_lobase;
160
161	/*
162	 * In SMP kernels, the TSS is stored as part of the per-CPU
163	 * data.  On older kernels, the CPU0's private page
164	 * is stored at an address that isn't mapped in minidumps.
165	 * However, the data is mapped at the alternate cpu0prvpage
166	 * address.  Thus, if the TSS is at the invalid address,
167	 * change it to be relative to cpu0prvpage instead.
168	 */
169	if (trunc_page(tss) == 0xffc00000) {
170		addr = kgdb_lookup("cpu0prvpage");
171		if (addr == 0)
172			return (0);
173		if (kvm_read(kvm, addr, &cpu0prvpage, sizeof(cpu0prvpage)) !=
174		    sizeof(cpu0prvpage)) {
175			warnx("kvm_read: %s", kvm_geterr(kvm));
176			return (0);
177		}
178		tss = cpu0prvpage + (tss & PAGE_MASK);
179	}
180	return ((CORE_ADDR)tss);
181}
182
183static struct kgdb_tss_cache *
184kgdb_trgt_tss_cache(struct frame_info *next_frame, void **this_cache)
185{
186	char buf[MAX_REGISTER_SIZE];
187	struct kgdb_tss_cache *cache;
188
189	cache = *this_cache;
190	if (cache == NULL) {
191		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_tss_cache);
192		*this_cache = cache;
193		cache->pc = frame_func_unwind(next_frame);
194		frame_unwind_register(next_frame, SP_REGNUM, buf);
195		cache->sp = extract_unsigned_integer(buf,
196		    register_size(current_gdbarch, SP_REGNUM));
197		cache->tss = kgdb_trgt_fetch_tss();
198	}
199	return (cache);
200}
201
202static void
203kgdb_trgt_dblfault_this_id(struct frame_info *next_frame, void **this_cache,
204    struct frame_id *this_id)
205{
206	struct kgdb_tss_cache *cache;
207
208	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
209	*this_id = frame_id_build(cache->sp, cache->pc);
210}
211
212static void
213kgdb_trgt_dblfault_prev_register(struct frame_info *next_frame,
214    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
215    CORE_ADDR *addrp, int *realnump, void *valuep)
216{
217	char dummy_valuep[MAX_REGISTER_SIZE];
218	struct kgdb_tss_cache *cache;
219	int ofs, regsz;
220
221	regsz = register_size(current_gdbarch, regnum);
222
223	if (valuep == NULL)
224		valuep = dummy_valuep;
225	memset(valuep, 0, regsz);
226	*optimizedp = 0;
227	*addrp = 0;
228	*lvalp = not_lval;
229	*realnump = -1;
230
231	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
232	    ? kgdb_trgt_tss_offset[regnum] : -1;
233	if (ofs == -1)
234		return;
235
236	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
237	if (cache->tss == 0)
238		return;
239	*addrp = cache->tss + ofs;
240	*lvalp = lval_memory;
241	target_read_memory(*addrp, valuep, regsz);
242}
243
244static const struct frame_unwind kgdb_trgt_dblfault_unwind = {
245        UNKNOWN_FRAME,
246        &kgdb_trgt_dblfault_this_id,
247        &kgdb_trgt_dblfault_prev_register
248};
249
250struct kgdb_frame_cache {
251	int		frame_type;
252	CORE_ADDR	pc;
253	CORE_ADDR	sp;
254};
255#define	FT_NORMAL		1
256#define	FT_INTRFRAME		2
257#define	FT_INTRTRAPFRAME	3
258#define	FT_TIMERFRAME		4
259
260static int kgdb_trgt_frame_offset[15] = {
261	offsetof(struct trapframe, tf_eax),
262	offsetof(struct trapframe, tf_ecx),
263	offsetof(struct trapframe, tf_edx),
264	offsetof(struct trapframe, tf_ebx),
265	offsetof(struct trapframe, tf_esp),
266	offsetof(struct trapframe, tf_ebp),
267	offsetof(struct trapframe, tf_esi),
268	offsetof(struct trapframe, tf_edi),
269	offsetof(struct trapframe, tf_eip),
270	offsetof(struct trapframe, tf_eflags),
271	offsetof(struct trapframe, tf_cs),
272	offsetof(struct trapframe, tf_ss),
273	offsetof(struct trapframe, tf_ds),
274	offsetof(struct trapframe, tf_es),
275	offsetof(struct trapframe, tf_fs)
276};
277
278static struct kgdb_frame_cache *
279kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
280{
281	char buf[MAX_REGISTER_SIZE];
282	struct kgdb_frame_cache *cache;
283	char *pname;
284	CORE_ADDR pcx;
285	uintptr_t addr, setidt_disp;
286
287	cache = *this_cache;
288	if (cache == NULL) {
289		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
290		*this_cache = cache;
291		pcx = frame_pc_unwind(next_frame);
292		if (pcx >= PMAP_TRM_MIN_ADDRESS) {
293			addr = kgdb_lookup("setidt_disp");
294			if (addr != 0) {
295				if (kvm_read(kvm, addr, &setidt_disp,
296				    sizeof(setidt_disp)) !=
297				    sizeof(setidt_disp))
298					warnx("kvm_read: %s", kvm_geterr(kvm));
299				else
300					pcx -= setidt_disp;
301			}
302		}
303		cache->pc = pcx;
304		find_pc_partial_function(cache->pc, &pname, NULL, NULL);
305		if (pname[0] != 'X')
306			cache->frame_type = FT_NORMAL;
307		else if (strcmp(pname, "Xtimerint") == 0)
308			cache->frame_type = FT_TIMERFRAME;
309		else if (strcmp(pname, "Xcpustop") == 0 ||
310		    strcmp(pname, "Xrendezvous") == 0 ||
311		    strcmp(pname, "Xipi_intr_bitmap_handler") == 0 ||
312		    strcmp(pname, "Xlazypmap") == 0)
313			cache->frame_type = FT_INTRTRAPFRAME;
314		else
315			cache->frame_type = FT_INTRFRAME;
316		frame_unwind_register(next_frame, SP_REGNUM, buf);
317		cache->sp = extract_unsigned_integer(buf,
318		    register_size(current_gdbarch, SP_REGNUM));
319	}
320	return (cache);
321}
322
323static void
324kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
325    struct frame_id *this_id)
326{
327	struct kgdb_frame_cache *cache;
328
329	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
330	*this_id = frame_id_build(cache->sp, cache->pc);
331}
332
333static void
334kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
335    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
336    CORE_ADDR *addrp, int *realnump, void *valuep)
337{
338	char dummy_valuep[MAX_REGISTER_SIZE];
339	struct kgdb_frame_cache *cache;
340	int ofs, regsz;
341
342	regsz = register_size(current_gdbarch, regnum);
343
344	if (valuep == NULL)
345		valuep = dummy_valuep;
346	memset(valuep, 0, regsz);
347	*optimizedp = 0;
348	*addrp = 0;
349	*lvalp = not_lval;
350	*realnump = -1;
351
352	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
353	    ? kgdb_trgt_frame_offset[regnum] + ofs_fix : -1;
354	if (ofs == -1)
355		return;
356
357	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
358	switch (cache->frame_type) {
359	case FT_NORMAL:
360		break;
361	case FT_INTRFRAME:
362		ofs += 4;
363		break;
364	case FT_TIMERFRAME:
365		break;
366	case FT_INTRTRAPFRAME:
367		ofs -= ofs_fix;
368		break;
369	default:
370		fprintf_unfiltered(gdb_stderr, "Correct FT_XXX frame offsets "
371		   "for %d\n", cache->frame_type);
372		break;
373	}
374	*addrp = cache->sp + ofs;
375	*lvalp = lval_memory;
376	target_read_memory(*addrp, valuep, regsz);
377}
378
379static const struct frame_unwind kgdb_trgt_trapframe_unwind = {
380        UNKNOWN_FRAME,
381        &kgdb_trgt_trapframe_this_id,
382        &kgdb_trgt_trapframe_prev_register
383};
384
385const struct frame_unwind *
386kgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
387{
388	char *pname;
389	CORE_ADDR pc;
390
391	pc = frame_pc_unwind(next_frame);
392	if (pc >= PMAP_TRM_MIN_ADDRESS)
393		return (&kgdb_trgt_trapframe_unwind);
394	pname = NULL;
395	find_pc_partial_function(pc, &pname, NULL, NULL);
396	if (pname == NULL)
397		return (NULL);
398	if (strcmp(pname, "dblfault_handler") == 0)
399		return (&kgdb_trgt_dblfault_unwind);
400	if (strcmp(pname, "calltrap") == 0 ||
401	    (pname[0] == 'X' && pname[1] != '_'))
402		return (&kgdb_trgt_trapframe_unwind);
403	/* printf("%s: %llx =%s\n", __func__, pc, pname); */
404	return (NULL);
405}
406
407/*
408 * This function ensures, that the PC is inside the
409 * function section which is understood by GDB.
410 *
411 * Return 0 when fixup is necessary, -1 otherwise.
412 */
413int
414kgdb_trgt_pc_fixup(CORE_ADDR *pc __unused)
415{
416
417	return (-1);
418}
419