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