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>
| 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: head/sys/i386/i386/db_interface.c 127813 2004-04-03 22:23:36Z marcel $");
| 28__FBSDID("$FreeBSD: head/sys/i386/i386/db_interface.c 131952 2004-07-10 23:47:20Z marcel $");
|
29 30/* 31 * Interface to new debugger. 32 */ 33#include <sys/param.h> 34#include <sys/systm.h>
| 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>
| 35#include <sys/cons.h>
|
| 36#include <sys/kdb.h>
|
37#include <sys/pcpu.h> 38#include <sys/proc.h>
| 37#include <sys/pcpu.h> 38#include <sys/proc.h>
|
39#include <sys/smp.h>
| |
40 41#include <machine/cpu.h>
| 39 40#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
| 41 42#include <vm/vm.h> 43#include <vm/pmap.h> 44 45#include <ddb/ddb.h> 46
|
51#include <machine/setjmp.h> 52 53static jmp_buf *db_nofault = 0; 54extern jmp_buf db_jmpbuf; 55 56extern void gdb_handle_exception(db_regs_t *, int, int); 57 58int db_active; 59db_regs_t ddb_regs; 60 61static jmp_buf db_global_jmpbuf; 62
| |
63/*
| 47/*
|
64 * kdb_trap - field a TRACE or BPT trap
| 48 * Read bytes from kernel address space for debugger.
|
65 */ 66int
| 49 */ 50int
|
67kdb_trap(int type, int code, struct i386_saved_state *regs)
| 51db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
68{
| 52{
|
69 u_int ef; 70 volatile int ddb_mode = !(boothowto & RB_GDB);
| 53 jmp_buf jb; 54 void *prev_jb; 55 char *src; 56 int ret;
|
71
| 57
|
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);
| 58 prev_jb = kdb_jmpbuf(jb); 59 ret = setjmp(jb); 60 if (ret == 0) { 61 src = (char *)addr; 62 while (size-- > 0) 63 *data++ = *src++;
|
87 }
| 64 }
|
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)®s->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);
| 65 (void)kdb_jmpbuf(prev_jb); 66 return (ret);
|
216} 217 218/*
| 67} 68 69/*
|
219 * Read bytes from kernel address space for debugger. 220 */ 221void 222db_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 */
| 70 * Write bytes to kernel address space for debugger. 71 */
|
238void
| 72int
|
239db_write_bytes(vm_offset_t addr, size_t size, char *data) 240{
| 73db_write_bytes(vm_offset_t addr, size_t size, char *data) 74{
|
241 char *dst;
| 75 jmp_buf jb; 76 void *prev_jb; 77 char *dst; 78 pt_entry_t *ptep0 = NULL; 79 pt_entry_t oldmap0 = 0; 80 vm_offset_t addr1; 81 pt_entry_t *ptep1 = NULL; 82 pt_entry_t oldmap1 = 0; 83 int ret;
|
242
| 84
|
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;
| 85 prev_jb = kdb_jmpbuf(jb); 86 ret = setjmp(jb); 87 if (ret == 0) { 88 if (addr > trunc_page((vm_offset_t)btext) - size && 89 addr < round_page((vm_offset_t)etext)) {
|
248
| 90
|
249 db_nofault = &db_jmpbuf;
| 91 ptep0 = pmap_pte(kernel_pmap, addr); 92 oldmap0 = *ptep0; 93 *ptep0 |= PG_RW;
|
250
| 94
|
251 if (addr > trunc_page((vm_offset_t)btext) - size && 252 addr < round_page((vm_offset_t)etext)) {
| 95 /* 96 * Map another page if the data crosses a page 97 * boundary. 98 */ 99 if ((*ptep0 & PG_PS) == 0) { 100 addr1 = trunc_page(addr + size - 1); 101 if (trunc_page(addr) != addr1) { 102 ptep1 = pmap_pte(kernel_pmap, addr1); 103 oldmap1 = *ptep1; 104 *ptep1 |= PG_RW; 105 } 106 } else { 107 addr1 = trunc_4mpage(addr + size - 1); 108 if (trunc_4mpage(addr) != addr1) { 109 ptep1 = pmap_pte(kernel_pmap, addr1); 110 oldmap1 = *ptep1; 111 *ptep1 |= PG_RW; 112 } 113 }
|
253
| 114
|
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;
| 115 invltlb();
|
272 }
| 116 }
|
273 }
| |
274
| 117
|
275 invltlb();
| 118 dst = (char *)addr; 119 120 while (size-- > 0) 121 *dst++ = *data++;
|
276 } 277
| 122 } 123
|
278 dst = (char *)addr;
| 124 (void)kdb_jmpbuf(prev_jb);
|
279
| 125
|
280 while (size-- > 0) 281 *dst++ = *data++; 282 283 db_nofault = 0; 284
| |
285 if (ptep0) {
| 126 if (ptep0) {
|
286 *ptep0 = oldmap0;
| 127 *ptep0 = oldmap0;
|
287
| 128
|
288 if (ptep1) 289 *ptep1 = oldmap1;
| 129 if (ptep1) 130 *ptep1 = oldmap1;
|
290
| 131
|
291 invltlb();
| 132 invltlb();
|
292 }
| 133 }
|
293}
| |
294
| 134
|
295/* 296 * XXX 297 * Move this to machdep.c and allow it to be called if any debugger is 298 * installed. 299 */ 300void 301Debugger(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 }
| 135 return (ret);
|
319} 320 321void 322db_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}
| 136} 137 138void 139db_show_mdpcpu(struct pcpu *pc) 140{ 141 142 db_printf("APIC ID = %d\n", pc->pc_apic_id); 143 db_printf("currentldt = 0x%x\n", pc->pc_currentldt); 144}
|