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