xref: /dragonfly/sys/platform/pc64/x86_64/db_trace.c (revision 2a7bd4d8)
1b2b3ffcdSSimon Schubert /*
2b2b3ffcdSSimon Schubert  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3b2b3ffcdSSimon Schubert  *
4b2b3ffcdSSimon Schubert  * Redistribution and use in source and binary forms, with or without
5b2b3ffcdSSimon Schubert  * modification, are permitted provided that the following conditions
6b2b3ffcdSSimon Schubert  * are met:
7b2b3ffcdSSimon Schubert  *
8b2b3ffcdSSimon Schubert  * 1. Redistributions of source code must retain the above copyright
9b2b3ffcdSSimon Schubert  *    notice, this list of conditions and the following disclaimer.
10b2b3ffcdSSimon Schubert  * 2. Redistributions in binary form must reproduce the above copyright
11b2b3ffcdSSimon Schubert  *    notice, this list of conditions and the following disclaimer in
12b2b3ffcdSSimon Schubert  *    the documentation and/or other materials provided with the
13b2b3ffcdSSimon Schubert  *    distribution.
14b2b3ffcdSSimon Schubert  * 3. Neither the name of The DragonFly Project nor the names of its
15b2b3ffcdSSimon Schubert  *    contributors may be used to endorse or promote products derived
16b2b3ffcdSSimon Schubert  *    from this software without specific, prior written permission.
17b2b3ffcdSSimon Schubert  *
18b2b3ffcdSSimon Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19b2b3ffcdSSimon Schubert  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20b2b3ffcdSSimon Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21b2b3ffcdSSimon Schubert  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22b2b3ffcdSSimon Schubert  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23b2b3ffcdSSimon Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24b2b3ffcdSSimon Schubert  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25b2b3ffcdSSimon Schubert  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26b2b3ffcdSSimon Schubert  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27b2b3ffcdSSimon Schubert  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28b2b3ffcdSSimon Schubert  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29b2b3ffcdSSimon Schubert  * SUCH DAMAGE.
30b2b3ffcdSSimon Schubert  *
31b2b3ffcdSSimon Schubert  * --
32b2b3ffcdSSimon Schubert  *
33b2b3ffcdSSimon Schubert  * Mach Operating System
34b2b3ffcdSSimon Schubert  * Copyright (c) 1991,1990 Carnegie Mellon University
35b2b3ffcdSSimon Schubert  * All Rights Reserved.
36b2b3ffcdSSimon Schubert  *
37b2b3ffcdSSimon Schubert  * Permission to use, copy, modify and distribute this software and its
38b2b3ffcdSSimon Schubert  * documentation is hereby granted, provided that both the copyright
39b2b3ffcdSSimon Schubert  * notice and this permission notice appear in all copies of the
40b2b3ffcdSSimon Schubert  * software, derivative works or modified versions, and any portions
41b2b3ffcdSSimon Schubert  * thereof, and that both notices appear in supporting documentation.
42b2b3ffcdSSimon Schubert  *
43b2b3ffcdSSimon Schubert  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
44b2b3ffcdSSimon Schubert  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
45b2b3ffcdSSimon Schubert  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46b2b3ffcdSSimon Schubert  *
47b2b3ffcdSSimon Schubert  * Carnegie Mellon requests users of this software to return to
48b2b3ffcdSSimon Schubert  *
49b2b3ffcdSSimon Schubert  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
50b2b3ffcdSSimon Schubert  *  School of Computer Science
51b2b3ffcdSSimon Schubert  *  Carnegie Mellon University
52b2b3ffcdSSimon Schubert  *  Pittsburgh PA 15213-3890
53b2b3ffcdSSimon Schubert  *
54b2b3ffcdSSimon Schubert  * any improvements or extensions that they make and grant Carnegie the
55b2b3ffcdSSimon Schubert  * rights to redistribute these changes.
56b2b3ffcdSSimon Schubert  *
57b2b3ffcdSSimon Schubert  * $FreeBSD: src/sys/i386/i386/db_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
58b2b3ffcdSSimon Schubert  */
59b2b3ffcdSSimon Schubert 
60b2b3ffcdSSimon Schubert #include <sys/param.h>
61b2b3ffcdSSimon Schubert #include <sys/systm.h>
62b2b3ffcdSSimon Schubert #include <sys/linker_set.h>
63b2b3ffcdSSimon Schubert #include <sys/lock.h>
64b2b3ffcdSSimon Schubert #include <sys/proc.h>
65b2b3ffcdSSimon Schubert #include <sys/reg.h>
66b2b3ffcdSSimon Schubert 
67b2b3ffcdSSimon Schubert #include <machine/cpu.h>
68b2b3ffcdSSimon Schubert #include <machine/md_var.h>
69b2b3ffcdSSimon Schubert 
70b2b3ffcdSSimon Schubert #include <vm/vm.h>
71b2b3ffcdSSimon Schubert #include <vm/vm_param.h>
72b2b3ffcdSSimon Schubert #include <vm/pmap.h>
73b2b3ffcdSSimon Schubert #include <vm/vm_map.h>
74b2b3ffcdSSimon Schubert #include <ddb/ddb.h>
75b2b3ffcdSSimon Schubert 
76b2b3ffcdSSimon Schubert #include <ddb/db_access.h>
77b2b3ffcdSSimon Schubert #include <ddb/db_sym.h>
78b2b3ffcdSSimon Schubert #include <ddb/db_variables.h>
79b2b3ffcdSSimon Schubert 
80b2b3ffcdSSimon Schubert db_varfcn_t db_dr0;
81b2b3ffcdSSimon Schubert db_varfcn_t db_dr1;
82b2b3ffcdSSimon Schubert db_varfcn_t db_dr2;
83b2b3ffcdSSimon Schubert db_varfcn_t db_dr3;
84b2b3ffcdSSimon Schubert db_varfcn_t db_dr4;
85b2b3ffcdSSimon Schubert db_varfcn_t db_dr5;
86b2b3ffcdSSimon Schubert db_varfcn_t db_dr6;
87b2b3ffcdSSimon Schubert db_varfcn_t db_dr7;
88b2b3ffcdSSimon Schubert 
89b2b3ffcdSSimon Schubert /*
90b2b3ffcdSSimon Schubert  * Machine register set.
91b2b3ffcdSSimon Schubert  */
92b2b3ffcdSSimon Schubert struct db_variable db_regs[] = {
93b2b3ffcdSSimon Schubert 	{ "cs",		&ddb_regs.tf_cs,     NULL },
94b2b3ffcdSSimon Schubert /*	{ "ds",		&ddb_regs.tf_ds,     NULL },
95b2b3ffcdSSimon Schubert 	{ "es",		&ddb_regs.tf_es,     NULL },
96b2b3ffcdSSimon Schubert 	{ "fs",		&ddb_regs.tf_fs,     NULL },
97b2b3ffcdSSimon Schubert 	{ "gs",		&ddb_regs.tf_gs,     NULL }, */
98b2b3ffcdSSimon Schubert 	{ "ss",		&ddb_regs.tf_ss,     NULL },
99b2b3ffcdSSimon Schubert 	{ "rax",	&ddb_regs.tf_rax,    NULL },
100b2b3ffcdSSimon Schubert 	{ "rcx",	&ddb_regs.tf_rcx,    NULL },
101b2b3ffcdSSimon Schubert 	{ "rdx",	&ddb_regs.tf_rdx,    NULL },
102b2b3ffcdSSimon Schubert 	{ "rbx",	&ddb_regs.tf_rbx,    NULL },
103b2b3ffcdSSimon Schubert 	{ "rsp",	&ddb_regs.tf_rsp,    NULL },
104b2b3ffcdSSimon Schubert 	{ "rbp",	&ddb_regs.tf_rbp,    NULL },
105b2b3ffcdSSimon Schubert 	{ "rsi",	&ddb_regs.tf_rsi,    NULL },
106b2b3ffcdSSimon Schubert 	{ "rdi",	&ddb_regs.tf_rdi,    NULL },
107b2b3ffcdSSimon Schubert 	{ "rip",	&ddb_regs.tf_rip,    NULL },
108b2b3ffcdSSimon Schubert 	{ "rfl",	&ddb_regs.tf_rflags, NULL },
109b2b3ffcdSSimon Schubert 	{ "r8",		&ddb_regs.tf_r8,     NULL },
110b2b3ffcdSSimon Schubert 	{ "r9",		&ddb_regs.tf_r9,     NULL },
111b2b3ffcdSSimon Schubert 	{ "r10",	&ddb_regs.tf_r10,    NULL },
112b2b3ffcdSSimon Schubert 	{ "r11",	&ddb_regs.tf_r11,    NULL },
113b2b3ffcdSSimon Schubert 	{ "r12",	&ddb_regs.tf_r12,    NULL },
114b2b3ffcdSSimon Schubert 	{ "r13",	&ddb_regs.tf_r13,    NULL },
115b2b3ffcdSSimon Schubert 	{ "r14",	&ddb_regs.tf_r14,    NULL },
116b2b3ffcdSSimon Schubert 	{ "r15",	&ddb_regs.tf_r15,    NULL },
117b2b3ffcdSSimon Schubert 	{ "dr0",	NULL,		     db_dr0 },
118b2b3ffcdSSimon Schubert 	{ "dr1",	NULL,		     db_dr1 },
119b2b3ffcdSSimon Schubert 	{ "dr2",	NULL,		     db_dr2 },
120b2b3ffcdSSimon Schubert 	{ "dr3",	NULL,		     db_dr3 },
121b2b3ffcdSSimon Schubert 	{ "dr4",	NULL,		     db_dr4 },
122b2b3ffcdSSimon Schubert 	{ "dr5",	NULL,		     db_dr5 },
123b2b3ffcdSSimon Schubert 	{ "dr6",	NULL,		     db_dr6 },
124b2b3ffcdSSimon Schubert 	{ "dr7",	NULL,		     db_dr7 },
125b2b3ffcdSSimon Schubert };
126c157ff7aSSascha Wildner struct db_variable *db_eregs = db_regs + NELEM(db_regs);
127b2b3ffcdSSimon Schubert 
128b2b3ffcdSSimon Schubert /*
129b2b3ffcdSSimon Schubert  * Stack trace.
130b2b3ffcdSSimon Schubert  */
131b2b3ffcdSSimon Schubert #define	INKERNEL(va)	(((vm_offset_t)(va)) >= USRSTACK)
132b2b3ffcdSSimon Schubert 
133b2b3ffcdSSimon Schubert struct x86_64_frame {
134b2b3ffcdSSimon Schubert 	struct x86_64_frame	*f_frame;
135b2b3ffcdSSimon Schubert 	long			f_retaddr;
136b2b3ffcdSSimon Schubert 	long			f_arg0;
137b2b3ffcdSSimon Schubert };
138b2b3ffcdSSimon Schubert 
139b2b3ffcdSSimon Schubert #define NORMAL		0
140b2b3ffcdSSimon Schubert #define	TRAP		1
141b2b3ffcdSSimon Schubert #define	INTERRUPT	2
142b2b3ffcdSSimon Schubert #define	SYSCALL		3
143b2b3ffcdSSimon Schubert 
144b2b3ffcdSSimon Schubert static void	db_nextframe(struct x86_64_frame **, db_addr_t *);
145b2b3ffcdSSimon Schubert static int	db_numargs(struct x86_64_frame *);
146b2b3ffcdSSimon Schubert static void	db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
147b2b3ffcdSSimon Schubert static void	dl_symbol_values(long callpc, const char **name);
148b2b3ffcdSSimon Schubert 
149b2b3ffcdSSimon Schubert 
150b2b3ffcdSSimon Schubert static char	*watchtype_str(int type);
151b2b3ffcdSSimon Schubert static int	kx86_64_set_watch(int watchnum, unsigned int watchaddr,
152b2b3ffcdSSimon Schubert                                int size, int access, struct dbreg * d);
153b2b3ffcdSSimon Schubert static int	kx86_64_clr_watch(int watchnum, struct dbreg * d);
154b2b3ffcdSSimon Schubert int		db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
155b2b3ffcdSSimon Schubert int		db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
156b2b3ffcdSSimon Schubert void		db_md_list_watchpoints(void);
157b2b3ffcdSSimon Schubert 
158b2b3ffcdSSimon Schubert 
159b2b3ffcdSSimon Schubert /*
160b2b3ffcdSSimon Schubert  * Figure out how many arguments were passed into the frame at "fp".
161b2b3ffcdSSimon Schubert  */
162b2b3ffcdSSimon Schubert static int
db_numargs(struct x86_64_frame * fp)163b2b3ffcdSSimon Schubert db_numargs(struct x86_64_frame *fp)
164b2b3ffcdSSimon Schubert {
165b2b3ffcdSSimon Schubert #if 1
166b2b3ffcdSSimon Schubert 	return (0);	/* regparm, needs dwarf2 info */
167b2b3ffcdSSimon Schubert #else
168b2b3ffcdSSimon Schubert 	int	args;
169b2b3ffcdSSimon Schubert #if 0
170b2b3ffcdSSimon Schubert 	int	*argp;
171b2b3ffcdSSimon Schubert 	int	inst;
172b2b3ffcdSSimon Schubert 
173b2b3ffcdSSimon Schubert 	argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
174b2b3ffcdSSimon Schubert 	/*
175b2b3ffcdSSimon Schubert 	 * XXX etext is wrong for LKMs.  We should attempt to interpret
176b2b3ffcdSSimon Schubert 	 * the instruction at the return address in all cases.  This
177b2b3ffcdSSimon Schubert 	 * may require better fault handling.
178b2b3ffcdSSimon Schubert 	 */
179b2b3ffcdSSimon Schubert 	if (argp < (int *)btext || argp >= (int *)etext) {
180b2b3ffcdSSimon Schubert 		args = 5;
181b2b3ffcdSSimon Schubert 	} else {
182b2b3ffcdSSimon Schubert 		inst = db_get_value((int)argp, 4, FALSE);
183b2b3ffcdSSimon Schubert 		if ((inst & 0xff) == 0x59)	/* popl %ecx */
184b2b3ffcdSSimon Schubert 			args = 1;
185b2b3ffcdSSimon Schubert 		else if ((inst & 0xffff) == 0xc483)	/* addl $Ibs, %esp */
186b2b3ffcdSSimon Schubert 			args = ((inst >> 16) & 0xff) / 4;
187b2b3ffcdSSimon Schubert 		else
188b2b3ffcdSSimon Schubert 			args = 5;
189b2b3ffcdSSimon Schubert 	}
190b2b3ffcdSSimon Schubert #endif
191b2b3ffcdSSimon Schubert 	args = 5;
192b2b3ffcdSSimon Schubert 	return(args);
193b2b3ffcdSSimon Schubert #endif
194b2b3ffcdSSimon Schubert }
195b2b3ffcdSSimon Schubert 
196b2b3ffcdSSimon Schubert static void
db_print_stack_entry(const char * name,int narg,char ** argnp,long * argp,db_addr_t callpc)197b2b3ffcdSSimon Schubert db_print_stack_entry(const char *name, int narg, char **argnp, long *argp,
198b2b3ffcdSSimon Schubert 		     db_addr_t callpc)
199b2b3ffcdSSimon Schubert {
200b2b3ffcdSSimon Schubert 	db_printf("%s(", name);
201b2b3ffcdSSimon Schubert 	while (narg) {
202b2b3ffcdSSimon Schubert 		if (argnp)
203b2b3ffcdSSimon Schubert 			db_printf("%s=", *argnp++);
204b2b3ffcdSSimon Schubert 		db_printf("%ld", (long)db_get_value((long)argp, 8, FALSE));
205b2b3ffcdSSimon Schubert 		argp++;
206b2b3ffcdSSimon Schubert 		if (--narg != 0)
207b2b3ffcdSSimon Schubert 			db_printf(",");
208b2b3ffcdSSimon Schubert 	}
209b2b3ffcdSSimon Schubert 	db_printf(") at ");
210b2b3ffcdSSimon Schubert 	db_printsym(callpc, DB_STGY_PROC);
211ebd07f54SVenkatesh Srinivas 	db_printf(" %p ",  (void*) callpc);
212b2b3ffcdSSimon Schubert 	db_printf("\n");
213b2b3ffcdSSimon Schubert }
214b2b3ffcdSSimon Schubert 
215b2b3ffcdSSimon Schubert /*
216b2b3ffcdSSimon Schubert  * Figure out the next frame up in the call stack.
217b2b3ffcdSSimon Schubert  */
218b2b3ffcdSSimon Schubert static void
db_nextframe(struct x86_64_frame ** fp,db_addr_t * ip)219b2b3ffcdSSimon Schubert db_nextframe(struct x86_64_frame **fp, db_addr_t *ip)
220b2b3ffcdSSimon Schubert {
221b2b3ffcdSSimon Schubert 	struct trapframe *tf;
222b2b3ffcdSSimon Schubert 	int frame_type;
223b2b3ffcdSSimon Schubert 	long rip, rsp, rbp;
224b2b3ffcdSSimon Schubert 	db_expr_t offset;
225b2b3ffcdSSimon Schubert 	const char *sym, *name;
226b2b3ffcdSSimon Schubert 
227b2b3ffcdSSimon Schubert 	if ((unsigned long)*fp < PAGE_SIZE) {
228b2b3ffcdSSimon Schubert 		*fp = NULL;
229b2b3ffcdSSimon Schubert 		return;
230b2b3ffcdSSimon Schubert 	}
231b2b3ffcdSSimon Schubert 	rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
232b2b3ffcdSSimon Schubert 	rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
233b2b3ffcdSSimon Schubert 
234b2b3ffcdSSimon Schubert 	/*
235b2b3ffcdSSimon Schubert 	 * Figure out frame type.
236b2b3ffcdSSimon Schubert 	 */
237b2b3ffcdSSimon Schubert 
238b2b3ffcdSSimon Schubert 	frame_type = NORMAL;
239b2b3ffcdSSimon Schubert 
240b2b3ffcdSSimon Schubert 	sym = db_search_symbol(rip, DB_STGY_ANY, &offset);
241b2b3ffcdSSimon Schubert 	db_symbol_values(sym, &name, NULL);
242b2b3ffcdSSimon Schubert 	dl_symbol_values(rip, &name);
243b2b3ffcdSSimon Schubert 	if (name != NULL) {
244b2b3ffcdSSimon Schubert 		if (!strcmp(name, "calltrap")) {
245b2b3ffcdSSimon Schubert 			frame_type = TRAP;
246b2b3ffcdSSimon Schubert 		} else if (!strncmp(name, "Xresume", 7)) {
247b2b3ffcdSSimon Schubert 			frame_type = INTERRUPT;
248b2b3ffcdSSimon Schubert 		} else if (!strcmp(name, "_Xsyscall")) {
249b2b3ffcdSSimon Schubert 			frame_type = SYSCALL;
250b2b3ffcdSSimon Schubert 		}
251b2b3ffcdSSimon Schubert 	}
252b2b3ffcdSSimon Schubert 
253b2b3ffcdSSimon Schubert 	/*
254b2b3ffcdSSimon Schubert 	 * Normal frames need no special processing.
255b2b3ffcdSSimon Schubert 	 */
256b2b3ffcdSSimon Schubert 	if (frame_type == NORMAL) {
257b2b3ffcdSSimon Schubert 		*ip = (db_addr_t) rip;
258b2b3ffcdSSimon Schubert 		*fp = (struct x86_64_frame *) rbp;
259b2b3ffcdSSimon Schubert 		return;
260b2b3ffcdSSimon Schubert 	}
261b2b3ffcdSSimon Schubert 
262b2b3ffcdSSimon Schubert 	db_print_stack_entry(name, 0, 0, 0, rip);
263b2b3ffcdSSimon Schubert 
264b2b3ffcdSSimon Schubert 	/*
265b2b3ffcdSSimon Schubert 	 * Point to base of trapframe which is just above the
266b2b3ffcdSSimon Schubert 	 * current frame.
267b2b3ffcdSSimon Schubert 	 */
268b2b3ffcdSSimon Schubert 	tf = (struct trapframe *)((long)*fp + 16);
269b2b3ffcdSSimon Schubert 
270b2b3ffcdSSimon Schubert #if 0
271b2b3ffcdSSimon Schubert 	rsp = (ISPL(tf->tf_cs) == SEL_UPL) ?  tf->tf_rsp : (long)&tf->tf_rsp;
272b2b3ffcdSSimon Schubert #endif
273b2b3ffcdSSimon Schubert 	rsp = (long)&tf->tf_rsp;
274b2b3ffcdSSimon Schubert 
275b2b3ffcdSSimon Schubert 	switch (frame_type) {
276b2b3ffcdSSimon Schubert 	case TRAP:
277b2b3ffcdSSimon Schubert 		{
278b2b3ffcdSSimon Schubert 			rip = tf->tf_rip;
279b2b3ffcdSSimon Schubert 			rbp = tf->tf_rbp;
280b2b3ffcdSSimon Schubert 			db_printf(
281b2b3ffcdSSimon Schubert 	    "--- trap %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
282b2b3ffcdSSimon Schubert 			    tf->tf_trapno, rip, rsp, rbp);
283b2b3ffcdSSimon Schubert 		}
284b2b3ffcdSSimon Schubert 		break;
285b2b3ffcdSSimon Schubert 	case SYSCALL:
286b2b3ffcdSSimon Schubert 		{
287b2b3ffcdSSimon Schubert 			rip = tf->tf_rip;
288b2b3ffcdSSimon Schubert 			rbp = tf->tf_rbp;
289b2b3ffcdSSimon Schubert 			db_printf(
290b2b3ffcdSSimon Schubert 	"--- syscall %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
291b2b3ffcdSSimon Schubert 			    tf->tf_rax, rip, rsp, rbp);
292b2b3ffcdSSimon Schubert 		}
293b2b3ffcdSSimon Schubert 		break;
294b2b3ffcdSSimon Schubert 	case INTERRUPT:
295b2b3ffcdSSimon Schubert 		tf = (struct trapframe *)((long)*fp + 16);
296b2b3ffcdSSimon Schubert 		{
297b2b3ffcdSSimon Schubert 			rip = tf->tf_rip;
298b2b3ffcdSSimon Schubert 			rbp = tf->tf_rbp;
299b2b3ffcdSSimon Schubert 			db_printf(
300b2b3ffcdSSimon Schubert 	    "--- interrupt, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
301b2b3ffcdSSimon Schubert 			    rip, rsp, rbp);
302b2b3ffcdSSimon Schubert 		}
303b2b3ffcdSSimon Schubert 		break;
304b2b3ffcdSSimon Schubert 	default:
305b2b3ffcdSSimon Schubert 		break;
306b2b3ffcdSSimon Schubert 	}
307b2b3ffcdSSimon Schubert 
308b2b3ffcdSSimon Schubert 	*ip = (db_addr_t) rip;
309b2b3ffcdSSimon Schubert 	*fp = (struct x86_64_frame *) rbp;
310b2b3ffcdSSimon Schubert }
311b2b3ffcdSSimon Schubert 
312b2b3ffcdSSimon Schubert void
db_stack_trace_cmd(db_expr_t addr,boolean_t have_addr,db_expr_t count,char * modif)313b2b3ffcdSSimon Schubert db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
314b2b3ffcdSSimon Schubert 		   char *modif)
315b2b3ffcdSSimon Schubert {
316b2b3ffcdSSimon Schubert 	struct x86_64_frame *frame;
317b2b3ffcdSSimon Schubert 	long *argp;
318b2b3ffcdSSimon Schubert 	db_addr_t callpc;
319b2b3ffcdSSimon Schubert 	boolean_t first;
320b2b3ffcdSSimon Schubert 	int i;
321b2b3ffcdSSimon Schubert 
322b2b3ffcdSSimon Schubert 	if (count == -1)
323b2b3ffcdSSimon Schubert 		count = 1024;
324b2b3ffcdSSimon Schubert 
325b2b3ffcdSSimon Schubert 	if (!have_addr) {
326b2b3ffcdSSimon Schubert 		frame = (struct x86_64_frame *)BP_REGS(&ddb_regs);
327b2b3ffcdSSimon Schubert 		if (frame == NULL)
328b2b3ffcdSSimon Schubert 			frame = (struct x86_64_frame *)(SP_REGS(&ddb_regs) - 8);
329b2b3ffcdSSimon Schubert 		callpc = PC_REGS(&ddb_regs);
330b2b3ffcdSSimon Schubert 	} else {
331b2b3ffcdSSimon Schubert 		/*
332b2b3ffcdSSimon Schubert 		 * Look for something that might be a frame pointer, just as
333b2b3ffcdSSimon Schubert 		 * a convenience.
334b2b3ffcdSSimon Schubert 		 */
335b2b3ffcdSSimon Schubert 		frame = (struct x86_64_frame *)addr;
336b2b3ffcdSSimon Schubert 		for (i = 0; i < 4096; i += 8) {
337b2b3ffcdSSimon Schubert 			struct x86_64_frame *check;
338b2b3ffcdSSimon Schubert 
339b2b3ffcdSSimon Schubert 			check = (struct x86_64_frame *)db_get_value((long)((char *)&frame->f_frame + i), 8, FALSE);
340b2b3ffcdSSimon Schubert 			if ((char *)check - (char *)frame >= 0 &&
341b2b3ffcdSSimon Schubert 			    (char *)check - (char *)frame < 4096
342b2b3ffcdSSimon Schubert 			) {
343b2b3ffcdSSimon Schubert 				break;
344b2b3ffcdSSimon Schubert 			}
345b2b3ffcdSSimon Schubert 			db_printf("%p does not look like a stack frame, skipping\n", (char *)&frame->f_frame + i);
346b2b3ffcdSSimon Schubert 		}
347b2b3ffcdSSimon Schubert 		if (i == 4096) {
348b2b3ffcdSSimon Schubert 			db_printf("Unable to find anything that looks like a stack frame\n");
349b2b3ffcdSSimon Schubert 			return;
350b2b3ffcdSSimon Schubert 		}
351b2b3ffcdSSimon Schubert 		frame = (void *)((char *)frame + i);
352b2b3ffcdSSimon Schubert 		db_printf("Trace beginning at frame %p\n", frame);
353b2b3ffcdSSimon Schubert 		callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
354b2b3ffcdSSimon Schubert 	}
355b2b3ffcdSSimon Schubert 
356b2b3ffcdSSimon Schubert 	first = TRUE;
357b2b3ffcdSSimon Schubert 	while (count--) {
358b2b3ffcdSSimon Schubert 		struct x86_64_frame *actframe;
359b2b3ffcdSSimon Schubert 		int		narg;
360b2b3ffcdSSimon Schubert 		const char *	name;
361b2b3ffcdSSimon Schubert 		db_expr_t	offset;
362b2b3ffcdSSimon Schubert 		c_db_sym_t	sym;
363b2b3ffcdSSimon Schubert #define MAXNARG	16
364b2b3ffcdSSimon Schubert 		char	*argnames[MAXNARG], **argnp = NULL;
365b2b3ffcdSSimon Schubert 
366b2b3ffcdSSimon Schubert 		sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
367b2b3ffcdSSimon Schubert 		db_symbol_values(sym, &name, NULL);
368b2b3ffcdSSimon Schubert 		dl_symbol_values(callpc, &name);
369b2b3ffcdSSimon Schubert 
370b2b3ffcdSSimon Schubert 		/*
371b2b3ffcdSSimon Schubert 		 * Attempt to determine a (possibly fake) frame that gives
372b2b3ffcdSSimon Schubert 		 * the caller's pc.  It may differ from `frame' if the
373b2b3ffcdSSimon Schubert 		 * current function never sets up a standard frame or hasn't
374b2b3ffcdSSimon Schubert 		 * set one up yet or has just discarded one.  The last two
375b2b3ffcdSSimon Schubert 		 * cases can be guessed fairly reliably for code generated
376b2b3ffcdSSimon Schubert 		 * by gcc.  The first case is too much trouble to handle in
377b2b3ffcdSSimon Schubert 		 * general because the amount of junk on the stack depends
378b2b3ffcdSSimon Schubert 		 * on the pc (the special handling of "calltrap", etc. in
379b2b3ffcdSSimon Schubert 		 * db_nextframe() works because the `next' pc is special).
380b2b3ffcdSSimon Schubert 		 */
381b2b3ffcdSSimon Schubert 		actframe = frame;
382b2b3ffcdSSimon Schubert 		if (first) {
383b2b3ffcdSSimon Schubert 			if (!have_addr) {
384b2b3ffcdSSimon Schubert 				int instr;
385b2b3ffcdSSimon Schubert 
386b2b3ffcdSSimon Schubert 				instr = db_get_value(callpc, 4, FALSE);
387b2b3ffcdSSimon Schubert 				if ((instr & 0xffffffff) == 0xe5894855) {
388b2b3ffcdSSimon Schubert 					/* pushq %rbp; movq %rsp, %rbp */
389b2b3ffcdSSimon Schubert 					actframe = (struct x86_64_frame *)
390b2b3ffcdSSimon Schubert 					    (SP_REGS(&ddb_regs) - 8);
391b2b3ffcdSSimon Schubert 				} else if ((instr & 0xffffff) == 0xe58948) {
392b2b3ffcdSSimon Schubert 					/* movq %rsp, %rbp */
393b2b3ffcdSSimon Schubert 					actframe = (struct x86_64_frame *)
394b2b3ffcdSSimon Schubert 					    SP_REGS(&ddb_regs);
395b2b3ffcdSSimon Schubert 					if (ddb_regs.tf_rbp == 0) {
396b2b3ffcdSSimon Schubert 						/* Fake caller's frame better. */
397b2b3ffcdSSimon Schubert 						frame = actframe;
398b2b3ffcdSSimon Schubert 					}
399b2b3ffcdSSimon Schubert 				} else if ((instr & 0xff) == 0xc3) {
400b2b3ffcdSSimon Schubert 					/* ret */
401b2b3ffcdSSimon Schubert 					actframe = (struct x86_64_frame *)
402b2b3ffcdSSimon Schubert 					    (SP_REGS(&ddb_regs) - 8);
403b2b3ffcdSSimon Schubert 				} else if (offset == 0) {
404b2b3ffcdSSimon Schubert 					/* Probably a symbol in assembler code. */
405b2b3ffcdSSimon Schubert 					actframe = (struct x86_64_frame *)
406b2b3ffcdSSimon Schubert 					    (SP_REGS(&ddb_regs) - 8);
407b2b3ffcdSSimon Schubert 				}
408b2b3ffcdSSimon Schubert 			} else if (name != NULL &&
409b2b3ffcdSSimon Schubert 				   strcmp(name, "fork_trampoline") == 0) {
410b2b3ffcdSSimon Schubert 				/*
411b2b3ffcdSSimon Schubert 				 * Don't try to walk back on a stack for a
412b2b3ffcdSSimon Schubert 				 * process that hasn't actually been run yet.
413b2b3ffcdSSimon Schubert 				 */
414b2b3ffcdSSimon Schubert 				db_print_stack_entry(name, 0, 0, 0, callpc);
415b2b3ffcdSSimon Schubert 				break;
416b2b3ffcdSSimon Schubert 			}
417b2b3ffcdSSimon Schubert 			first = FALSE;
418b2b3ffcdSSimon Schubert 		}
419b2b3ffcdSSimon Schubert 
420b2b3ffcdSSimon Schubert 		argp = &actframe->f_arg0;
421b2b3ffcdSSimon Schubert 		narg = MAXNARG;
422b2b3ffcdSSimon Schubert 		if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
423b2b3ffcdSSimon Schubert 			argnp = argnames;
424b2b3ffcdSSimon Schubert 		} else {
425b2b3ffcdSSimon Schubert 			narg = db_numargs(frame);
426b2b3ffcdSSimon Schubert 		}
427b2b3ffcdSSimon Schubert 
428b2b3ffcdSSimon Schubert 		db_print_stack_entry(name, narg, argnp, argp, callpc);
429b2b3ffcdSSimon Schubert 
430*a1495858SMatthew Dillon 		/*
431*a1495858SMatthew Dillon 		 * Stop at the system call boundary (else we risk
432*a1495858SMatthew Dillon 		 * double-faulting on junk).
433*a1495858SMatthew Dillon 		 */
434*a1495858SMatthew Dillon 		if (name && strcmp(name, "Xfast_syscall") == 0)
435*a1495858SMatthew Dillon 			break;
436*a1495858SMatthew Dillon 
437b2b3ffcdSSimon Schubert 		if (actframe != frame) {
438b2b3ffcdSSimon Schubert 			/* `frame' belongs to caller. */
439b2b3ffcdSSimon Schubert 			callpc = (db_addr_t)
440b2b3ffcdSSimon Schubert 			    db_get_value((long)&actframe->f_retaddr, 8, FALSE);
441b2b3ffcdSSimon Schubert 			continue;
442b2b3ffcdSSimon Schubert 		}
443b2b3ffcdSSimon Schubert 
444b2b3ffcdSSimon Schubert 		db_nextframe(&frame, &callpc);
4454090d6ffSSascha Wildner 		if (frame == NULL)
446b2b3ffcdSSimon Schubert 			break;
447b2b3ffcdSSimon Schubert 	}
448b2b3ffcdSSimon Schubert }
449b2b3ffcdSSimon Schubert 
450b2b3ffcdSSimon Schubert void
print_backtrace(int count)4517ce2998eSAlex Hornung print_backtrace(int count)
452b2b3ffcdSSimon Schubert {
453b2b3ffcdSSimon Schubert 	register_t  rbp;
454b2b3ffcdSSimon Schubert 
455b2b3ffcdSSimon Schubert 	__asm __volatile("movq %%rbp, %0" : "=r" (rbp));
4567ce2998eSAlex Hornung 	db_stack_trace_cmd(rbp, 1, count, NULL);
457b2b3ffcdSSimon Schubert }
458b2b3ffcdSSimon Schubert 
459b2b3ffcdSSimon Schubert #define DB_DRX_FUNC(reg)						\
460b2b3ffcdSSimon Schubert int									\
461b2b3ffcdSSimon Schubert db_ ## reg (struct db_variable *vp, db_expr_t *valuep, int op)		\
462b2b3ffcdSSimon Schubert {									\
463b2b3ffcdSSimon Schubert 	if (op == DB_VAR_GET)						\
464b2b3ffcdSSimon Schubert 		*valuep = r ## reg ();					\
465b2b3ffcdSSimon Schubert 	else								\
466b2b3ffcdSSimon Schubert 		load_ ## reg (*valuep); 				\
467b2b3ffcdSSimon Schubert 									\
468b2b3ffcdSSimon Schubert 	return(0);							\
469b2b3ffcdSSimon Schubert }
470b2b3ffcdSSimon Schubert 
471b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr0)
DB_DRX_FUNC(dr1)472b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr1)
473b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr2)
474b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr3)
475b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr4)
476b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr5)
477b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr6)
478b2b3ffcdSSimon Schubert DB_DRX_FUNC(dr7)
479b2b3ffcdSSimon Schubert 
480b2b3ffcdSSimon Schubert static int
481b2b3ffcdSSimon Schubert kx86_64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
482b2b3ffcdSSimon Schubert 	       struct dbreg *d)
483b2b3ffcdSSimon Schubert {
484b2b3ffcdSSimon Schubert 	int i;
485b2b3ffcdSSimon Schubert 	unsigned int mask;
486b2b3ffcdSSimon Schubert 
487b2b3ffcdSSimon Schubert 	if (watchnum == -1) {
488b2b3ffcdSSimon Schubert 		for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
489b2b3ffcdSSimon Schubert 			if ((d->dr[7] & mask) == 0)
490b2b3ffcdSSimon Schubert 				break;
491b2b3ffcdSSimon Schubert 		if (i < 4)
492b2b3ffcdSSimon Schubert 			watchnum = i;
493b2b3ffcdSSimon Schubert 		else
494b2b3ffcdSSimon Schubert 			return(-1);
495b2b3ffcdSSimon Schubert 	}
496b2b3ffcdSSimon Schubert 
497b2b3ffcdSSimon Schubert 	switch (access) {
498b2b3ffcdSSimon Schubert 	case DBREG_DR7_EXEC:
499b2b3ffcdSSimon Schubert 		size = 1; /* size must be 1 for an execution breakpoint */
500b2b3ffcdSSimon Schubert 		/* fall through */
501b2b3ffcdSSimon Schubert 	case DBREG_DR7_WRONLY:
502b2b3ffcdSSimon Schubert 	case DBREG_DR7_RDWR:
503b2b3ffcdSSimon Schubert 		break;
504b2b3ffcdSSimon Schubert 	default:
505b2b3ffcdSSimon Schubert 		return(-1);
506b2b3ffcdSSimon Schubert 	}
507b2b3ffcdSSimon Schubert 
508b2b3ffcdSSimon Schubert 	/*
509b2b3ffcdSSimon Schubert 	 * we can watch a 1, 2, 4, or 8 byte sized location
510b2b3ffcdSSimon Schubert 	 */
511b2b3ffcdSSimon Schubert 	switch (size) {
512b2b3ffcdSSimon Schubert 	case 1:
513b2b3ffcdSSimon Schubert 		mask = 0x00;
514b2b3ffcdSSimon Schubert 		break;
515b2b3ffcdSSimon Schubert 	case 2:
516b2b3ffcdSSimon Schubert 		mask = 0x01 << 2;
517b2b3ffcdSSimon Schubert 		break;
518b2b3ffcdSSimon Schubert 	case 4:
519b2b3ffcdSSimon Schubert 		mask = 0x03 << 2;
5201a70d68aSSascha Wildner 		break;
521b2b3ffcdSSimon Schubert 	case 8:
522b2b3ffcdSSimon Schubert 		mask = 0x02 << 2;
523b2b3ffcdSSimon Schubert 		break;
524b2b3ffcdSSimon Schubert 	default:
525b2b3ffcdSSimon Schubert 		return(-1);
526b2b3ffcdSSimon Schubert 	}
527b2b3ffcdSSimon Schubert 
528b2b3ffcdSSimon Schubert 	mask |= access;
529b2b3ffcdSSimon Schubert 
530b2b3ffcdSSimon Schubert 	/* clear the bits we are about to affect */
531b2b3ffcdSSimon Schubert 	d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
532b2b3ffcdSSimon Schubert 
533b2b3ffcdSSimon Schubert 	/* set drN register to the address, N=watchnum */
534b2b3ffcdSSimon Schubert 	DBREG_DRX(d, watchnum) = watchaddr;
535b2b3ffcdSSimon Schubert 
536b2b3ffcdSSimon Schubert 	/* enable the watchpoint */
537b2b3ffcdSSimon Schubert 	d->dr[7] |= (0x2 << (watchnum * 2)) | (mask << (watchnum * 4 + 16));
538b2b3ffcdSSimon Schubert 
539b2b3ffcdSSimon Schubert 	return(watchnum);
540b2b3ffcdSSimon Schubert }
541b2b3ffcdSSimon Schubert 
542b2b3ffcdSSimon Schubert 
543b2b3ffcdSSimon Schubert int
kx86_64_clr_watch(int watchnum,struct dbreg * d)544b2b3ffcdSSimon Schubert kx86_64_clr_watch(int watchnum, struct dbreg *d)
545b2b3ffcdSSimon Schubert {
546b2b3ffcdSSimon Schubert 	if (watchnum < 0 || watchnum >= 4)
547b2b3ffcdSSimon Schubert 		return(-1);
548b2b3ffcdSSimon Schubert 
549b2b3ffcdSSimon Schubert 	d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
550b2b3ffcdSSimon Schubert 	DBREG_DRX(d, watchnum) = 0;
551b2b3ffcdSSimon Schubert 
552b2b3ffcdSSimon Schubert 	return(0);
553b2b3ffcdSSimon Schubert }
554b2b3ffcdSSimon Schubert 
555b2b3ffcdSSimon Schubert 
556b2b3ffcdSSimon Schubert int
db_md_set_watchpoint(db_expr_t addr,db_expr_t size)557b2b3ffcdSSimon Schubert db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
558b2b3ffcdSSimon Schubert {
559b2b3ffcdSSimon Schubert 	int avail, wsize;
560b2b3ffcdSSimon Schubert 	int i;
561b2b3ffcdSSimon Schubert 	struct dbreg d;
562b2b3ffcdSSimon Schubert 
563b2b3ffcdSSimon Schubert 	fill_dbregs(NULL, &d);
564b2b3ffcdSSimon Schubert 
565b2b3ffcdSSimon Schubert 	avail = 0;
566b2b3ffcdSSimon Schubert 	for (i = 0; i < 4; i++) {
567b2b3ffcdSSimon Schubert 		if ((d.dr[7] & (3 << (i * 2))) == 0)
568b2b3ffcdSSimon Schubert 			avail++;
569b2b3ffcdSSimon Schubert 	}
570b2b3ffcdSSimon Schubert 
571b2b3ffcdSSimon Schubert 	if (avail * 8 < size)
572b2b3ffcdSSimon Schubert 		return(-1);
573b2b3ffcdSSimon Schubert 
574b2b3ffcdSSimon Schubert 	for (i=0; i < 4 && (size != 0); i++) {
575b2b3ffcdSSimon Schubert 		if ((d.dr[7] & (3 << (i * 2))) == 0) {
576b2b3ffcdSSimon Schubert 			if (size >= 8 || (avail == 1 && size > 4))
577b2b3ffcdSSimon Schubert 				wsize = 8;
578b2b3ffcdSSimon Schubert 			else if (size > 2)
579b2b3ffcdSSimon Schubert 				wsize = 4;
580b2b3ffcdSSimon Schubert 			else
581b2b3ffcdSSimon Schubert 				wsize = size;
582b2b3ffcdSSimon Schubert 			if (wsize == 3)
583b2b3ffcdSSimon Schubert 				wsize++;
584b2b3ffcdSSimon Schubert 			kx86_64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, &d);
585b2b3ffcdSSimon Schubert 			addr += wsize;
586b2b3ffcdSSimon Schubert 			size -= wsize;
587b2b3ffcdSSimon Schubert 		}
588b2b3ffcdSSimon Schubert 	}
589b2b3ffcdSSimon Schubert 
590b2b3ffcdSSimon Schubert 	set_dbregs(NULL, &d);
591b2b3ffcdSSimon Schubert 
592b2b3ffcdSSimon Schubert 	return(0);
593b2b3ffcdSSimon Schubert }
594b2b3ffcdSSimon Schubert 
595b2b3ffcdSSimon Schubert int
db_md_clr_watchpoint(db_expr_t addr,db_expr_t size)596b2b3ffcdSSimon Schubert db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
597b2b3ffcdSSimon Schubert {
598b2b3ffcdSSimon Schubert 	struct dbreg d;
599b2b3ffcdSSimon Schubert 	int i;
600b2b3ffcdSSimon Schubert 
601b2b3ffcdSSimon Schubert 	fill_dbregs(NULL, &d);
602b2b3ffcdSSimon Schubert 
603b2b3ffcdSSimon Schubert 	for(i = 0; i < 4; i++) {
604b2b3ffcdSSimon Schubert 		if (d.dr[7] & (3 << (i * 2))) {
605b2b3ffcdSSimon Schubert 			if ((DBREG_DRX((&d), i) >= addr) &&
606b2b3ffcdSSimon Schubert 			    (DBREG_DRX((&d), i) < addr + size))
607b2b3ffcdSSimon Schubert 				kx86_64_clr_watch(i, &d);
608b2b3ffcdSSimon Schubert 		}
609b2b3ffcdSSimon Schubert 	}
610b2b3ffcdSSimon Schubert 
611b2b3ffcdSSimon Schubert 	set_dbregs(NULL, &d);
612b2b3ffcdSSimon Schubert 
613b2b3ffcdSSimon Schubert 	return(0);
614b2b3ffcdSSimon Schubert }
615b2b3ffcdSSimon Schubert 
616b2b3ffcdSSimon Schubert static char *
watchtype_str(int type)617b2b3ffcdSSimon Schubert watchtype_str(int type)
618b2b3ffcdSSimon Schubert {
619b2b3ffcdSSimon Schubert 	switch (type) {
620b2b3ffcdSSimon Schubert 	case DBREG_DR7_EXEC:
621b2b3ffcdSSimon Schubert 		return "execute";
622b2b3ffcdSSimon Schubert 	case DBREG_DR7_RDWR:
623b2b3ffcdSSimon Schubert 		return "read/write";
624b2b3ffcdSSimon Schubert 	case DBREG_DR7_WRONLY:
625b2b3ffcdSSimon Schubert 		return "write";
626b2b3ffcdSSimon Schubert 	default:
627b2b3ffcdSSimon Schubert 		return "invalid";
628b2b3ffcdSSimon Schubert 	}
629b2b3ffcdSSimon Schubert }
630b2b3ffcdSSimon Schubert 
631b2b3ffcdSSimon Schubert void
db_md_list_watchpoints(void)632b2b3ffcdSSimon Schubert db_md_list_watchpoints(void)
633b2b3ffcdSSimon Schubert {
634b2b3ffcdSSimon Schubert 	int i;
635b2b3ffcdSSimon Schubert 	struct dbreg d;
636b2b3ffcdSSimon Schubert 
637b2b3ffcdSSimon Schubert 	fill_dbregs(NULL, &d);
638b2b3ffcdSSimon Schubert 
639b2b3ffcdSSimon Schubert 	db_printf("\nhardware watchpoints:\n");
640b2b3ffcdSSimon Schubert 	db_printf("  watch    status        type  len     address\n"
641b2b3ffcdSSimon Schubert 		  "  -----  --------  ----------  ---  ----------\n");
642b2b3ffcdSSimon Schubert 	for (i = 0; i < 4; i++) {
643b2b3ffcdSSimon Schubert 		if (d.dr[7] & (0x03 << (i * 2))) {
644b2b3ffcdSSimon Schubert 			unsigned type, len;
645b2b3ffcdSSimon Schubert 			type = (d.dr[7] >> (16 + (i * 4))) & 3;
646b2b3ffcdSSimon Schubert 			len =  (d.dr[7] >> (16 + (i * 4) + 2)) & 3;
647b2b3ffcdSSimon Schubert 			db_printf("  %-5d  %-8s  %10s  %3d  0x%08lx\n",
648b2b3ffcdSSimon Schubert 				  i, "enabled", watchtype_str(type),
649b2b3ffcdSSimon Schubert 				  len + 1, DBREG_DRX((&d), i));
650b2b3ffcdSSimon Schubert 		} else {
651b2b3ffcdSSimon Schubert 			db_printf("  %-5d  disabled\n", i);
652b2b3ffcdSSimon Schubert 		}
653b2b3ffcdSSimon Schubert 	}
654b2b3ffcdSSimon Schubert 
655b2b3ffcdSSimon Schubert 	db_printf("\ndebug register values:\n");
656b2b3ffcdSSimon Schubert 	for (i = 0; i < 8; i++)
657b2b3ffcdSSimon Schubert 		db_printf("  dr%d 0x%08lx\n", i, DBREG_DRX((&d),i));
658b2b3ffcdSSimon Schubert 	db_printf("\n");
659b2b3ffcdSSimon Schubert }
660b2b3ffcdSSimon Schubert 
661b2b3ffcdSSimon Schubert /*
662b2b3ffcdSSimon Schubert  * See if dladdr() can get the symbol name via the standard dynamic loader.
663b2b3ffcdSSimon Schubert  */
664b2b3ffcdSSimon Schubert static
665b2b3ffcdSSimon Schubert void
dl_symbol_values(long callpc,const char ** name)666b2b3ffcdSSimon Schubert dl_symbol_values(long callpc, const char **name)
667b2b3ffcdSSimon Schubert {
668b2b3ffcdSSimon Schubert #if 0
669b2b3ffcdSSimon Schubert 	Dl_info info;
670b2b3ffcdSSimon Schubert 	if (*name == NULL) {
671b2b3ffcdSSimon Schubert 		if (dladdr((const void *)callpc, &info) != 0) {
672b2b3ffcdSSimon Schubert 			if (info.dli_saddr <= (const void *)callpc)
673b2b3ffcdSSimon Schubert 				*name = info.dli_sname;
674b2b3ffcdSSimon Schubert 		}
675b2b3ffcdSSimon Schubert 	}
676b2b3ffcdSSimon Schubert #endif
677b2b3ffcdSSimon Schubert }
678b2b3ffcdSSimon Schubert 
679