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