KObj extension stage I/III
[dragonfly.git] / sys / i386 / i386 / db_interface.c
1 /*
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  *
26  * $FreeBSD: src/sys/i386/i386/db_interface.c,v 1.48.2.1 2000/07/07 00:38:46 obrien Exp $
27  * $DragonFly: src/sys/i386/i386/Attic/db_interface.c,v 1.10 2004/02/21 06:37:07 dillon Exp $
28  */
29
30 /*
31  * Interface to new debugger.
32  */
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/reboot.h>
36 #include <sys/cons.h>
37
38 #include <machine/cpu.h>
39 #include <machine/smp.h>
40 #include <machine/smptests.h>   /** CPUSTOP_ON_DDBBREAK */
41 #include <machine/globaldata.h>
42
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45
46 #include <ddb/ddb.h>
47
48 #include <setjmp.h>
49
50 static jmp_buf *db_nofault = 0;
51 extern jmp_buf  db_jmpbuf;
52
53 extern void     gdb_handle_exception (db_regs_t *, int, int);
54
55 int     db_active;
56 db_regs_t ddb_regs;
57
58 static jmp_buf  db_global_jmpbuf;
59 static int      db_global_jmpbuf_valid;
60
61 #ifdef __GNUC__
62 #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
63 #endif
64
65 #define VERBOSE_CPUSTOP_ON_DDBBREAK
66
67 /*
68  *  kdb_trap - field a TRACE or BPT trap
69  */
70 int
71 kdb_trap(type, code, regs)
72         int     type, code;
73         struct i386_saved_state *regs;
74 {
75         volatile int ddb_mode = !(boothowto & RB_GDB);
76
77         /*
78          * XXX try to do nothing if the console is in graphics mode.
79          * Handle trace traps (and hardware breakpoints...) by ignoring
80          * them except for forgetting about them.  Return 0 for other
81          * traps to say that we haven't done anything.  The trap handler
82          * will usually panic.  We should handle breakpoint traps for
83          * our breakpoints by disarming our breakpoints and fixing up
84          * %eip.
85          */
86         if (cons_unavail && ddb_mode) {
87             if (type == T_TRCTRAP) {
88                 regs->tf_eflags &= ~PSL_T;
89                 return (1);
90             }
91             return (0);
92         }
93
94         switch (type) {
95             case T_BPTFLT:      /* breakpoint */
96             case T_TRCTRAP:     /* debug exception */
97                 break;
98
99             default:
100                 /*
101                  * XXX this is almost useless now.  In most cases,
102                  * trap_fatal() has already printed a much more verbose
103                  * message.  However, it is dangerous to print things in
104                  * trap_fatal() - printf() might be reentered and trap.
105                  * The debugger should be given control first.
106                  */
107                 if (ddb_mode)
108                     db_printf("kernel: type %d trap, code=%x\n", type, code);
109
110                 if (db_nofault) {
111                     jmp_buf *no_fault = db_nofault;
112                     db_nofault = 0;
113                     longjmp(*no_fault, 1);
114                 }
115         }
116
117         /*
118          * This handles unexpected traps in ddb commands, including calls to
119          * non-ddb functions.  db_nofault only applies to memory accesses by
120          * internal ddb commands.
121          */
122         if (db_global_jmpbuf_valid)
123             longjmp(db_global_jmpbuf, 1);
124
125         /*
126          * XXX We really should switch to a local stack here.
127          */
128         ddb_regs = *regs;
129
130         /*
131          * If in kernel mode, esp and ss are not saved, so dummy them up.
132          */
133         if (ISPL(regs->tf_cs) == 0) {
134             ddb_regs.tf_esp = (int)&regs->tf_esp;
135             ddb_regs.tf_ss = rss();
136         }
137
138 #ifdef SMP
139 #ifdef CPUSTOP_ON_DDBBREAK
140
141 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
142         db_printf("\nCPU%d stopping CPUs: 0x%08x\n", 
143             mycpu->gd_cpuid, mycpu->gd_other_cpus);
144 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
145
146         /* We stop all CPUs except ourselves (obviously) */
147         stop_cpus(mycpu->gd_other_cpus);
148
149 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
150         db_printf(" stopped\n");
151 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
152
153 #endif /* CPUSTOP_ON_DDBBREAK */
154 #endif /* SMP */
155
156         (void) setjmp(db_global_jmpbuf);
157         db_global_jmpbuf_valid = TRUE;
158         db_active++;
159         if (ddb_mode) {
160             cndbctl(TRUE);
161             db_trap(type, code);
162             cndbctl(FALSE);
163         } else
164             gdb_handle_exception(&ddb_regs, type, code);
165         db_active--;
166         db_global_jmpbuf_valid = FALSE;
167
168 #ifdef SMP
169 #ifdef CPUSTOP_ON_DDBBREAK
170
171 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
172         db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
173             mycpu->gd_cpuid, stopped_cpus);
174 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
175
176         /* Restart all the CPUs we previously stopped */
177         if (stopped_cpus != mycpu->gd_other_cpus) {
178                 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
179                           mycpu->gd_other_cpus, stopped_cpus);
180                 panic("stop_cpus() failed");
181         }
182         restart_cpus(stopped_cpus);
183
184 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
185         db_printf(" restarted\n");
186 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
187
188 #endif /* CPUSTOP_ON_DDBBREAK */
189 #endif /* SMP */
190
191         regs->tf_eip    = ddb_regs.tf_eip;
192         regs->tf_eflags = ddb_regs.tf_eflags;
193         regs->tf_eax    = ddb_regs.tf_eax;
194         regs->tf_ecx    = ddb_regs.tf_ecx;
195         regs->tf_edx    = ddb_regs.tf_edx;
196         regs->tf_ebx    = ddb_regs.tf_ebx;
197
198         /*
199          * If in user mode, the saved ESP and SS were valid, restore them.
200          */
201         if (ISPL(regs->tf_cs)) {
202             regs->tf_esp = ddb_regs.tf_esp;
203             regs->tf_ss  = ddb_regs.tf_ss & 0xffff;
204         }
205
206         regs->tf_ebp    = ddb_regs.tf_ebp;
207         regs->tf_esi    = ddb_regs.tf_esi;
208         regs->tf_edi    = ddb_regs.tf_edi;
209         regs->tf_es     = ddb_regs.tf_es & 0xffff;
210         regs->tf_fs     = ddb_regs.tf_fs & 0xffff;
211         regs->tf_cs     = ddb_regs.tf_cs & 0xffff;
212         regs->tf_ds     = ddb_regs.tf_ds & 0xffff;
213         return (1);
214 }
215
216 /*
217  * Read bytes from kernel address space for debugger.
218  */
219 void
220 db_read_bytes(addr, size, data)
221         vm_offset_t     addr;
222         size_t  size;
223         char    *data;
224 {
225         char    *src;
226
227         db_nofault = &db_jmpbuf;
228
229         src = (char *)addr;
230         while (size-- > 0)
231             *data++ = *src++;
232
233         db_nofault = 0;
234 }
235
236 /*
237  * Write bytes to kernel address space for debugger.
238  */
239 void
240 db_write_bytes(addr, size, data)
241         vm_offset_t     addr;
242         size_t  size;
243         char    *data;
244 {
245         char    *dst;
246
247         unsigned        *ptep0 = NULL;
248         unsigned        oldmap0 = 0;
249         vm_offset_t     addr1;
250         unsigned        *ptep1 = NULL;
251         unsigned        oldmap1 = 0;
252
253         db_nofault = &db_jmpbuf;
254
255         if (addr > trunc_page((vm_offset_t)btext) - size &&
256             addr < round_page((vm_offset_t)etext)) {
257
258             ptep0 = pmap_pte(kernel_pmap, addr);
259             oldmap0 = *ptep0;
260             *ptep0 |= PG_RW;
261
262             /* Map another page if the data crosses a page boundary. */
263             if ((*ptep0 & PG_PS) == 0) {
264                 addr1 = trunc_page(addr + size - 1);
265                 if (trunc_page(addr) != addr1) {
266                     ptep1 = pmap_pte(kernel_pmap, addr1);
267                     oldmap1 = *ptep1;
268                     *ptep1 |= PG_RW;
269                 }
270             } else {
271                 addr1 = trunc_4mpage(addr + size - 1);
272                 if (trunc_4mpage(addr) != addr1) {
273                     ptep1 = pmap_pte(kernel_pmap, addr1);
274                     oldmap1 = *ptep1;
275                     *ptep1 |= PG_RW;
276                 }
277             }
278
279             cpu_invltlb();
280         }
281
282         dst = (char *)addr;
283
284         while (size-- > 0)
285             *dst++ = *data++;
286
287         db_nofault = 0;
288
289         if (ptep0) {
290             *ptep0 = oldmap0;
291
292             if (ptep1)
293                 *ptep1 = oldmap1;
294
295             cpu_invltlb();
296         }
297 }
298
299 /*
300  * The debugger sometimes needs to know the actual KVM address represented
301  * by the instruction pointer, stack pointer, or base pointer.  Normally
302  * the actual KVM address is simply the contents of the register.  However,
303  * if the debugger is entered from the BIOS or VM86 we need to figure out
304  * the offset from the segment register.
305  */
306 db_addr_t
307 PC_REGS(db_regs_t *regs)
308 {
309     struct soft_segment_descriptor softseg;
310
311     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_cs & 0xffff)].sd, &softseg);
312     return(regs->tf_eip + softseg.ssd_base);
313 }
314
315 db_addr_t
316 SP_REGS(db_regs_t *regs)
317 {
318     struct soft_segment_descriptor softseg;
319
320     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ss & 0xffff)].sd, &softseg);
321     return(regs->tf_esp + softseg.ssd_base);
322 }
323
324 db_addr_t
325 BP_REGS(db_regs_t *regs)
326 {
327     struct soft_segment_descriptor softseg;
328
329     sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ds & 0xffff)].sd, &softseg);
330     return(regs->tf_ebp + softseg.ssd_base);
331 }
332
333 /*
334  * XXX
335  * Move this to machdep.c and allow it to be called if any debugger is
336  * installed.
337  */
338 void
339 Debugger(msg)
340         const char *msg;
341 {
342         static volatile u_char in_Debugger;
343
344         /*
345          * XXX
346          * Do nothing if the console is in graphics mode.  This is
347          * OK if the call is for the debugger hotkey but not if the call
348          * is a weak form of panicing.
349          */
350         if (cons_unavail && !(boothowto & RB_GDB))
351             return;
352
353         if (!in_Debugger) {
354             in_Debugger = 1;
355             db_printf("Debugger(\"%s\")\n", msg);
356             breakpoint();
357             in_Debugger = 0;
358         }
359 }