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