]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/usr.bin/gdb/kgdb/trgt_i386.c
MFV r353551: 10452 ZoL: merge in large dnode feature fixes
[FreeBSD/FreeBSD.git] / gnu / usr.bin / gdb / kgdb / trgt_i386.c
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
52 static int ofs_fix;
53
54 CORE_ADDR
55 kgdb_trgt_core_pcb(u_int cpuid)
56 {
57         return (kgdb_trgt_stop_pcb(cpuid, sizeof(struct pcb)));
58 }
59
60 void
61 kgdb_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
81 void
82 kgdb_trgt_store_registers(int regno __unused)
83 {
84         fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__);
85 }
86
87 void
88 kgdb_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
104 struct kgdb_tss_cache {
105         CORE_ADDR       pc;
106         CORE_ADDR       sp;
107         CORE_ADDR       tss;
108 };
109
110 static 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  */
136 static CORE_ADDR
137 kgdb_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
183 static struct kgdb_tss_cache *
184 kgdb_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
202 static void
203 kgdb_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
212 static void
213 kgdb_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
244 static 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
250 struct 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
260 static 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
278 static struct kgdb_frame_cache *
279 kgdb_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
323 static void
324 kgdb_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
333 static void
334 kgdb_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
379 static 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
385 const struct frame_unwind *
386 kgdb_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  */
413 int
414 kgdb_trgt_pc_fixup(CORE_ADDR *pc __unused)
415 {
416
417         return (-1);
418 }