2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
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.
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.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 * Interface to new debugger.
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/reboot.h>
41 #include <machine/cpu.h>
43 #include <machine/smptests.h> /** CPUSTOP_ON_DDBBREAK */
51 #include <machine/setjmp.h>
53 static jmp_buf *db_nofault = 0;
54 extern jmp_buf db_jmpbuf;
56 extern void gdb_handle_exception(db_regs_t *, int, int);
61 static jmp_buf db_global_jmpbuf;
64 * kdb_trap - field a TRACE or BPT trap
67 kdb_trap(int type, int code, struct i386_saved_state *regs)
70 volatile int ddb_mode = !(boothowto & RB_GDB);
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
81 if (cnunavailable() != 0 && ddb_mode) {
82 if (type == T_TRCTRAP) {
83 regs->tf_eflags &= ~PSL_T;
93 #ifdef CPUSTOP_ON_DDBBREAK
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 */
100 /* We stop all CPUs except ourselves (obviously) */
101 stop_cpus(PCPU_GET(other_cpus));
103 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
104 db_printf(" stopped.\n");
105 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
107 #endif /* CPUSTOP_ON_DDBBREAK */
111 case T_BPTFLT: /* breakpoint */
112 case T_TRCTRAP: /* debug exception */
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.
124 db_printf("kernel: type %d trap, code=%x\n", type, code);
127 jmp_buf *no_fault = db_nofault;
129 longjmp(*no_fault, 1);
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.
139 longjmp(db_global_jmpbuf, 1);
142 * XXX We really should switch to a local stack here.
147 * If in kernel mode, esp and ss are not saved, so dummy them up.
149 if (ISPL(regs->tf_cs) == 0) {
150 ddb_regs.tf_esp = (int)®s->tf_esp;
151 ddb_regs.tf_ss = rss();
154 (void) setjmp(db_global_jmpbuf);
163 gdb_handle_exception(&ddb_regs, type, code);
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;
175 * If in user mode, the saved ESP and SS were valid, restore them.
177 if (ISPL(regs->tf_cs)) {
178 regs->tf_esp = ddb_regs.tf_esp;
179 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
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;
191 #ifdef CPUSTOP_ON_DDBBREAK
193 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
194 db_printf("\nCPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid),
196 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
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");
204 restart_cpus(stopped_cpus);
206 #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
207 db_printf(" restarted.\n");
208 #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
210 #endif /* CPUSTOP_ON_DDBBREAK */
219 * Read bytes from kernel address space for debugger.
222 db_read_bytes(vm_offset_t addr, size_t size, char *data)
226 db_nofault = &db_jmpbuf;
236 * Write bytes to kernel address space for debugger.
239 db_write_bytes(vm_offset_t addr, size_t size, char *data)
243 pt_entry_t *ptep0 = NULL;
244 pt_entry_t oldmap0 = 0;
246 pt_entry_t *ptep1 = NULL;
247 pt_entry_t oldmap1 = 0;
249 db_nofault = &db_jmpbuf;
251 if (addr > trunc_page((vm_offset_t)btext) - size &&
252 addr < round_page((vm_offset_t)etext)) {
254 ptep0 = pmap_pte(kernel_pmap, addr);
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);
267 addr1 = trunc_4mpage(addr + size - 1);
268 if (trunc_4mpage(addr) != addr1) {
269 ptep1 = pmap_pte(kernel_pmap, addr1);
297 * Move this to machdep.c and allow it to be called if any debugger is
301 Debugger(const char *msg)
303 static volatile u_int in_Debugger;
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.
311 if (cnunavailable() != 0 && !(boothowto & RB_GDB))
314 if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) {
315 db_printf("Debugger(\"%s\")\n", msg);
317 atomic_store_rel_int(&in_Debugger, 0);
322 db_show_mdpcpu(struct pcpu *pc)
325 db_printf("APIC ID = %d\n", pc->pc_apic_id);
326 db_printf("currentldt = 0x%x\n", pc->pc_currentldt);