10e6594a8SSascha Wildner /* 20e6594a8SSascha Wildner * Copyright (c) 2008 The DragonFly Project. All rights reserved. 30e6594a8SSascha Wildner * 40e6594a8SSascha Wildner * Redistribution and use in source and binary forms, with or without 50e6594a8SSascha Wildner * modification, are permitted provided that the following conditions 60e6594a8SSascha Wildner * are met: 70e6594a8SSascha Wildner * 80e6594a8SSascha Wildner * 1. Redistributions of source code must retain the above copyright 90e6594a8SSascha Wildner * notice, this list of conditions and the following disclaimer. 100e6594a8SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 110e6594a8SSascha Wildner * notice, this list of conditions and the following disclaimer in 120e6594a8SSascha Wildner * the documentation and/or other materials provided with the 130e6594a8SSascha Wildner * distribution. 140e6594a8SSascha Wildner * 3. Neither the name of The DragonFly Project nor the names of its 150e6594a8SSascha Wildner * contributors may be used to endorse or promote products derived 160e6594a8SSascha Wildner * from this software without specific, prior written permission. 170e6594a8SSascha Wildner * 180e6594a8SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 190e6594a8SSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 200e6594a8SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 210e6594a8SSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 220e6594a8SSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 230e6594a8SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 240e6594a8SSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 250e6594a8SSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 260e6594a8SSascha Wildner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 270e6594a8SSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 280e6594a8SSascha Wildner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290e6594a8SSascha Wildner * SUCH DAMAGE. 300e6594a8SSascha Wildner * 310e6594a8SSascha Wildner * -- 320e6594a8SSascha Wildner * 330e6594a8SSascha Wildner * Mach Operating System 340e6594a8SSascha Wildner * Copyright (c) 1991,1990 Carnegie Mellon University 350e6594a8SSascha Wildner * All Rights Reserved. 360e6594a8SSascha Wildner * 370e6594a8SSascha Wildner * Permission to use, copy, modify and distribute this software and its 380e6594a8SSascha Wildner * documentation is hereby granted, provided that both the copyright 390e6594a8SSascha Wildner * notice and this permission notice appear in all copies of the 400e6594a8SSascha Wildner * software, derivative works or modified versions, and any portions 410e6594a8SSascha Wildner * thereof, and that both notices appear in supporting documentation. 420e6594a8SSascha Wildner * 430e6594a8SSascha Wildner * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 440e6594a8SSascha Wildner * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 450e6594a8SSascha Wildner * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 460e6594a8SSascha Wildner * 470e6594a8SSascha Wildner * Carnegie Mellon requests users of this software to return to 480e6594a8SSascha Wildner * 490e6594a8SSascha Wildner * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 500e6594a8SSascha Wildner * School of Computer Science 510e6594a8SSascha Wildner * Carnegie Mellon University 520e6594a8SSascha Wildner * Pittsburgh PA 15213-3890 530e6594a8SSascha Wildner * 540e6594a8SSascha Wildner * any improvements or extensions that they make and grant Carnegie the 550e6594a8SSascha Wildner * rights to redistribute these changes. 560e6594a8SSascha Wildner * 570e6594a8SSascha Wildner * $FreeBSD: src/sys/i386/i386/db_interface.c,v 1.48.2.1 2000/07/07 00:38:46 obrien Exp $ 580e6594a8SSascha Wildner */ 590e6594a8SSascha Wildner 600e6594a8SSascha Wildner /* 610e6594a8SSascha Wildner * Interface to new debugger. 620e6594a8SSascha Wildner */ 630e6594a8SSascha Wildner #include <sys/param.h> 640e6594a8SSascha Wildner #include <sys/systm.h> 650e6594a8SSascha Wildner #include <sys/reboot.h> 660e6594a8SSascha Wildner #include <sys/cons.h> 670e6594a8SSascha Wildner #include <sys/thread.h> 680e6594a8SSascha Wildner 690e6594a8SSascha Wildner #include <machine/cpu.h> 700e6594a8SSascha Wildner #include <machine/smp.h> 710e6594a8SSascha Wildner #include <machine/globaldata.h> 720e6594a8SSascha Wildner #include <machine/md_var.h> 730e6594a8SSascha Wildner 740e6594a8SSascha Wildner #include <vm/vm.h> 750e6594a8SSascha Wildner #include <vm/pmap.h> 760e6594a8SSascha Wildner 770e6594a8SSascha Wildner #include <ddb/ddb.h> 780e6594a8SSascha Wildner 790e6594a8SSascha Wildner #include <sys/thread2.h> 800e6594a8SSascha Wildner 810e6594a8SSascha Wildner #include <setjmp.h> 820e6594a8SSascha Wildner 834090d6ffSSascha Wildner static jmp_buf *db_nofault = NULL; 840e6594a8SSascha Wildner extern jmp_buf db_jmpbuf; 850e6594a8SSascha Wildner 860e6594a8SSascha Wildner extern void gdb_handle_exception (db_regs_t *, int, int); 870e6594a8SSascha Wildner 880e6594a8SSascha Wildner int db_active; 890e6594a8SSascha Wildner db_regs_t ddb_regs; 900e6594a8SSascha Wildner 910e6594a8SSascha Wildner static jmp_buf db_global_jmpbuf; 920e6594a8SSascha Wildner static int db_global_jmpbuf_valid; 930e6594a8SSascha Wildner 940e6594a8SSascha Wildner #ifdef __GNUC__ 950e6594a8SSascha Wildner #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;}) 960e6594a8SSascha Wildner #endif 970e6594a8SSascha Wildner 980e6594a8SSascha Wildner /* 990e6594a8SSascha Wildner * kdb_trap - field a TRACE or BPT trap 1000e6594a8SSascha Wildner */ 1010e6594a8SSascha Wildner int 1020e6594a8SSascha Wildner kdb_trap(int type, int code, struct x86_64_saved_state *regs) 1030e6594a8SSascha Wildner { 1040e6594a8SSascha Wildner volatile int ddb_mode = !(boothowto & RB_GDB); 1050e6594a8SSascha Wildner 1060e6594a8SSascha Wildner /* 1070e6594a8SSascha Wildner * XXX try to do nothing if the console is in graphics mode. 1080e6594a8SSascha Wildner * Handle trace traps (and hardware breakpoints...) by ignoring 1090e6594a8SSascha Wildner * them except for forgetting about them. Return 0 for other 1100e6594a8SSascha Wildner * traps to say that we haven't done anything. The trap handler 1110e6594a8SSascha Wildner * will usually panic. We should handle breakpoint traps for 1120e6594a8SSascha Wildner * our breakpoints by disarming our breakpoints and fixing up 1130e6594a8SSascha Wildner * %eip. 1140e6594a8SSascha Wildner */ 1150e6594a8SSascha Wildner if (cons_unavail && ddb_mode) { 1160e6594a8SSascha Wildner if (type == T_TRCTRAP) { 1170e6594a8SSascha Wildner regs->tf_rflags &= ~PSL_T; 1180e6594a8SSascha Wildner return (1); 1190e6594a8SSascha Wildner } 1200e6594a8SSascha Wildner return (0); 1210e6594a8SSascha Wildner } 1220e6594a8SSascha Wildner 1230e6594a8SSascha Wildner switch (type) { 1240e6594a8SSascha Wildner case T_BPTFLT: /* breakpoint */ 1250e6594a8SSascha Wildner case T_TRCTRAP: /* debug exception */ 1260e6594a8SSascha Wildner break; 1270e6594a8SSascha Wildner 1280e6594a8SSascha Wildner default: 1290e6594a8SSascha Wildner /* 1300e6594a8SSascha Wildner * XXX this is almost useless now. In most cases, 1310e6594a8SSascha Wildner * trap_fatal() has already printed a much more verbose 1320e6594a8SSascha Wildner * message. However, it is dangerous to print things in 1330e6594a8SSascha Wildner * trap_fatal() - kprintf() might be reentered and trap. 1340e6594a8SSascha Wildner * The debugger should be given control first. 1350e6594a8SSascha Wildner */ 1360e6594a8SSascha Wildner if (ddb_mode) 1370e6594a8SSascha Wildner db_printf("kernel: type %d trap, code=%x\n", type, code); 1380e6594a8SSascha Wildner 1390e6594a8SSascha Wildner if (db_nofault) { 1400e6594a8SSascha Wildner jmp_buf *no_fault = db_nofault; 1414090d6ffSSascha Wildner db_nofault = NULL; 1420e6594a8SSascha Wildner longjmp(*no_fault, 1); 1430e6594a8SSascha Wildner } 1440e6594a8SSascha Wildner } 1450e6594a8SSascha Wildner 1460e6594a8SSascha Wildner /* 1470e6594a8SSascha Wildner * This handles unexpected traps in ddb commands, including calls to 1480e6594a8SSascha Wildner * non-ddb functions. db_nofault only applies to memory accesses by 1490e6594a8SSascha Wildner * internal ddb commands. 1500e6594a8SSascha Wildner */ 1510e6594a8SSascha Wildner if (db_global_jmpbuf_valid) 1520e6594a8SSascha Wildner longjmp(db_global_jmpbuf, 1); 1530e6594a8SSascha Wildner 1540e6594a8SSascha Wildner /* 1550e6594a8SSascha Wildner * XXX We really should switch to a local stack here. 1560e6594a8SSascha Wildner */ 1570e6594a8SSascha Wildner ddb_regs = *regs; 1580e6594a8SSascha Wildner 1590e6594a8SSascha Wildner crit_enter(); 160b6bf0651SMatthew Dillon db_printf("\nCPU%d stopping CPUs: 0x%016jx\n", 161*1ad93419SNuno Antunes mycpu->gd_cpuid, (uintmax_t)CPUMASK_LOWMASK(mycpu->gd_other_cpus)); 1620e6594a8SSascha Wildner 1630e6594a8SSascha Wildner /* We stop all CPUs except ourselves (obviously) */ 1640e6594a8SSascha Wildner stop_cpus(mycpu->gd_other_cpus); 1650e6594a8SSascha Wildner 1660e6594a8SSascha Wildner db_printf(" stopped\n"); 1670e6594a8SSascha Wildner 1680e6594a8SSascha Wildner setjmp(db_global_jmpbuf); 1690e6594a8SSascha Wildner db_global_jmpbuf_valid = TRUE; 1700e6594a8SSascha Wildner db_active++; 1710e6594a8SSascha Wildner vcons_set_mode(1); 1720e6594a8SSascha Wildner if (ddb_mode) { 1730e6594a8SSascha Wildner cndbctl(TRUE); 1740e6594a8SSascha Wildner db_trap(type, code); 1750e6594a8SSascha Wildner cndbctl(FALSE); 1760e6594a8SSascha Wildner } else 1770e6594a8SSascha Wildner gdb_handle_exception(&ddb_regs, type, code); 1780e6594a8SSascha Wildner db_active--; 1790e6594a8SSascha Wildner vcons_set_mode(0); 1800e6594a8SSascha Wildner db_global_jmpbuf_valid = FALSE; 1810e6594a8SSascha Wildner 182da23a592SMatthew Dillon db_printf("\nCPU%d restarting CPUs: 0x%016jx\n", 183*1ad93419SNuno Antunes mycpu->gd_cpuid, (uintmax_t)CPUMASK_LOWMASK(stopped_cpus)); 1840e6594a8SSascha Wildner 1850e6594a8SSascha Wildner /* Restart all the CPUs we previously stopped */ 186*1ad93419SNuno Antunes if (CPUMASK_CMPMASKNEQ(stopped_cpus, mycpu->gd_other_cpus)) { 187b6bf0651SMatthew Dillon db_printf("whoa, other_cpus: 0x%016jx, " 188b6bf0651SMatthew Dillon "stopped_cpus: 0x%016jx\n", 189*1ad93419SNuno Antunes (uintmax_t)CPUMASK_LOWMASK(mycpu->gd_other_cpus), 190*1ad93419SNuno Antunes (uintmax_t)CPUMASK_LOWMASK(stopped_cpus)); 1910e6594a8SSascha Wildner panic("stop_cpus() failed"); 1920e6594a8SSascha Wildner } 1930e6594a8SSascha Wildner restart_cpus(stopped_cpus); 1940e6594a8SSascha Wildner 1950e6594a8SSascha Wildner db_printf(" restarted\n"); 1960e6594a8SSascha Wildner crit_exit(); 1970e6594a8SSascha Wildner 1980e6594a8SSascha Wildner regs->tf_rip = ddb_regs.tf_rip; 1990e6594a8SSascha Wildner regs->tf_rflags = ddb_regs.tf_rflags; 2000e6594a8SSascha Wildner regs->tf_rax = ddb_regs.tf_rax; 2010e6594a8SSascha Wildner regs->tf_rcx = ddb_regs.tf_rcx; 2020e6594a8SSascha Wildner regs->tf_rdx = ddb_regs.tf_rdx; 2030e6594a8SSascha Wildner regs->tf_rbx = ddb_regs.tf_rbx; 2040e6594a8SSascha Wildner 2050e6594a8SSascha Wildner regs->tf_rsp = ddb_regs.tf_rsp; 2060e6594a8SSascha Wildner regs->tf_ss = ddb_regs.tf_ss & 0xffff; 2070e6594a8SSascha Wildner 2080e6594a8SSascha Wildner regs->tf_rbp = ddb_regs.tf_rbp; 2090e6594a8SSascha Wildner regs->tf_rsi = ddb_regs.tf_rsi; 2100e6594a8SSascha Wildner regs->tf_rdi = ddb_regs.tf_rdi; 2110e6594a8SSascha Wildner 2120e6594a8SSascha Wildner regs->tf_r8 = ddb_regs.tf_r8; 2130e6594a8SSascha Wildner regs->tf_r9 = ddb_regs.tf_r9; 2140e6594a8SSascha Wildner regs->tf_r10 = ddb_regs.tf_r10; 2150e6594a8SSascha Wildner regs->tf_r11 = ddb_regs.tf_r11; 2160e6594a8SSascha Wildner regs->tf_r12 = ddb_regs.tf_r12; 2170e6594a8SSascha Wildner regs->tf_r13 = ddb_regs.tf_r13; 2180e6594a8SSascha Wildner regs->tf_r14 = ddb_regs.tf_r14; 2190e6594a8SSascha Wildner regs->tf_r15 = ddb_regs.tf_r15; 2200e6594a8SSascha Wildner 2210e6594a8SSascha Wildner /* regs->tf_es = ddb_regs.tf_es & 0xffff; */ 2220e6594a8SSascha Wildner /* regs->tf_fs = ddb_regs.tf_fs & 0xffff; */ 2230e6594a8SSascha Wildner /* regs->tf_gs = ddb_regs.tf_gs & 0xffff; */ 2240e6594a8SSascha Wildner regs->tf_cs = ddb_regs.tf_cs & 0xffff; 2250e6594a8SSascha Wildner /* regs->tf_ds = ddb_regs.tf_ds & 0xffff; */ 2260e6594a8SSascha Wildner return (1); 2270e6594a8SSascha Wildner } 2280e6594a8SSascha Wildner 2290e6594a8SSascha Wildner /* 2300e6594a8SSascha Wildner * Read bytes from kernel address space for debugger. 2310e6594a8SSascha Wildner */ 2320e6594a8SSascha Wildner void 2330e6594a8SSascha Wildner db_read_bytes(vm_offset_t addr, size_t size, char *data) 2340e6594a8SSascha Wildner { 2350e6594a8SSascha Wildner char *src; 2360e6594a8SSascha Wildner 2370e6594a8SSascha Wildner db_nofault = &db_jmpbuf; 2380e6594a8SSascha Wildner 2390e6594a8SSascha Wildner src = (char *)addr; 2400e6594a8SSascha Wildner while (size-- > 0) 2410e6594a8SSascha Wildner *data++ = *src++; 2420e6594a8SSascha Wildner 2434090d6ffSSascha Wildner db_nofault = NULL; 2440e6594a8SSascha Wildner } 2450e6594a8SSascha Wildner 2460e6594a8SSascha Wildner /* 2470e6594a8SSascha Wildner * Write bytes to kernel address space for debugger. 2480e6594a8SSascha Wildner */ 2490e6594a8SSascha Wildner void 2500e6594a8SSascha Wildner db_write_bytes(vm_offset_t addr, size_t size, char *data) 2510e6594a8SSascha Wildner { 2520e6594a8SSascha Wildner char *dst; 2530e6594a8SSascha Wildner #if 0 2540e6594a8SSascha Wildner vpte_t *ptep0 = NULL; 2550e6594a8SSascha Wildner vpte_t oldmap0 = 0; 2560e6594a8SSascha Wildner vm_offset_t addr1; 2570e6594a8SSascha Wildner vpte_t *ptep1 = NULL; 2580e6594a8SSascha Wildner vpte_t oldmap1 = 0; 2590e6594a8SSascha Wildner #endif 2600e6594a8SSascha Wildner 2610e6594a8SSascha Wildner db_nofault = &db_jmpbuf; 2620e6594a8SSascha Wildner #if 0 2630e6594a8SSascha Wildner if (addr > trunc_page((vm_offset_t)btext) - size && 2640e6594a8SSascha Wildner addr < round_page((vm_offset_t)etext)) { 2650e6594a8SSascha Wildner 2660e6594a8SSascha Wildner ptep0 = pmap_kpte(addr); 2670e6594a8SSascha Wildner oldmap0 = *ptep0; 268a86ce0cdSMatthew Dillon *ptep0 |= VPTE_RW; 2690e6594a8SSascha Wildner 2700e6594a8SSascha Wildner /* Map another page if the data crosses a page boundary. */ 2710e6594a8SSascha Wildner if ((*ptep0 & PG_PS) == 0) { 2720e6594a8SSascha Wildner addr1 = trunc_page(addr + size - 1); 2730e6594a8SSascha Wildner if (trunc_page(addr) != addr1) { 2740e6594a8SSascha Wildner ptep1 = pmap_kpte(addr1); 2750e6594a8SSascha Wildner oldmap1 = *ptep1; 276a86ce0cdSMatthew Dillon *ptep1 |= VPTE_RW; 2770e6594a8SSascha Wildner } 2780e6594a8SSascha Wildner } else { 2790e6594a8SSascha Wildner addr1 = trunc_4mpage(addr + size - 1); 2800e6594a8SSascha Wildner if (trunc_4mpage(addr) != addr1) { 2810e6594a8SSascha Wildner ptep1 = pmap_kpte(addr1); 2820e6594a8SSascha Wildner oldmap1 = *ptep1; 283a86ce0cdSMatthew Dillon *ptep1 |= VPTE_RW; 2840e6594a8SSascha Wildner } 2850e6594a8SSascha Wildner } 2860e6594a8SSascha Wildner 2870e6594a8SSascha Wildner cpu_invltlb(); 2880e6594a8SSascha Wildner } 2890e6594a8SSascha Wildner #endif 2900e6594a8SSascha Wildner 2910e6594a8SSascha Wildner dst = (char *)addr; 2920e6594a8SSascha Wildner 2930e6594a8SSascha Wildner while (size-- > 0) 2940e6594a8SSascha Wildner *dst++ = *data++; 2950e6594a8SSascha Wildner 2964090d6ffSSascha Wildner db_nofault = NULL; 2970e6594a8SSascha Wildner 2980e6594a8SSascha Wildner #if 0 2990e6594a8SSascha Wildner if (ptep0) { 3000e6594a8SSascha Wildner *ptep0 = oldmap0; 3010e6594a8SSascha Wildner 3020e6594a8SSascha Wildner if (ptep1) 3030e6594a8SSascha Wildner *ptep1 = oldmap1; 3040e6594a8SSascha Wildner 3050e6594a8SSascha Wildner cpu_invltlb(); 3060e6594a8SSascha Wildner } 3070e6594a8SSascha Wildner #endif 3080e6594a8SSascha Wildner } 3090e6594a8SSascha Wildner 3100e6594a8SSascha Wildner /* 3110e6594a8SSascha Wildner * The debugger sometimes needs to know the actual KVM address represented 3120e6594a8SSascha Wildner * by the instruction pointer, stack pointer, or base pointer. Normally 3130e6594a8SSascha Wildner * the actual KVM address is simply the contents of the register. However, 3140e6594a8SSascha Wildner * if the debugger is entered from the BIOS or VM86 we need to figure out 3150e6594a8SSascha Wildner * the offset from the segment register. 3160e6594a8SSascha Wildner */ 3170e6594a8SSascha Wildner db_addr_t 3180e6594a8SSascha Wildner PC_REGS(db_regs_t *regs) 3190e6594a8SSascha Wildner { 3200e6594a8SSascha Wildner return(regs->tf_rip); 3210e6594a8SSascha Wildner } 3220e6594a8SSascha Wildner 3230e6594a8SSascha Wildner db_addr_t 3240e6594a8SSascha Wildner SP_REGS(db_regs_t *regs) 3250e6594a8SSascha Wildner { 3260e6594a8SSascha Wildner return(regs->tf_rsp); 3270e6594a8SSascha Wildner } 3280e6594a8SSascha Wildner 3290e6594a8SSascha Wildner db_addr_t 3300e6594a8SSascha Wildner BP_REGS(db_regs_t *regs) 3310e6594a8SSascha Wildner { 3320e6594a8SSascha Wildner return(regs->tf_rbp); 3330e6594a8SSascha Wildner } 3340e6594a8SSascha Wildner 3350e6594a8SSascha Wildner /* 3360e6594a8SSascha Wildner * XXX 3370e6594a8SSascha Wildner * Move this to machdep.c and allow it to be called if any debugger is 3380e6594a8SSascha Wildner * installed. 3390e6594a8SSascha Wildner */ 3400e6594a8SSascha Wildner void 3410e6594a8SSascha Wildner Debugger(const char *msg) 3420e6594a8SSascha Wildner { 3430e6594a8SSascha Wildner static volatile u_char in_Debugger; 3440e6594a8SSascha Wildner 3450e6594a8SSascha Wildner /* 3460e6594a8SSascha Wildner * XXX 3470e6594a8SSascha Wildner * Do nothing if the console is in graphics mode. This is 3480e6594a8SSascha Wildner * OK if the call is for the debugger hotkey but not if the call 3490e6594a8SSascha Wildner * is a weak form of panicing. 3500e6594a8SSascha Wildner */ 3510e6594a8SSascha Wildner if (cons_unavail && !(boothowto & RB_GDB)) 3520e6594a8SSascha Wildner return; 3530e6594a8SSascha Wildner 3540e6594a8SSascha Wildner if (!in_Debugger) { 3550e6594a8SSascha Wildner in_Debugger = 1; 3560e6594a8SSascha Wildner db_printf("Debugger(\"%s\")\n", msg); 3570e6594a8SSascha Wildner breakpoint(); 3580e6594a8SSascha Wildner in_Debugger = 0; 3590e6594a8SSascha Wildner } 3600e6594a8SSascha Wildner } 361