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_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
580e6594a8SSascha Wildner  */
590e6594a8SSascha Wildner 
600e6594a8SSascha Wildner #include <sys/param.h>
610e6594a8SSascha Wildner #include <sys/systm.h>
620e6594a8SSascha Wildner #include <sys/linker_set.h>
630e6594a8SSascha Wildner #include <sys/lock.h>
640e6594a8SSascha Wildner #include <sys/proc.h>
650e6594a8SSascha Wildner #include <sys/reg.h>
660e6594a8SSascha Wildner 
670e6594a8SSascha Wildner #include <machine/cpu.h>
680e6594a8SSascha Wildner #include <machine/md_var.h>
690e6594a8SSascha Wildner 
700e6594a8SSascha Wildner #include <vm/vm.h>
710e6594a8SSascha Wildner #include <vm/vm_param.h>
720e6594a8SSascha Wildner #include <vm/pmap.h>
730e6594a8SSascha Wildner #include <vm/vm_map.h>
740e6594a8SSascha Wildner #include <ddb/ddb.h>
750e6594a8SSascha Wildner #include <dlfcn.h>	/* DLL */
760e6594a8SSascha Wildner 
770e6594a8SSascha Wildner #include <ddb/db_access.h>
780e6594a8SSascha Wildner #include <ddb/db_sym.h>
790e6594a8SSascha Wildner #include <ddb/db_variables.h>
800e6594a8SSascha Wildner 
810e6594a8SSascha Wildner db_varfcn_t db_dr0;
820e6594a8SSascha Wildner db_varfcn_t db_dr1;
830e6594a8SSascha Wildner db_varfcn_t db_dr2;
840e6594a8SSascha Wildner db_varfcn_t db_dr3;
850e6594a8SSascha Wildner db_varfcn_t db_dr4;
860e6594a8SSascha Wildner db_varfcn_t db_dr5;
870e6594a8SSascha Wildner db_varfcn_t db_dr6;
880e6594a8SSascha Wildner db_varfcn_t db_dr7;
890e6594a8SSascha Wildner 
900e6594a8SSascha Wildner /*
910e6594a8SSascha Wildner  * Machine register set.
920e6594a8SSascha Wildner  */
930e6594a8SSascha Wildner struct db_variable db_regs[] = {
940e6594a8SSascha Wildner 	{ "cs",		&ddb_regs.tf_cs,     NULL },
950e6594a8SSascha Wildner /*	{ "ds",		&ddb_regs.tf_ds,     NULL },
960e6594a8SSascha Wildner 	{ "es",		&ddb_regs.tf_es,     NULL },
970e6594a8SSascha Wildner 	{ "fs",		&ddb_regs.tf_fs,     NULL },
980e6594a8SSascha Wildner 	{ "gs",		&ddb_regs.tf_gs,     NULL }, */
990e6594a8SSascha Wildner 	{ "ss",		&ddb_regs.tf_ss,     NULL },
1000e6594a8SSascha Wildner 	{ "rax",	&ddb_regs.tf_rax,    NULL },
1010e6594a8SSascha Wildner 	{ "rcx",	&ddb_regs.tf_rcx,    NULL },
1020e6594a8SSascha Wildner 	{ "rdx",	&ddb_regs.tf_rdx,    NULL },
1030e6594a8SSascha Wildner 	{ "rbx",	&ddb_regs.tf_rbx,    NULL },
1040e6594a8SSascha Wildner 	{ "rsp",	&ddb_regs.tf_rsp,    NULL },
1050e6594a8SSascha Wildner 	{ "rbp",	&ddb_regs.tf_rbp,    NULL },
1060e6594a8SSascha Wildner 	{ "rsi",	&ddb_regs.tf_rsi,    NULL },
1070e6594a8SSascha Wildner 	{ "rdi",	&ddb_regs.tf_rdi,    NULL },
1080e6594a8SSascha Wildner 	{ "rip",	&ddb_regs.tf_rip,    NULL },
1090e6594a8SSascha Wildner 	{ "rfl",	&ddb_regs.tf_rflags, NULL },
1100e6594a8SSascha Wildner 	{ "r8",		&ddb_regs.tf_r8,     NULL },
1110e6594a8SSascha Wildner 	{ "r9",		&ddb_regs.tf_r9,     NULL },
1120e6594a8SSascha Wildner 	{ "r10",	&ddb_regs.tf_r10,    NULL },
1130e6594a8SSascha Wildner 	{ "r11",	&ddb_regs.tf_r11,    NULL },
1140e6594a8SSascha Wildner 	{ "r12",	&ddb_regs.tf_r12,    NULL },
1150e6594a8SSascha Wildner 	{ "r13",	&ddb_regs.tf_r13,    NULL },
1160e6594a8SSascha Wildner 	{ "r14",	&ddb_regs.tf_r14,    NULL },
1170e6594a8SSascha Wildner 	{ "r15",	&ddb_regs.tf_r15,    NULL },
1180e6594a8SSascha Wildner 	{ "dr0",	NULL,		     db_dr0 },
1190e6594a8SSascha Wildner 	{ "dr1",	NULL,		     db_dr1 },
1200e6594a8SSascha Wildner 	{ "dr2",	NULL,		     db_dr2 },
1210e6594a8SSascha Wildner 	{ "dr3",	NULL,		     db_dr3 },
1220e6594a8SSascha Wildner 	{ "dr4",	NULL,		     db_dr4 },
1230e6594a8SSascha Wildner 	{ "dr5",	NULL,		     db_dr5 },
1240e6594a8SSascha Wildner 	{ "dr6",	NULL,		     db_dr6 },
1250e6594a8SSascha Wildner 	{ "dr7",	NULL,		     db_dr7 },
1260e6594a8SSascha Wildner };
127c157ff7aSSascha Wildner struct db_variable *db_eregs = db_regs + NELEM(db_regs);
1280e6594a8SSascha Wildner 
1290e6594a8SSascha Wildner /*
1300e6594a8SSascha Wildner  * Stack trace.
1310e6594a8SSascha Wildner  */
1320e6594a8SSascha Wildner #define	INKERNEL(va)	(((vm_offset_t)(va)) >= USRSTACK)
1330e6594a8SSascha Wildner 
134a76ca9b9SSascha Wildner struct x86_64_frame {
135a76ca9b9SSascha Wildner 	struct x86_64_frame	*f_frame;
1360e6594a8SSascha Wildner 	long			f_retaddr;
1370e6594a8SSascha Wildner 	long			f_arg0;
1380e6594a8SSascha Wildner };
1390e6594a8SSascha Wildner 
1400e6594a8SSascha Wildner #define NORMAL		0
1410e6594a8SSascha Wildner #define	TRAP		1
1420e6594a8SSascha Wildner #define	INTERRUPT	2
1430e6594a8SSascha Wildner #define	SYSCALL		3
1440e6594a8SSascha Wildner 
145a76ca9b9SSascha Wildner static void	db_nextframe(struct x86_64_frame **, db_addr_t *);
146a76ca9b9SSascha Wildner static int	db_numargs(struct x86_64_frame *);
1470e6594a8SSascha Wildner static void	db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
1480e6594a8SSascha Wildner static void	dl_symbol_values(long callpc, const char **name);
1490e6594a8SSascha Wildner 
1500e6594a8SSascha Wildner 
1510e6594a8SSascha Wildner static char	*watchtype_str(int type);
152a76ca9b9SSascha Wildner static int	kx86_64_set_watch(int watchnum, unsigned int watchaddr,
1530e6594a8SSascha Wildner                                int size, int access, struct dbreg * d);
154a76ca9b9SSascha Wildner static int	kx86_64_clr_watch(int watchnum, struct dbreg * d);
1550e6594a8SSascha Wildner int		db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
1560e6594a8SSascha Wildner int		db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
1570e6594a8SSascha Wildner void		db_md_list_watchpoints(void);
1580e6594a8SSascha Wildner 
1590e6594a8SSascha Wildner 
1600e6594a8SSascha Wildner /*
1610e6594a8SSascha Wildner  * Figure out how many arguments were passed into the frame at "fp".
1620e6594a8SSascha Wildner  */
1630e6594a8SSascha Wildner static int
db_numargs(struct x86_64_frame * fp)164a76ca9b9SSascha Wildner db_numargs(struct x86_64_frame *fp)
1650e6594a8SSascha Wildner {
1660e6594a8SSascha Wildner #if 1
1670e6594a8SSascha Wildner 	return (0);	/* regparm, needs dwarf2 info */
1680e6594a8SSascha Wildner #else
1690e6594a8SSascha Wildner 	int	args;
1700e6594a8SSascha Wildner #if 0
1710e6594a8SSascha Wildner 	int	*argp;
1720e6594a8SSascha Wildner 	int	inst;
1730e6594a8SSascha Wildner 
1740e6594a8SSascha Wildner 	argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
1750e6594a8SSascha Wildner 	/*
1760e6594a8SSascha Wildner 	 * XXX etext is wrong for LKMs.  We should attempt to interpret
1770e6594a8SSascha Wildner 	 * the instruction at the return address in all cases.  This
1780e6594a8SSascha Wildner 	 * may require better fault handling.
1790e6594a8SSascha Wildner 	 */
1800e6594a8SSascha Wildner 	if (argp < (int *)btext || argp >= (int *)etext) {
1810e6594a8SSascha Wildner 		args = 5;
1820e6594a8SSascha Wildner 	} else {
1830e6594a8SSascha Wildner 		inst = db_get_value((int)argp, 4, FALSE);
1840e6594a8SSascha Wildner 		if ((inst & 0xff) == 0x59)	/* popl %ecx */
1850e6594a8SSascha Wildner 			args = 1;
1860e6594a8SSascha Wildner 		else if ((inst & 0xffff) == 0xc483)	/* addl $Ibs, %esp */
1870e6594a8SSascha Wildner 			args = ((inst >> 16) & 0xff) / 4;
1880e6594a8SSascha Wildner 		else
1890e6594a8SSascha Wildner 			args = 5;
1900e6594a8SSascha Wildner 	}
1910e6594a8SSascha Wildner #endif
1920e6594a8SSascha Wildner 	args = 5;
1930e6594a8SSascha Wildner 	return(args);
1940e6594a8SSascha Wildner #endif
1950e6594a8SSascha Wildner }
1960e6594a8SSascha Wildner 
1970e6594a8SSascha Wildner static void
db_print_stack_entry(const char * name,int narg,char ** argnp,long * argp,db_addr_t callpc)1980e6594a8SSascha Wildner db_print_stack_entry(const char *name, int narg, char **argnp, long *argp,
1990e6594a8SSascha Wildner 		     db_addr_t callpc)
2000e6594a8SSascha Wildner {
2010e6594a8SSascha Wildner 	db_printf("%s(", name);
2020e6594a8SSascha Wildner 	while (narg) {
2030e6594a8SSascha Wildner 		if (argnp)
2040e6594a8SSascha Wildner 			db_printf("%s=", *argnp++);
2050e6594a8SSascha Wildner 		db_printf("%ld", (long)db_get_value((long)argp, 8, FALSE));
2060e6594a8SSascha Wildner 		argp++;
2070e6594a8SSascha Wildner 		if (--narg != 0)
2080e6594a8SSascha Wildner 			db_printf(",");
2090e6594a8SSascha Wildner 	}
2100e6594a8SSascha Wildner 	db_printf(") at ");
2110e6594a8SSascha Wildner 	db_printsym(callpc, DB_STGY_PROC);
2120e6594a8SSascha Wildner 	db_printf("\n");
2130e6594a8SSascha Wildner }
2140e6594a8SSascha Wildner 
2150e6594a8SSascha Wildner /*
2160e6594a8SSascha Wildner  * Figure out the next frame up in the call stack.
2170e6594a8SSascha Wildner  */
2180e6594a8SSascha Wildner static void
db_nextframe(struct x86_64_frame ** fp,db_addr_t * ip)219a76ca9b9SSascha Wildner db_nextframe(struct x86_64_frame **fp, db_addr_t *ip)
2200e6594a8SSascha Wildner {
2210e6594a8SSascha Wildner 	struct trapframe *tf;
2220e6594a8SSascha Wildner 	int frame_type;
2230e6594a8SSascha Wildner 	long rip, rsp, rbp;
2240e6594a8SSascha Wildner 	db_expr_t offset;
2250e6594a8SSascha Wildner 	const char *sym, *name;
2260e6594a8SSascha Wildner 
2270e6594a8SSascha Wildner 	if ((unsigned long)*fp < PAGE_SIZE) {
2280e6594a8SSascha Wildner 		*fp = NULL;
2290e6594a8SSascha Wildner 		return;
2300e6594a8SSascha Wildner 	}
2310e6594a8SSascha Wildner 	rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
2320e6594a8SSascha Wildner 	rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
2330e6594a8SSascha Wildner 
2340e6594a8SSascha Wildner 	/*
2350e6594a8SSascha Wildner 	 * Figure out frame type.
2360e6594a8SSascha Wildner 	 */
2370e6594a8SSascha Wildner 
2380e6594a8SSascha Wildner 	frame_type = NORMAL;
2390e6594a8SSascha Wildner 
2400e6594a8SSascha Wildner 	sym = db_search_symbol(rip, DB_STGY_ANY, &offset);
2410e6594a8SSascha Wildner 	db_symbol_values(sym, &name, NULL);
2420e6594a8SSascha Wildner 	dl_symbol_values(rip, &name);
2430e6594a8SSascha Wildner 	if (name != NULL) {
2440e6594a8SSascha Wildner 		if (!strcmp(name, "calltrap")) {
2450e6594a8SSascha Wildner 			frame_type = TRAP;
2460e6594a8SSascha Wildner 		} else if (!strncmp(name, "Xresume", 7)) {
2470e6594a8SSascha Wildner 			frame_type = INTERRUPT;
2480e6594a8SSascha Wildner 		} else if (!strcmp(name, "_Xsyscall")) {
2490e6594a8SSascha Wildner 			frame_type = SYSCALL;
2500e6594a8SSascha Wildner 		}
2510e6594a8SSascha Wildner 	}
2520e6594a8SSascha Wildner 
2530e6594a8SSascha Wildner 	/*
2540e6594a8SSascha Wildner 	 * Normal frames need no special processing.
2550e6594a8SSascha Wildner 	 */
2560e6594a8SSascha Wildner 	if (frame_type == NORMAL) {
2570e6594a8SSascha Wildner 		*ip = (db_addr_t) rip;
258a76ca9b9SSascha Wildner 		*fp = (struct x86_64_frame *) rbp;
2590e6594a8SSascha Wildner 		return;
2600e6594a8SSascha Wildner 	}
2610e6594a8SSascha Wildner 
2620e6594a8SSascha Wildner 	db_print_stack_entry(name, 0, 0, 0, rip);
2630e6594a8SSascha Wildner 
2640e6594a8SSascha Wildner 	/*
2650e6594a8SSascha Wildner 	 * Point to base of trapframe which is just above the
2660e6594a8SSascha Wildner 	 * current frame.
2670e6594a8SSascha Wildner 	 */
2680e6594a8SSascha Wildner 	tf = (struct trapframe *)((long)*fp + 16);
2690e6594a8SSascha Wildner 
2700e6594a8SSascha Wildner #if 0
2710e6594a8SSascha Wildner 	rsp = (ISPL(tf->tf_cs) == SEL_UPL) ?  tf->tf_rsp : (long)&tf->tf_rsp;
2720e6594a8SSascha Wildner #endif
2730e6594a8SSascha Wildner 	rsp = (long)&tf->tf_rsp;
2740e6594a8SSascha Wildner 
2750e6594a8SSascha Wildner 	switch (frame_type) {
2760e6594a8SSascha Wildner 	case TRAP:
2770e6594a8SSascha Wildner 		{
2780e6594a8SSascha Wildner 			rip = tf->tf_rip;
2790e6594a8SSascha Wildner 			rbp = tf->tf_rbp;
2800e6594a8SSascha Wildner 			db_printf(
2810e6594a8SSascha Wildner 	    "--- trap %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
2820e6594a8SSascha Wildner 			    tf->tf_trapno, rip, rsp, rbp);
2830e6594a8SSascha Wildner 		}
2840e6594a8SSascha Wildner 		break;
2850e6594a8SSascha Wildner 	case SYSCALL:
2860e6594a8SSascha Wildner 		{
2870e6594a8SSascha Wildner 			rip = tf->tf_rip;
2880e6594a8SSascha Wildner 			rbp = tf->tf_rbp;
2890e6594a8SSascha Wildner 			db_printf(
2900e6594a8SSascha Wildner 	"--- syscall %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
2910e6594a8SSascha Wildner 			    tf->tf_rax, rip, rsp, rbp);
2920e6594a8SSascha Wildner 		}
2930e6594a8SSascha Wildner 		break;
2940e6594a8SSascha Wildner 	case INTERRUPT:
2950e6594a8SSascha Wildner 		tf = (struct trapframe *)((long)*fp + 16);
2960e6594a8SSascha Wildner 		{
2970e6594a8SSascha Wildner 			rip = tf->tf_rip;
2980e6594a8SSascha Wildner 			rbp = tf->tf_rbp;
2990e6594a8SSascha Wildner 			db_printf(
3000e6594a8SSascha Wildner 	    "--- interrupt, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
3010e6594a8SSascha Wildner 			    rip, rsp, rbp);
3020e6594a8SSascha Wildner 		}
3030e6594a8SSascha Wildner 		break;
3040e6594a8SSascha Wildner 	default:
3050e6594a8SSascha Wildner 		break;
3060e6594a8SSascha Wildner 	}
3070e6594a8SSascha Wildner 
3080e6594a8SSascha Wildner 	*ip = (db_addr_t) rip;
309a76ca9b9SSascha Wildner 	*fp = (struct x86_64_frame *) rbp;
3100e6594a8SSascha Wildner }
3110e6594a8SSascha Wildner 
3120e6594a8SSascha Wildner void
db_stack_trace_cmd(db_expr_t addr,boolean_t have_addr,db_expr_t count,char * modif)3130e6594a8SSascha Wildner db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
3140e6594a8SSascha Wildner 		   char *modif)
3150e6594a8SSascha Wildner {
316a76ca9b9SSascha Wildner 	struct x86_64_frame *frame;
3170e6594a8SSascha Wildner 	long *argp;
3180e6594a8SSascha Wildner 	db_addr_t callpc;
3190e6594a8SSascha Wildner 	boolean_t first;
3200e6594a8SSascha Wildner 	int i;
3210e6594a8SSascha Wildner 
3220e6594a8SSascha Wildner 	if (count == -1)
3230e6594a8SSascha Wildner 		count = 1024;
3240e6594a8SSascha Wildner 
3250e6594a8SSascha Wildner 	if (!have_addr) {
326a76ca9b9SSascha Wildner 		frame = (struct x86_64_frame *)BP_REGS(&ddb_regs);
3270e6594a8SSascha Wildner 		if (frame == NULL)
328a76ca9b9SSascha Wildner 			frame = (struct x86_64_frame *)(SP_REGS(&ddb_regs) - 8);
3290e6594a8SSascha Wildner 		callpc = PC_REGS(&ddb_regs);
3300e6594a8SSascha Wildner 	} else {
3310e6594a8SSascha Wildner 		/*
3320e6594a8SSascha Wildner 		 * Look for something that might be a frame pointer, just as
3330e6594a8SSascha Wildner 		 * a convenience.
3340e6594a8SSascha Wildner 		 */
335a76ca9b9SSascha Wildner 		frame = (struct x86_64_frame *)addr;
3360e6594a8SSascha Wildner 		for (i = 0; i < 4096; i += 8) {
337a76ca9b9SSascha Wildner 			struct x86_64_frame *check;
3380e6594a8SSascha Wildner 
339a76ca9b9SSascha Wildner 			check = (struct x86_64_frame *)db_get_value((long)((char *)&frame->f_frame + i), 8, FALSE);
3400e6594a8SSascha Wildner 			if ((char *)check - (char *)frame >= 0 &&
3410e6594a8SSascha Wildner 			    (char *)check - (char *)frame < 4096
3420e6594a8SSascha Wildner 			) {
3430e6594a8SSascha Wildner 				break;
3440e6594a8SSascha Wildner 			}
3450e6594a8SSascha Wildner 			db_printf("%p does not look like a stack frame, skipping\n", (char *)&frame->f_frame + i);
3460e6594a8SSascha Wildner 		}
3470e6594a8SSascha Wildner 		if (i == 4096) {
3480e6594a8SSascha Wildner 			db_printf("Unable to find anything that looks like a stack frame\n");
3490e6594a8SSascha Wildner 			return;
3500e6594a8SSascha Wildner 		}
3510e6594a8SSascha Wildner 		frame = (void *)((char *)frame + i);
3520e6594a8SSascha Wildner 		db_printf("Trace beginning at frame %p\n", frame);
3530e6594a8SSascha Wildner 		callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
3540e6594a8SSascha Wildner 	}
3550e6594a8SSascha Wildner 
3560e6594a8SSascha Wildner 	first = TRUE;
3570e6594a8SSascha Wildner 	while (count--) {
358a76ca9b9SSascha Wildner 		struct x86_64_frame *actframe;
3590e6594a8SSascha Wildner 		int		narg;
3600e6594a8SSascha Wildner 		const char *	name;
3610e6594a8SSascha Wildner 		db_expr_t	offset;
3620e6594a8SSascha Wildner 		c_db_sym_t	sym;
3630e6594a8SSascha Wildner #define MAXNARG	16
3640e6594a8SSascha Wildner 		char	*argnames[MAXNARG], **argnp = NULL;
3650e6594a8SSascha Wildner 
3660e6594a8SSascha Wildner 		sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
3670e6594a8SSascha Wildner 		db_symbol_values(sym, &name, NULL);
3680e6594a8SSascha Wildner 		dl_symbol_values(callpc, &name);
3690e6594a8SSascha Wildner 
3700e6594a8SSascha Wildner 		/*
3710e6594a8SSascha Wildner 		 * Attempt to determine a (possibly fake) frame that gives
3720e6594a8SSascha Wildner 		 * the caller's pc.  It may differ from `frame' if the
3730e6594a8SSascha Wildner 		 * current function never sets up a standard frame or hasn't
3740e6594a8SSascha Wildner 		 * set one up yet or has just discarded one.  The last two
3750e6594a8SSascha Wildner 		 * cases can be guessed fairly reliably for code generated
3760e6594a8SSascha Wildner 		 * by gcc.  The first case is too much trouble to handle in
3770e6594a8SSascha Wildner 		 * general because the amount of junk on the stack depends
3780e6594a8SSascha Wildner 		 * on the pc (the special handling of "calltrap", etc. in
3790e6594a8SSascha Wildner 		 * db_nextframe() works because the `next' pc is special).
3800e6594a8SSascha Wildner 		 */
3810e6594a8SSascha Wildner 		actframe = frame;
3820e6594a8SSascha Wildner 		if (first) {
3830e6594a8SSascha Wildner 			if (!have_addr) {
3840e6594a8SSascha Wildner 				int instr;
3850e6594a8SSascha Wildner 
3860e6594a8SSascha Wildner 				instr = db_get_value(callpc, 4, FALSE);
3870e6594a8SSascha Wildner 				if ((instr & 0xffffffff) == 0xe5894855) {
3880e6594a8SSascha Wildner 					/* pushq %rbp; movq %rsp, %rbp */
389a76ca9b9SSascha Wildner 					actframe = (struct x86_64_frame *)
3900e6594a8SSascha Wildner 					    (SP_REGS(&ddb_regs) - 8);
3910e6594a8SSascha Wildner 				} else if ((instr & 0xffffff) == 0xe58948) {
3920e6594a8SSascha Wildner 					/* movq %rsp, %rbp */
393a76ca9b9SSascha Wildner 					actframe = (struct x86_64_frame *)
3940e6594a8SSascha Wildner 					    SP_REGS(&ddb_regs);
3950e6594a8SSascha Wildner 					if (ddb_regs.tf_rbp == 0) {
3960e6594a8SSascha Wildner 						/* Fake caller's frame better. */
3970e6594a8SSascha Wildner 						frame = actframe;
3980e6594a8SSascha Wildner 					}
3990e6594a8SSascha Wildner 				} else if ((instr & 0xff) == 0xc3) {
4000e6594a8SSascha Wildner 					/* ret */
401a76ca9b9SSascha Wildner 					actframe = (struct x86_64_frame *)
4020e6594a8SSascha Wildner 					    (SP_REGS(&ddb_regs) - 8);
4030e6594a8SSascha Wildner 				} else if (offset == 0) {
4040e6594a8SSascha Wildner 					/* Probably a symbol in assembler code. */
405a76ca9b9SSascha Wildner 					actframe = (struct x86_64_frame *)
4060e6594a8SSascha Wildner 					    (SP_REGS(&ddb_regs) - 8);
4070e6594a8SSascha Wildner 				}
4080e6594a8SSascha Wildner 			} else if (name != NULL &&
4090e6594a8SSascha Wildner 				   strcmp(name, "fork_trampoline") == 0) {
4100e6594a8SSascha Wildner 				/*
4110e6594a8SSascha Wildner 				 * Don't try to walk back on a stack for a
4120e6594a8SSascha Wildner 				 * process that hasn't actually been run yet.
4130e6594a8SSascha Wildner 				 */
4140e6594a8SSascha Wildner 				db_print_stack_entry(name, 0, 0, 0, callpc);
4150e6594a8SSascha Wildner 				break;
4160e6594a8SSascha Wildner 			}
4170e6594a8SSascha Wildner 			first = FALSE;
4180e6594a8SSascha Wildner 		}
4190e6594a8SSascha Wildner 
4200e6594a8SSascha Wildner 		argp = &actframe->f_arg0;
4210e6594a8SSascha Wildner 		narg = MAXNARG;
4220e6594a8SSascha Wildner 		if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
4230e6594a8SSascha Wildner 			argnp = argnames;
4240e6594a8SSascha Wildner 		} else {
4250e6594a8SSascha Wildner 			narg = db_numargs(frame);
4260e6594a8SSascha Wildner 		}
4270e6594a8SSascha Wildner 
4280e6594a8SSascha Wildner 		db_print_stack_entry(name, narg, argnp, argp, callpc);
4290e6594a8SSascha Wildner 
4300e6594a8SSascha Wildner 		if (actframe != frame) {
4310e6594a8SSascha Wildner 			/* `frame' belongs to caller. */
4320e6594a8SSascha Wildner 			callpc = (db_addr_t)
4330e6594a8SSascha Wildner 			    db_get_value((long)&actframe->f_retaddr, 8, FALSE);
4340e6594a8SSascha Wildner 			continue;
4350e6594a8SSascha Wildner 		}
4360e6594a8SSascha Wildner 
4370e6594a8SSascha Wildner 		db_nextframe(&frame, &callpc);
438*4090d6ffSSascha Wildner 		if (frame == NULL)
4390e6594a8SSascha Wildner 			break;
4400e6594a8SSascha Wildner 	}
4410e6594a8SSascha Wildner }
4420e6594a8SSascha Wildner 
4430e6594a8SSascha Wildner void
print_backtrace(int count)4447ce2998eSAlex Hornung print_backtrace(int count)
4450e6594a8SSascha Wildner {
4460e6594a8SSascha Wildner 	register_t  rbp;
4470e6594a8SSascha Wildner 
4480e6594a8SSascha Wildner 	__asm __volatile("movq %%rbp, %0" : "=r" (rbp));
4497ce2998eSAlex Hornung 	db_stack_trace_cmd(rbp, 1, count, NULL);
4500e6594a8SSascha Wildner }
4510e6594a8SSascha Wildner 
4520e6594a8SSascha Wildner #define DB_DRX_FUNC(reg)						\
4530e6594a8SSascha Wildner int									\
4540e6594a8SSascha Wildner db_ ## reg (struct db_variable *vp, db_expr_t *valuep, int op)		\
4550e6594a8SSascha Wildner {									\
4560e6594a8SSascha Wildner 	if (op == DB_VAR_GET)						\
4570e6594a8SSascha Wildner 		*valuep = r ## reg ();					\
4580e6594a8SSascha Wildner 	else								\
4590e6594a8SSascha Wildner 		load_ ## reg (*valuep); 				\
4600e6594a8SSascha Wildner 									\
4610e6594a8SSascha Wildner 	return(0);							\
4620e6594a8SSascha Wildner }
4630e6594a8SSascha Wildner 
4640e6594a8SSascha Wildner DB_DRX_FUNC(dr0)
DB_DRX_FUNC(dr1)4650e6594a8SSascha Wildner DB_DRX_FUNC(dr1)
4660e6594a8SSascha Wildner DB_DRX_FUNC(dr2)
4670e6594a8SSascha Wildner DB_DRX_FUNC(dr3)
4680e6594a8SSascha Wildner DB_DRX_FUNC(dr4)
4690e6594a8SSascha Wildner DB_DRX_FUNC(dr5)
4700e6594a8SSascha Wildner DB_DRX_FUNC(dr6)
4710e6594a8SSascha Wildner DB_DRX_FUNC(dr7)
4720e6594a8SSascha Wildner 
4730e6594a8SSascha Wildner static int
474a76ca9b9SSascha Wildner kx86_64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
4750e6594a8SSascha Wildner 	       struct dbreg *d)
4760e6594a8SSascha Wildner {
4770e6594a8SSascha Wildner 	int i;
4780e6594a8SSascha Wildner 	unsigned int mask;
4790e6594a8SSascha Wildner 
4800e6594a8SSascha Wildner 	if (watchnum == -1) {
4810e6594a8SSascha Wildner 		for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
4820e6594a8SSascha Wildner 			if ((d->dr[7] & mask) == 0)
4830e6594a8SSascha Wildner 				break;
4840e6594a8SSascha Wildner 		if (i < 4)
4850e6594a8SSascha Wildner 			watchnum = i;
4860e6594a8SSascha Wildner 		else
4870e6594a8SSascha Wildner 			return(-1);
4880e6594a8SSascha Wildner 	}
4890e6594a8SSascha Wildner 
4900e6594a8SSascha Wildner 	switch (access) {
4910e6594a8SSascha Wildner 	case DBREG_DR7_EXEC:
4920e6594a8SSascha Wildner 		size = 1; /* size must be 1 for an execution breakpoint */
4930e6594a8SSascha Wildner 		/* fall through */
4940e6594a8SSascha Wildner 	case DBREG_DR7_WRONLY:
4950e6594a8SSascha Wildner 	case DBREG_DR7_RDWR:
4960e6594a8SSascha Wildner 		break;
4970e6594a8SSascha Wildner 	default:
4980e6594a8SSascha Wildner 		return(-1);
4990e6594a8SSascha Wildner 	}
5000e6594a8SSascha Wildner 
5010e6594a8SSascha Wildner 	/*
5020e6594a8SSascha Wildner 	 * we can watch a 1, 2, 4, or 8 byte sized location
5030e6594a8SSascha Wildner 	 */
5040e6594a8SSascha Wildner 	switch (size) {
5050e6594a8SSascha Wildner 	case 1:
5060e6594a8SSascha Wildner 		mask = 0x00;
5070e6594a8SSascha Wildner 		break;
5080e6594a8SSascha Wildner 	case 2:
5090e6594a8SSascha Wildner 		mask = 0x01 << 2;
5100e6594a8SSascha Wildner 		break;
5110e6594a8SSascha Wildner 	case 4:
5120e6594a8SSascha Wildner 		mask = 0x03 << 2;
5130da449fcSSascha Wildner 		break;
5140e6594a8SSascha Wildner 	case 8:
5150e6594a8SSascha Wildner 		mask = 0x02 << 2;
5160e6594a8SSascha Wildner 		break;
5170e6594a8SSascha Wildner 	default:
5180e6594a8SSascha Wildner 		return(-1);
5190e6594a8SSascha Wildner 	}
5200e6594a8SSascha Wildner 
5210e6594a8SSascha Wildner 	mask |= access;
5220e6594a8SSascha Wildner 
5230e6594a8SSascha Wildner 	/* clear the bits we are about to affect */
5240e6594a8SSascha Wildner 	d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
5250e6594a8SSascha Wildner 
5260e6594a8SSascha Wildner 	/* set drN register to the address, N=watchnum */
5270e6594a8SSascha Wildner 	DBREG_DRX(d, watchnum) = watchaddr;
5280e6594a8SSascha Wildner 
5290e6594a8SSascha Wildner 	/* enable the watchpoint */
5300e6594a8SSascha Wildner 	d->dr[7] |= (0x2 << (watchnum * 2)) | (mask << (watchnum * 4 + 16));
5310e6594a8SSascha Wildner 
5320e6594a8SSascha Wildner 	return(watchnum);
5330e6594a8SSascha Wildner }
5340e6594a8SSascha Wildner 
5350e6594a8SSascha Wildner 
5360e6594a8SSascha Wildner int
kx86_64_clr_watch(int watchnum,struct dbreg * d)537a76ca9b9SSascha Wildner kx86_64_clr_watch(int watchnum, struct dbreg *d)
5380e6594a8SSascha Wildner {
5390e6594a8SSascha Wildner 	if (watchnum < 0 || watchnum >= 4)
5400e6594a8SSascha Wildner 		return(-1);
5410e6594a8SSascha Wildner 
5420e6594a8SSascha Wildner 	d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
5430e6594a8SSascha Wildner 	DBREG_DRX(d, watchnum) = 0;
5440e6594a8SSascha Wildner 
5450e6594a8SSascha Wildner 	return(0);
5460e6594a8SSascha Wildner }
5470e6594a8SSascha Wildner 
5480e6594a8SSascha Wildner 
5490e6594a8SSascha Wildner int
db_md_set_watchpoint(db_expr_t addr,db_expr_t size)5500e6594a8SSascha Wildner db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
5510e6594a8SSascha Wildner {
5520e6594a8SSascha Wildner 	int avail, wsize;
5530e6594a8SSascha Wildner 	int i;
5540e6594a8SSascha Wildner 	struct dbreg d;
5550e6594a8SSascha Wildner 
5560e6594a8SSascha Wildner 	fill_dbregs(NULL, &d);
5570e6594a8SSascha Wildner 
5580e6594a8SSascha Wildner 	avail = 0;
5590e6594a8SSascha Wildner 	for (i = 0; i < 4; i++) {
5600e6594a8SSascha Wildner 		if ((d.dr[7] & (3 << (i * 2))) == 0)
5610e6594a8SSascha Wildner 			avail++;
5620e6594a8SSascha Wildner 	}
5630e6594a8SSascha Wildner 
5640e6594a8SSascha Wildner 	if (avail * 8 < size)
5650e6594a8SSascha Wildner 		return(-1);
5660e6594a8SSascha Wildner 
5670e6594a8SSascha Wildner 	for (i=0; i < 4 && (size != 0); i++) {
5680e6594a8SSascha Wildner 		if ((d.dr[7] & (3 << (i * 2))) == 0) {
5690e6594a8SSascha Wildner 			if (size >= 8 || (avail == 1 && size > 4))
5700e6594a8SSascha Wildner 				wsize = 8;
5710e6594a8SSascha Wildner 			else if (size > 2)
5720e6594a8SSascha Wildner 				wsize = 4;
5730e6594a8SSascha Wildner 			else
5740e6594a8SSascha Wildner 				wsize = size;
5750e6594a8SSascha Wildner 			if (wsize == 3)
5760e6594a8SSascha Wildner 				wsize++;
577a76ca9b9SSascha Wildner 			kx86_64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, &d);
5780e6594a8SSascha Wildner 			addr += wsize;
5790e6594a8SSascha Wildner 			size -= wsize;
5800e6594a8SSascha Wildner 		}
5810e6594a8SSascha Wildner 	}
5820e6594a8SSascha Wildner 
5830e6594a8SSascha Wildner 	set_dbregs(NULL, &d);
5840e6594a8SSascha Wildner 
5850e6594a8SSascha Wildner 	return(0);
5860e6594a8SSascha Wildner }
5870e6594a8SSascha Wildner 
5880e6594a8SSascha Wildner int
db_md_clr_watchpoint(db_expr_t addr,db_expr_t size)5890e6594a8SSascha Wildner db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
5900e6594a8SSascha Wildner {
5910e6594a8SSascha Wildner 	struct dbreg d;
5920e6594a8SSascha Wildner 	int i;
5930e6594a8SSascha Wildner 
5940e6594a8SSascha Wildner 	fill_dbregs(NULL, &d);
5950e6594a8SSascha Wildner 
5960e6594a8SSascha Wildner 	for(i = 0; i < 4; i++) {
5970e6594a8SSascha Wildner 		if (d.dr[7] & (3 << (i * 2))) {
5980e6594a8SSascha Wildner 			if ((DBREG_DRX((&d), i) >= addr) &&
5990e6594a8SSascha Wildner 			    (DBREG_DRX((&d), i) < addr + size))
600a76ca9b9SSascha Wildner 				kx86_64_clr_watch(i, &d);
6010e6594a8SSascha Wildner 		}
6020e6594a8SSascha Wildner 	}
6030e6594a8SSascha Wildner 
6040e6594a8SSascha Wildner 	set_dbregs(NULL, &d);
6050e6594a8SSascha Wildner 
6060e6594a8SSascha Wildner 	return(0);
6070e6594a8SSascha Wildner }
6080e6594a8SSascha Wildner 
6090e6594a8SSascha Wildner static char *
watchtype_str(int type)6100e6594a8SSascha Wildner watchtype_str(int type)
6110e6594a8SSascha Wildner {
6120e6594a8SSascha Wildner 	switch (type) {
6130e6594a8SSascha Wildner 	case DBREG_DR7_EXEC:
6140e6594a8SSascha Wildner 		return "execute";
6150e6594a8SSascha Wildner 	case DBREG_DR7_RDWR:
6160e6594a8SSascha Wildner 		return "read/write";
6170e6594a8SSascha Wildner 	case DBREG_DR7_WRONLY:
6180e6594a8SSascha Wildner 		return "write";
6190e6594a8SSascha Wildner 	default:
6200e6594a8SSascha Wildner 		return "invalid";
6210e6594a8SSascha Wildner 	}
6220e6594a8SSascha Wildner }
6230e6594a8SSascha Wildner 
6240e6594a8SSascha Wildner void
db_md_list_watchpoints(void)6250e6594a8SSascha Wildner db_md_list_watchpoints(void)
6260e6594a8SSascha Wildner {
6270e6594a8SSascha Wildner 	int i;
6280e6594a8SSascha Wildner 	struct dbreg d;
6290e6594a8SSascha Wildner 
6300e6594a8SSascha Wildner 	fill_dbregs(NULL, &d);
6310e6594a8SSascha Wildner 
6320e6594a8SSascha Wildner 	db_printf("\nhardware watchpoints:\n");
6330e6594a8SSascha Wildner 	db_printf("  watch    status        type  len     address\n"
6340e6594a8SSascha Wildner 		  "  -----  --------  ----------  ---  ----------\n");
6350e6594a8SSascha Wildner 	for (i = 0; i < 4; i++) {
6360e6594a8SSascha Wildner 		if (d.dr[7] & (0x03 << (i * 2))) {
6370e6594a8SSascha Wildner 			unsigned type, len;
6380e6594a8SSascha Wildner 			type = (d.dr[7] >> (16 + (i * 4))) & 3;
6390e6594a8SSascha Wildner 			len =  (d.dr[7] >> (16 + (i * 4) + 2)) & 3;
6400e6594a8SSascha Wildner 			db_printf("  %-5d  %-8s  %10s  %3d  0x%08lx\n",
6410e6594a8SSascha Wildner 				  i, "enabled", watchtype_str(type),
6420e6594a8SSascha Wildner 				  len + 1, DBREG_DRX((&d), i));
6430e6594a8SSascha Wildner 		} else {
6440e6594a8SSascha Wildner 			db_printf("  %-5d  disabled\n", i);
6450e6594a8SSascha Wildner 		}
6460e6594a8SSascha Wildner 	}
6470e6594a8SSascha Wildner 
6480e6594a8SSascha Wildner 	db_printf("\ndebug register values:\n");
6490e6594a8SSascha Wildner 	for (i = 0; i < 8; i++)
6500e6594a8SSascha Wildner 		db_printf("  dr%d 0x%08lx\n", i, DBREG_DRX((&d),i));
6510e6594a8SSascha Wildner 	db_printf("\n");
6520e6594a8SSascha Wildner }
6530e6594a8SSascha Wildner 
6540e6594a8SSascha Wildner /*
6550e6594a8SSascha Wildner  * See if dladdr() can get the symbol name via the standard dynamic loader.
6560e6594a8SSascha Wildner  */
6570e6594a8SSascha Wildner static
6580e6594a8SSascha Wildner void
dl_symbol_values(long callpc,const char ** name)6590e6594a8SSascha Wildner dl_symbol_values(long callpc, const char **name)
6600e6594a8SSascha Wildner {
6610e6594a8SSascha Wildner 	Dl_info info;
6620e6594a8SSascha Wildner 
6630e6594a8SSascha Wildner 	if (*name == NULL) {
6640e6594a8SSascha Wildner 		if (dladdr((const void *)callpc, &info) != 0) {
6650e6594a8SSascha Wildner 			if (info.dli_saddr <= (const void *)callpc)
6660e6594a8SSascha Wildner 				*name = info.dli_sname;
6670e6594a8SSascha Wildner 		}
6680e6594a8SSascha Wildner 	}
6690e6594a8SSascha Wildner }
670