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