kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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.5 2003/07/26 19:07:47 rob 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 #ifdef SMP
40 #include <machine/smp.h>
41 #include <machine/smptests.h>   /** CPUSTOP_ON_DDBBREAK */
42 #endif
43 #include <machine/globaldata.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 #include <ddb/ddb.h>
49
50 #include <setjmp.h>
51
52 static jmp_buf *db_nofault = 0;
53 extern jmp_buf  db_jmpbuf;
54
55 extern void     gdb_handle_exception __P((db_regs_t *, int, int));
56
57 int     db_active;
58 db_regs_t ddb_regs;
59
60 static jmp_buf  db_global_jmpbuf;
61 static int      db_global_jmpbuf_valid;
62
63 #ifdef __GNUC__
64 #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
65 #endif
66
67 #define VERBOSE_CPUSTOP_ON_DDBBREAK
68
69 /*
70  *  kdb_trap - field a TRACE or BPT trap
71  */
72 int
73 kdb_trap(type, code, regs)
74         int     type, code;
75         struct i386_saved_state *regs;
76 {
77         volatile int ddb_mode = !(boothowto & RB_GDB);
78
79         /*
80          * XXX try to do nothing if the console is in graphics mode.
81          * Handle trace traps (and hardware breakpoints...) by ignoring
82          * them except for forgetting about them.  Return 0 for other
83          * traps to say that we haven't done anything.  The trap handler
84          * will usually panic.  We should handle breakpoint traps for
85          * our breakpoints by disarming our breakpoints and fixing up
86          * %eip.
87          */
88         if (cons_unavail && ddb_mode) {
89             if (type == T_TRCTRAP) {
90                 regs->tf_eflags &= ~PSL_T;
91                 return (1);
92             }
93             return (0);
94         }
95
96         switch (type) {
97             case T_BPTFLT:      /* breakpoint */
98             case T_TRCTRAP:     /* debug exception */
99                 break;
100
101             default:
102                 /*
103                  * XXX this is almost useless now.  In most cases,
104                  * trap_fatal() has already printed a much more verbose
105                  * message.  However, it is dangerous to print things in
106                  * trap_fatal() - printf() might be reentered and trap.
107                  * The debugger should be given control first.
108                  */
109                 if (ddb_mode)
110                     db_printf("kernel: type %d trap, code=%x\n", type, code);
111
112                 if (db_nofault) {
113                     jmp_buf *no_fault = db_nofault;
114                     db_nofault = 0;
115                     longjmp(*no_fault, 1);
116                 }
117         }
118
119         /*
120          * This handles unexpected traps in ddb commands, including calls to
121          * non-ddb functions.  db_nofault only applies to memory accesses by
122          * internal ddb commands.
123          */
124         if (db_global_jmpbuf_valid)
125             longjmp(db_global_jmpbuf, 1);
126
127         /*
128          * XXX We really should switch to a local stack here.
129          */
130         ddb_regs = *regs;
131
132         /*
133          * If in kernel mode, esp and ss are not saved, so dummy them up.
134          */
135         if (ISPL(regs->tf_cs) == 0) {
136             ddb_regs.tf_esp = (int)&regs->tf_esp;
137             ddb_regs.tf_ss = rss();
138         }
139
140 #ifdef SMP
141 #ifdef CPUSTOP_ON_DDBBREAK
142
143 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
144         db_printf("\nCPU%d stopping CPUs: 0x%08x\n", 
145             mycpu->gd_cpuid, mycpu->gd_other_cpus);
146 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
147
148         /* We stop all CPUs except ourselves (obviously) */
149         stop_cpus(mycpu->gd_other_cpus);
150
151 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
152         db_printf(" stopped\n");
153 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
154
155 #endif /* CPUSTOP_ON_DDBBREAK */
156 #endif /* SMP */
157
158         (void) setjmp(db_global_jmpbuf);
159         db_global_jmpbuf_valid = TRUE;
160         db_active++;
161         if (ddb_mode) {
162             cndbctl(TRUE);
163             db_trap(type, code);
164             cndbctl(FALSE);
165         } else
166             gdb_handle_exception(&ddb_regs, type, code);
167         db_active--;
168         db_global_jmpbuf_valid = FALSE;
169
170 #ifdef SMP
171 #ifdef CPUSTOP_ON_DDBBREAK
172
173 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
174         db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
175             mycpu->gd_cpuid, stopped_cpus);
176 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
177
178         /* Restart all the CPUs we previously stopped */
179         if (stopped_cpus != mycpu->gd_other_cpus && smp_started != 0) {
180                 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
181                           mycpu->gd_other_cpus, stopped_cpus);
182                 panic("stop_cpus() failed");
183         }
184         restart_cpus(stopped_cpus);
185
186 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
187         db_printf(" restarted\n");
188 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
189
190 #endif /* CPUSTOP_ON_DDBBREAK */
191 #endif /* SMP */
192
193         regs->tf_eip    = ddb_regs.tf_eip;
194         regs->tf_eflags = ddb_regs.tf_eflags;
195         regs->tf_eax    = ddb_regs.tf_eax;
196         regs->tf_ecx    = ddb_regs.tf_ecx;
197         regs->tf_edx    = ddb_regs.tf_edx;
198         regs->tf_ebx    = ddb_regs.tf_ebx;
199
200         /*
201          * If in user mode, the saved ESP and SS were valid, restore them.
202          */
203         if (ISPL(regs->tf_cs)) {
204             regs->tf_esp = ddb_regs.tf_esp;
205             regs->tf_ss  = ddb_regs.tf_ss & 0xffff;
206         }
207
208         regs->tf_ebp    = ddb_regs.tf_ebp;
209         regs->tf_esi    = ddb_regs.tf_esi;
210         regs->tf_edi    = ddb_regs.tf_edi;
211         regs->tf_es     = ddb_regs.tf_es & 0xffff;
212         regs->tf_fs     = ddb_regs.tf_fs & 0xffff;
213         regs->tf_cs     = ddb_regs.tf_cs & 0xffff;
214         regs->tf_ds     = ddb_regs.tf_ds & 0xffff;
215         return (1);
216 }
217
218 /*
219  * Read bytes from kernel address space for debugger.
220  */
221 void
222 db_read_bytes(addr, size, data)
223         vm_offset_t     addr;
224         size_t  size;
225         char    *data;
226 {
227         char    *src;
228
229         db_nofault = &db_jmpbuf;
230
231         src = (char *)addr;
232         while (size-- > 0)
233             *data++ = *src++;
234
235         db_nofault = 0;
236 }
237
238 /*
239  * Write bytes to kernel address space for debugger.
240  */
241 void
242 db_write_bytes(addr, size, data)
243         vm_offset_t     addr;
244         size_t  size;
245         char    *data;
246 {
247         char    *dst;
248
249         unsigned        *ptep0 = NULL;
250         unsigned        oldmap0 = 0;
251         vm_offset_t     addr1;
252         unsigned        *ptep1 = NULL;
253         unsigned        oldmap1 = 0;
254
255         db_nofault = &db_jmpbuf;
256
257         if (addr > trunc_page((vm_offset_t)btext) - size &&
258             addr < round_page((vm_offset_t)etext)) {
259
260             ptep0 = pmap_pte(kernel_pmap, addr);
261             oldmap0 = *ptep0;
262             *ptep0 |= PG_RW;
263
264             /* Map another page if the data crosses a page boundary. */
265             if ((*ptep0 & PG_PS) == 0) {
266                 addr1 = trunc_page(addr + size - 1);
267                 if (trunc_page(addr) != addr1) {
268                     ptep1 = pmap_pte(kernel_pmap, addr1);
269                     oldmap1 = *ptep1;
270                     *ptep1 |= PG_RW;
271                 }
272             } else {
273                 addr1 = trunc_4mpage(addr + size - 1);
274                 if (trunc_4mpage(addr) != addr1) {
275                     ptep1 = pmap_pte(kernel_pmap, addr1);
276                     oldmap1 = *ptep1;
277                     *ptep1 |= PG_RW;
278                 }
279             }
280
281             invltlb();
282         }
283
284         dst = (char *)addr;
285
286         while (size-- > 0)
287             *dst++ = *data++;
288
289         db_nofault = 0;
290
291         if (ptep0) {
292             *ptep0 = oldmap0;
293
294             if (ptep1)
295                 *ptep1 = oldmap1;
296
297             invltlb();
298         }
299 }
300
301 /*
302  * XXX
303  * Move this to machdep.c and allow it to be called if any debugger is
304  * installed.
305  */
306 void
307 Debugger(msg)
308         const char *msg;
309 {
310         static volatile u_char in_Debugger;
311
312         /*
313          * XXX
314          * Do nothing if the console is in graphics mode.  This is
315          * OK if the call is for the debugger hotkey but not if the call
316          * is a weak form of panicing.
317          */
318         if (cons_unavail && !(boothowto & RB_GDB))
319             return;
320
321         if (!in_Debugger) {
322             in_Debugger = 1;
323             db_printf("Debugger(\"%s\")\n", msg);
324             breakpoint();
325             in_Debugger = 0;
326         }
327 }