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: releng/10.3/gnu/usr.bin/gdb/kgdb/trgt_i386.c 246893 2013-02-17 02:15:19Z marcel $");
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
52246893SmarcelCORE_ADDR
53246893Smarcelkgdb_trgt_core_pcb(u_int cpuid)
54246893Smarcel{
55246893Smarcel	return (kgdb_trgt_stop_pcb(cpuid, sizeof(struct pcb)));
56246893Smarcel}
57246893Smarcel
58132624Smarcelvoid
59132624Smarcelkgdb_trgt_fetch_registers(int regno __unused)
60132624Smarcel{
61132624Smarcel	struct kthr *kt;
62132624Smarcel	struct pcb pcb;
63132624Smarcel
64178713Sjhb	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
65132624Smarcel	if (kt == NULL)
66132624Smarcel		return;
67132624Smarcel	if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
68132624Smarcel		warnx("kvm_read: %s", kvm_geterr(kvm));
69132624Smarcel		memset(&pcb, 0, sizeof(pcb));
70132624Smarcel	}
71149955Smarcel	supply_register(I386_EBX_REGNUM, (char *)&pcb.pcb_ebx);
72149955Smarcel	supply_register(I386_ESP_REGNUM, (char *)&pcb.pcb_esp);
73149955Smarcel	supply_register(I386_EBP_REGNUM, (char *)&pcb.pcb_ebp);
74149955Smarcel	supply_register(I386_ESI_REGNUM, (char *)&pcb.pcb_esi);
75149955Smarcel	supply_register(I386_EDI_REGNUM, (char *)&pcb.pcb_edi);
76149955Smarcel	supply_register(I386_EIP_REGNUM, (char *)&pcb.pcb_eip);
77132624Smarcel}
78132624Smarcel
79132624Smarcelvoid
80132624Smarcelkgdb_trgt_store_registers(int regno __unused)
81132624Smarcel{
82132624Smarcel	fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
83132624Smarcel}
84149954Smarcel
85178670Sjhbvoid
86178670Sjhbkgdb_trgt_new_objfile(struct objfile *objfile)
87178670Sjhb{
88178670Sjhb
89178670Sjhb	/*
90178670Sjhb	 * In revision 1.117 of i386/i386/exception.S trap handlers
91178670Sjhb	 * were changed to pass trapframes by reference rather than
92178670Sjhb	 * by value.  Detect this by seeing if the first instruction
93178670Sjhb	 * at the 'calltrap' label is a "push %esp" which has the
94178670Sjhb	 * opcode 0x54.
95178670Sjhb	 */
96178670Sjhb	if (kgdb_parse("((char *)calltrap)[0]") == 0x54)
97178670Sjhb		ofs_fix = 4;
98178670Sjhb	else
99178670Sjhb		ofs_fix = 0;
100178670Sjhb}
101178670Sjhb
102173681Sjhbstruct kgdb_tss_cache {
103173681Sjhb	CORE_ADDR	pc;
104173681Sjhb	CORE_ADDR	sp;
105173681Sjhb	CORE_ADDR	tss;
106173681Sjhb};
107173681Sjhb
108173681Sjhbstatic int kgdb_trgt_tss_offset[15] = {
109173681Sjhb	offsetof(struct i386tss, tss_eax),
110173681Sjhb	offsetof(struct i386tss, tss_ecx),
111173681Sjhb	offsetof(struct i386tss, tss_edx),
112173681Sjhb	offsetof(struct i386tss, tss_ebx),
113173681Sjhb	offsetof(struct i386tss, tss_esp),
114173681Sjhb	offsetof(struct i386tss, tss_ebp),
115173681Sjhb	offsetof(struct i386tss, tss_esi),
116173681Sjhb	offsetof(struct i386tss, tss_edi),
117173681Sjhb	offsetof(struct i386tss, tss_eip),
118173681Sjhb	offsetof(struct i386tss, tss_eflags),
119173681Sjhb	offsetof(struct i386tss, tss_cs),
120173681Sjhb	offsetof(struct i386tss, tss_ss),
121173681Sjhb	offsetof(struct i386tss, tss_ds),
122173681Sjhb	offsetof(struct i386tss, tss_es),
123173681Sjhb	offsetof(struct i386tss, tss_fs)
124173681Sjhb};
125173681Sjhb
126173681Sjhb/*
127173681Sjhb * If the current thread is executing on a CPU, fetch the common_tss
128173681Sjhb * for that CPU.
129173681Sjhb *
130173681Sjhb * This is painful because 'struct pcpu' is variant sized, so we can't
131173681Sjhb * use it.  Instead, we lookup the GDT selector for this CPU and
132173681Sjhb * extract the base of the TSS from there.
133173681Sjhb */
134173681Sjhbstatic CORE_ADDR
135173681Sjhbkgdb_trgt_fetch_tss(void)
136173681Sjhb{
137173681Sjhb	struct kthr *kt;
138173681Sjhb	struct segment_descriptor sd;
139173681Sjhb	uintptr_t addr, cpu0prvpage, tss;
140173681Sjhb
141178713Sjhb	kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid));
142173681Sjhb	if (kt == NULL || kt->cpu == NOCPU)
143173681Sjhb		return (0);
144173681Sjhb
145210852Sjhb	addr = kgdb_lookup("gdt");
146173681Sjhb	if (addr == 0)
147173681Sjhb		return (0);
148173681Sjhb	addr += (kt->cpu * NGDT + GPROC0_SEL) * sizeof(sd);
149173681Sjhb	if (kvm_read(kvm, addr, &sd, sizeof(sd)) != sizeof(sd)) {
150173681Sjhb		warnx("kvm_read: %s", kvm_geterr(kvm));
151173681Sjhb		return (0);
152173681Sjhb	}
153173681Sjhb	if (sd.sd_type != SDT_SYS386BSY) {
154173681Sjhb		warnx("descriptor is not a busy TSS");
155173681Sjhb		return (0);
156173681Sjhb	}
157173681Sjhb	tss = sd.sd_hibase << 24 | sd.sd_lobase;
158173681Sjhb
159173681Sjhb	/*
160173681Sjhb	 * In SMP kernels, the TSS is stored as part of the per-CPU
161173681Sjhb	 * data.  On older kernels, the CPU0's private page
162173681Sjhb	 * is stored at an address that isn't mapped in minidumps.
163173681Sjhb	 * However, the data is mapped at the alternate cpu0prvpage
164173681Sjhb	 * address.  Thus, if the TSS is at the invalid address,
165173681Sjhb	 * change it to be relative to cpu0prvpage instead.
166173681Sjhb	 */
167173681Sjhb	if (trunc_page(tss) == 0xffc00000) {
168210852Sjhb		addr = kgdb_lookup("cpu0prvpage");
169210852Sjhb		if (addr == 0)
170173681Sjhb			return (0);
171173681Sjhb		if (kvm_read(kvm, addr, &cpu0prvpage, sizeof(cpu0prvpage)) !=
172173681Sjhb		    sizeof(cpu0prvpage)) {
173173681Sjhb			warnx("kvm_read: %s", kvm_geterr(kvm));
174173681Sjhb			return (0);
175173681Sjhb		}
176173681Sjhb		tss = cpu0prvpage + (tss & PAGE_MASK);
177173681Sjhb	}
178173681Sjhb	return ((CORE_ADDR)tss);
179173681Sjhb}
180173681Sjhb
181173681Sjhbstatic struct kgdb_tss_cache *
182173681Sjhbkgdb_trgt_tss_cache(struct frame_info *next_frame, void **this_cache)
183173681Sjhb{
184173681Sjhb	char buf[MAX_REGISTER_SIZE];
185173681Sjhb	struct kgdb_tss_cache *cache;
186173681Sjhb
187173681Sjhb	cache = *this_cache;
188173681Sjhb	if (cache == NULL) {
189173681Sjhb		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_tss_cache);
190173681Sjhb		*this_cache = cache;
191173681Sjhb		cache->pc = frame_func_unwind(next_frame);
192173681Sjhb		frame_unwind_register(next_frame, SP_REGNUM, buf);
193173681Sjhb		cache->sp = extract_unsigned_integer(buf,
194173681Sjhb		    register_size(current_gdbarch, SP_REGNUM));
195173681Sjhb		cache->tss = kgdb_trgt_fetch_tss();
196173681Sjhb	}
197173681Sjhb	return (cache);
198173681Sjhb}
199173681Sjhb
200173681Sjhbstatic void
201173681Sjhbkgdb_trgt_dblfault_this_id(struct frame_info *next_frame, void **this_cache,
202173681Sjhb    struct frame_id *this_id)
203173681Sjhb{
204173681Sjhb	struct kgdb_tss_cache *cache;
205173681Sjhb
206173681Sjhb	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
207173681Sjhb	*this_id = frame_id_build(cache->sp, cache->pc);
208173681Sjhb}
209173681Sjhb
210173681Sjhbstatic void
211173681Sjhbkgdb_trgt_dblfault_prev_register(struct frame_info *next_frame,
212173681Sjhb    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
213173681Sjhb    CORE_ADDR *addrp, int *realnump, void *valuep)
214173681Sjhb{
215173681Sjhb	char dummy_valuep[MAX_REGISTER_SIZE];
216173681Sjhb	struct kgdb_tss_cache *cache;
217173681Sjhb	int ofs, regsz;
218173681Sjhb
219173681Sjhb	regsz = register_size(current_gdbarch, regnum);
220173681Sjhb
221173681Sjhb	if (valuep == NULL)
222173681Sjhb		valuep = dummy_valuep;
223173681Sjhb	memset(valuep, 0, regsz);
224173681Sjhb	*optimizedp = 0;
225173681Sjhb	*addrp = 0;
226173681Sjhb	*lvalp = not_lval;
227173681Sjhb	*realnump = -1;
228173681Sjhb
229173681Sjhb	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
230173681Sjhb	    ? kgdb_trgt_tss_offset[regnum] : -1;
231173681Sjhb	if (ofs == -1)
232173681Sjhb		return;
233173681Sjhb
234173681Sjhb	cache = kgdb_trgt_tss_cache(next_frame, this_cache);
235173681Sjhb	if (cache->tss == 0)
236173681Sjhb		return;
237173681Sjhb	*addrp = cache->tss + ofs;
238173681Sjhb	*lvalp = lval_memory;
239173681Sjhb	target_read_memory(*addrp, valuep, regsz);
240173681Sjhb}
241173681Sjhb
242173681Sjhbstatic const struct frame_unwind kgdb_trgt_dblfault_unwind = {
243173681Sjhb        UNKNOWN_FRAME,
244173681Sjhb        &kgdb_trgt_dblfault_this_id,
245173681Sjhb        &kgdb_trgt_dblfault_prev_register
246173681Sjhb};
247173681Sjhb
248149955Smarcelstruct kgdb_frame_cache {
249183414Skib	int		frame_type;
250149955Smarcel	CORE_ADDR	pc;
251149955Smarcel	CORE_ADDR	sp;
252149955Smarcel};
253183414Skib#define	FT_NORMAL		1
254183414Skib#define	FT_INTRFRAME		2
255183414Skib#define	FT_INTRTRAPFRAME	3
256183414Skib#define	FT_TIMERFRAME		4
257149955Smarcel
258149955Smarcelstatic int kgdb_trgt_frame_offset[15] = {
259149955Smarcel	offsetof(struct trapframe, tf_eax),
260149955Smarcel	offsetof(struct trapframe, tf_ecx),
261149955Smarcel	offsetof(struct trapframe, tf_edx),
262149955Smarcel	offsetof(struct trapframe, tf_ebx),
263149955Smarcel	offsetof(struct trapframe, tf_esp),
264149955Smarcel	offsetof(struct trapframe, tf_ebp),
265149955Smarcel	offsetof(struct trapframe, tf_esi),
266149955Smarcel	offsetof(struct trapframe, tf_edi),
267149955Smarcel	offsetof(struct trapframe, tf_eip),
268149955Smarcel	offsetof(struct trapframe, tf_eflags),
269149955Smarcel	offsetof(struct trapframe, tf_cs),
270149955Smarcel	offsetof(struct trapframe, tf_ss),
271149955Smarcel	offsetof(struct trapframe, tf_ds),
272149955Smarcel	offsetof(struct trapframe, tf_es),
273149955Smarcel	offsetof(struct trapframe, tf_fs)
274149955Smarcel};
275149955Smarcel
276149955Smarcelstatic struct kgdb_frame_cache *
277149955Smarcelkgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
278149955Smarcel{
279149955Smarcel	char buf[MAX_REGISTER_SIZE];
280149955Smarcel	struct kgdb_frame_cache *cache;
281149975Smarcel	char *pname;
282149955Smarcel
283149955Smarcel	cache = *this_cache;
284149955Smarcel	if (cache == NULL) {
285149955Smarcel		cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
286149955Smarcel		*this_cache = cache;
287149955Smarcel		cache->pc = frame_func_unwind(next_frame);
288149975Smarcel		find_pc_partial_function(cache->pc, &pname, NULL, NULL);
289183414Skib		if (pname[0] != 'X')
290183414Skib			cache->frame_type = FT_NORMAL;
291183414Skib		else if (strcmp(pname, "Xtimerint") == 0)
292183414Skib			cache->frame_type = FT_TIMERFRAME;
293183414Skib		else if (strcmp(pname, "Xcpustop") == 0 ||
294183414Skib		    strcmp(pname, "Xrendezvous") == 0 ||
295183414Skib		    strcmp(pname, "Xipi_intr_bitmap_handler") == 0 ||
296183414Skib		    strcmp(pname, "Xlazypmap") == 0)
297183414Skib			cache->frame_type = FT_INTRTRAPFRAME;
298183414Skib		else
299183414Skib			cache->frame_type = FT_INTRFRAME;
300149955Smarcel		frame_unwind_register(next_frame, SP_REGNUM, buf);
301149955Smarcel		cache->sp = extract_unsigned_integer(buf,
302149955Smarcel		    register_size(current_gdbarch, SP_REGNUM));
303149955Smarcel	}
304149955Smarcel	return (cache);
305149955Smarcel}
306149955Smarcel
307149954Smarcelstatic void
308149954Smarcelkgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
309149954Smarcel    struct frame_id *this_id)
310149954Smarcel{
311149955Smarcel	struct kgdb_frame_cache *cache;
312149955Smarcel
313149955Smarcel	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
314149955Smarcel	*this_id = frame_id_build(cache->sp, cache->pc);
315149954Smarcel}
316149954Smarcel
317149954Smarcelstatic void
318149954Smarcelkgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
319149954Smarcel    void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
320149954Smarcel    CORE_ADDR *addrp, int *realnump, void *valuep)
321149954Smarcel{
322149955Smarcel	char dummy_valuep[MAX_REGISTER_SIZE];
323149955Smarcel	struct kgdb_frame_cache *cache;
324149955Smarcel	int ofs, regsz;
325149955Smarcel
326149955Smarcel	regsz = register_size(current_gdbarch, regnum);
327149955Smarcel
328149955Smarcel	if (valuep == NULL)
329149955Smarcel		valuep = dummy_valuep;
330149955Smarcel	memset(valuep, 0, regsz);
331149955Smarcel	*optimizedp = 0;
332149955Smarcel	*addrp = 0;
333149955Smarcel	*lvalp = not_lval;
334149955Smarcel	*realnump = -1;
335149955Smarcel
336149955Smarcel	ofs = (regnum >= I386_EAX_REGNUM && regnum <= I386_FS_REGNUM)
337167143Skib	    ? kgdb_trgt_frame_offset[regnum] + ofs_fix : -1;
338149955Smarcel	if (ofs == -1)
339149955Smarcel		return;
340149955Smarcel
341149955Smarcel	cache = kgdb_trgt_frame_cache(next_frame, this_cache);
342183414Skib	switch (cache->frame_type) {
343183414Skib	case FT_NORMAL:
344183414Skib		break;
345183414Skib	case FT_INTRFRAME:
346183414Skib		ofs += 4;
347183414Skib		break;
348183414Skib	case FT_TIMERFRAME:
349183414Skib		break;
350183414Skib	case FT_INTRTRAPFRAME:
351183414Skib		ofs -= ofs_fix;
352183414Skib		break;
353183414Skib	default:
354183414Skib		fprintf_unfiltered(gdb_stderr, "Correct FT_XXX frame offsets "
355183414Skib		   "for %d\n", cache->frame_type);
356183414Skib		break;
357183414Skib	}
358183414Skib	*addrp = cache->sp + ofs;
359149955Smarcel	*lvalp = lval_memory;
360149955Smarcel	target_read_memory(*addrp, valuep, regsz);
361149954Smarcel}
362149954Smarcel
363149954Smarcelstatic const struct frame_unwind kgdb_trgt_trapframe_unwind = {
364149954Smarcel        UNKNOWN_FRAME,
365149954Smarcel        &kgdb_trgt_trapframe_this_id,
366149954Smarcel        &kgdb_trgt_trapframe_prev_register
367149954Smarcel};
368149954Smarcel
369149954Smarcelconst struct frame_unwind *
370149954Smarcelkgdb_trgt_trapframe_sniffer(struct frame_info *next_frame)
371149954Smarcel{
372149955Smarcel	char *pname;
373149955Smarcel	CORE_ADDR pc;
374149954Smarcel
375149955Smarcel	pc = frame_pc_unwind(next_frame);
376149955Smarcel	pname = NULL;
377149955Smarcel	find_pc_partial_function(pc, &pname, NULL, NULL);
378149955Smarcel	if (pname == NULL)
379149955Smarcel		return (NULL);
380173681Sjhb	if (strcmp(pname, "dblfault_handler") == 0)
381173681Sjhb		return (&kgdb_trgt_dblfault_unwind);
382149975Smarcel	if (strcmp(pname, "calltrap") == 0 ||
383149975Smarcel	    (pname[0] == 'X' && pname[1] != '_'))
384149955Smarcel		return (&kgdb_trgt_trapframe_unwind);
385149955Smarcel	/* printf("%s: %llx =%s\n", __func__, pc, pname); */
386149975Smarcel	return (NULL);
387149954Smarcel}
388