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