xref: /freebsd/sys/amd64/amd64/db_trace.c (revision 9768746b)
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$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kdb.h>
33 #include <sys/proc.h>
34 #include <sys/reg.h>
35 #include <sys/smp.h>
36 #include <sys/stack.h>
37 
38 #include <machine/cpu.h>
39 #include <machine/md_var.h>
40 #include <machine/pcb.h>
41 #include <machine/stack.h>
42 
43 #include <vm/vm.h>
44 #include <vm/vm_param.h>
45 #include <vm/pmap.h>
46 
47 #include <ddb/ddb.h>
48 #include <ddb/db_access.h>
49 #include <ddb/db_sym.h>
50 #include <ddb/db_variables.h>
51 
52 static db_varfcn_t db_frame;
53 static db_varfcn_t db_frame_seg;
54 
55 CTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg));
56 
57 /*
58  * Machine register set.
59  */
60 #define	DB_OFFSET(x)	(db_expr_t *)offsetof(struct trapframe, x)
61 struct db_variable db_regs[] = {
62 	{ "cs",		DB_OFFSET(tf_cs),	db_frame_seg },
63 	{ "ds",		DB_OFFSET(tf_ds),	db_frame_seg },
64 	{ "es",		DB_OFFSET(tf_es),	db_frame_seg },
65 	{ "fs",		DB_OFFSET(tf_fs),	db_frame_seg },
66 	{ "gs",		DB_OFFSET(tf_gs),	db_frame_seg },
67 	{ "ss",		DB_OFFSET(tf_ss),	db_frame_seg },
68 	{ "rax",	DB_OFFSET(tf_rax),	db_frame },
69 	{ "rcx",        DB_OFFSET(tf_rcx),	db_frame },
70 	{ "rdx",	DB_OFFSET(tf_rdx),	db_frame },
71 	{ "rbx",	DB_OFFSET(tf_rbx),	db_frame },
72 	{ "rsp",	DB_OFFSET(tf_rsp),	db_frame },
73 	{ "rbp",	DB_OFFSET(tf_rbp),	db_frame },
74 	{ "rsi",	DB_OFFSET(tf_rsi),	db_frame },
75 	{ "rdi",	DB_OFFSET(tf_rdi),	db_frame },
76 	{ "r8",		DB_OFFSET(tf_r8),	db_frame },
77 	{ "r9",		DB_OFFSET(tf_r9),	db_frame },
78 	{ "r10",	DB_OFFSET(tf_r10),	db_frame },
79 	{ "r11",	DB_OFFSET(tf_r11),	db_frame },
80 	{ "r12",	DB_OFFSET(tf_r12),	db_frame },
81 	{ "r13",	DB_OFFSET(tf_r13),	db_frame },
82 	{ "r14",	DB_OFFSET(tf_r14),	db_frame },
83 	{ "r15",	DB_OFFSET(tf_r15),	db_frame },
84 	{ "rip",	DB_OFFSET(tf_rip),	db_frame },
85 	{ "rflags",	DB_OFFSET(tf_rflags),	db_frame },
86 };
87 struct db_variable *db_eregs = db_regs + nitems(db_regs);
88 
89 static int
90 db_frame_seg(struct db_variable *vp, db_expr_t *valuep, int op)
91 {
92 	uint16_t *reg;
93 
94 	if (kdb_frame == NULL)
95 		return (0);
96 
97 	reg = (uint16_t *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
98 	if (op == DB_VAR_GET)
99 		*valuep = *reg;
100 	else
101 		*reg = *valuep;
102 	return (1);
103 }
104 
105 static int
106 db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
107 {
108 	long *reg;
109 
110 	if (kdb_frame == NULL)
111 		return (0);
112 
113 	reg = (long *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
114 	if (op == DB_VAR_GET)
115 		*valuep = *reg;
116 	else
117 		*reg = *valuep;
118 	return (1);
119 }
120 
121 #define NORMAL		0
122 #define	TRAP		1
123 #define	INTERRUPT	2
124 #define	SYSCALL		3
125 
126 static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *);
127 static void db_print_stack_entry(const char *, db_addr_t, void *);
128 
129 static void
130 db_print_stack_entry(const char *name, db_addr_t callpc, void *frame)
131 {
132 
133 	db_printf("%s() at ", name != NULL ? name : "??");
134 	db_printsym(callpc, DB_STGY_PROC);
135 	if (frame != NULL)
136 		db_printf("/frame 0x%lx", (register_t)frame);
137 	db_printf("\n");
138 }
139 
140 /*
141  * Figure out the next frame up in the call stack.
142  */
143 static void
144 db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td)
145 {
146 	struct trapframe *tf;
147 	int frame_type;
148 	long rip, rsp, rbp;
149 	db_expr_t offset;
150 	c_db_sym_t sym;
151 	const char *name;
152 
153 	rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
154 	rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
155 
156 	/*
157 	 * Figure out frame type.  We look at the address just before
158 	 * the saved instruction pointer as the saved EIP is after the
159 	 * call function, and if the function being called is marked as
160 	 * dead (such as panic() at the end of dblfault_handler()), then
161 	 * the instruction at the saved EIP will be part of a different
162 	 * function (syscall() in this example) rather than the one that
163 	 * actually made the call.
164 	 */
165 	frame_type = NORMAL;
166 	sym = db_search_symbol(rip - 1, DB_STGY_ANY, &offset);
167 	db_symbol_values(sym, &name, NULL);
168 	if (name != NULL) {
169 		if (strcmp(name, "calltrap") == 0 ||
170 		    strcmp(name, "fork_trampoline") == 0 ||
171 		    strcmp(name, "mchk_calltrap") == 0 ||
172 		    strcmp(name, "nmi_calltrap") == 0 ||
173 		    strcmp(name, "Xdblfault") == 0)
174 			frame_type = TRAP;
175 		else if (strncmp(name, "Xatpic_intr", 11) == 0 ||
176 		    strncmp(name, "Xapic_isr", 9) == 0 ||
177 		    strcmp(name, "Xxen_intr_upcall") == 0 ||
178 		    strcmp(name, "Xtimerint") == 0 ||
179 		    strcmp(name, "Xipi_intr_bitmap_handler") == 0 ||
180 		    strcmp(name, "Xcpustop") == 0 ||
181 		    strcmp(name, "Xcpususpend") == 0 ||
182 		    strcmp(name, "Xrendezvous") == 0)
183 			frame_type = INTERRUPT;
184 		else if (strcmp(name, "Xfast_syscall") == 0 ||
185 		    strcmp(name, "Xfast_syscall_pti") == 0 ||
186 		    strcmp(name, "fast_syscall_common") == 0)
187 			frame_type = SYSCALL;
188 #ifdef COMPAT_FREEBSD32
189 		else if (strcmp(name, "Xint0x80_syscall") == 0)
190 			frame_type = SYSCALL;
191 #endif
192 	}
193 
194 	/*
195 	 * Normal frames need no special processing.
196 	 */
197 	if (frame_type == NORMAL) {
198 		*ip = (db_addr_t) rip;
199 		*fp = (struct amd64_frame *) rbp;
200 		return;
201 	}
202 
203 	db_print_stack_entry(name, rip, &(*fp)->f_frame);
204 
205 	/*
206 	 * Point to base of trapframe which is just above the
207 	 * current frame.
208 	 */
209 	tf = (struct trapframe *)((long)*fp + 16);
210 
211 	if (INKERNEL((long) tf)) {
212 		rsp = tf->tf_rsp;
213 		rip = tf->tf_rip;
214 		rbp = tf->tf_rbp;
215 		switch (frame_type) {
216 		case TRAP:
217 			db_printf("--- trap %#r", tf->tf_trapno);
218 			break;
219 		case SYSCALL:
220 			db_printf("--- syscall");
221 			db_decode_syscall(td, tf->tf_rax);
222 			break;
223 		case INTERRUPT:
224 			db_printf("--- interrupt");
225 			break;
226 		default:
227 			panic("The moon has moved again.");
228 		}
229 		db_printf(", rip = %#lr, rsp = %#lr, rbp = %#lr ---\n", rip,
230 		    rsp, rbp);
231 	}
232 
233 	*ip = (db_addr_t) rip;
234 	*fp = (struct amd64_frame *) rbp;
235 }
236 
237 static int __nosanitizeaddress __nosanitizememory
238 db_backtrace(struct thread *td, struct trapframe *tf, struct amd64_frame *frame,
239     db_addr_t pc, register_t sp, int count)
240 {
241 	struct amd64_frame *actframe;
242 	const char *name;
243 	db_expr_t offset;
244 	c_db_sym_t sym;
245 	boolean_t first;
246 
247 	if (count == -1)
248 		count = 1024;
249 
250 	first = TRUE;
251 	while (count-- && !db_pager_quit) {
252 		sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
253 		db_symbol_values(sym, &name, NULL);
254 
255 		/*
256 		 * Attempt to determine a (possibly fake) frame that gives
257 		 * the caller's pc.  It may differ from `frame' if the
258 		 * current function never sets up a standard frame or hasn't
259 		 * set one up yet or has just discarded one.  The last two
260 		 * cases can be guessed fairly reliably for code generated
261 		 * by gcc.  The first case is too much trouble to handle in
262 		 * general because the amount of junk on the stack depends
263 		 * on the pc (the special handling of "calltrap", etc. in
264 		 * db_nextframe() works because the `next' pc is special).
265 		 */
266 		actframe = frame;
267 		if (first) {
268 			first = FALSE;
269 			if (sym == C_DB_SYM_NULL && sp != 0) {
270 				/*
271 				 * If a symbol couldn't be found, we've probably
272 				 * jumped to a bogus location, so try and use
273 				 * the return address to find our caller.
274 				 */
275 				db_print_stack_entry(name, pc, NULL);
276 				pc = db_get_value(sp, 8, FALSE);
277 				if (db_search_symbol(pc, DB_STGY_PROC,
278 				    &offset) == C_DB_SYM_NULL)
279 					break;
280 				continue;
281 			} else if (tf != NULL) {
282 				int instr;
283 
284 				instr = db_get_value(pc, 4, FALSE);
285 				if ((instr & 0xffffffff) == 0xe5894855) {
286 					/* pushq %rbp; movq %rsp, %rbp */
287 					actframe = (void *)(tf->tf_rsp - 8);
288 				} else if ((instr & 0xffffff) == 0xe58948) {
289 					/* movq %rsp, %rbp */
290 					actframe = (void *)tf->tf_rsp;
291 					if (tf->tf_rbp == 0) {
292 						/* Fake frame better. */
293 						frame = actframe;
294 					}
295 				} else if ((instr & 0xff) == 0xc3) {
296 					/* ret */
297 					actframe = (void *)(tf->tf_rsp - 8);
298 				} else if (offset == 0) {
299 					/* Probably an assembler symbol. */
300 					actframe = (void *)(tf->tf_rsp - 8);
301 				}
302 			} else if (name != NULL &&
303 			    strcmp(name, "fork_trampoline") == 0) {
304 				/*
305 				 * Don't try to walk back on a stack for a
306 				 * process that hasn't actually been run yet.
307 				 */
308 				db_print_stack_entry(name, pc, actframe);
309 				break;
310 			}
311 		}
312 
313 		db_print_stack_entry(name, pc, actframe);
314 
315 		if (actframe != frame) {
316 			/* `frame' belongs to caller. */
317 			pc = (db_addr_t)
318 			    db_get_value((long)&actframe->f_retaddr, 8, FALSE);
319 			continue;
320 		}
321 
322 		db_nextframe(&frame, &pc, td);
323 
324 		if (INKERNEL((long)pc) && !INKERNEL((long)frame)) {
325 			sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
326 			db_symbol_values(sym, &name, NULL);
327 			db_print_stack_entry(name, pc, frame);
328 			break;
329 		}
330 		if (!INKERNEL((long) frame)) {
331 			break;
332 		}
333 	}
334 
335 	return (0);
336 }
337 
338 void
339 db_trace_self(void)
340 {
341 	struct amd64_frame *frame;
342 	db_addr_t callpc;
343 	register_t rbp;
344 
345 	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
346 	frame = (struct amd64_frame *)rbp;
347 	callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
348 	frame = frame->f_frame;
349 	db_backtrace(curthread, NULL, frame, callpc, 0, -1);
350 }
351 
352 int
353 db_trace_thread(struct thread *thr, int count)
354 {
355 	struct pcb *ctx;
356 	struct trapframe *tf;
357 
358 	ctx = kdb_thr_ctx(thr);
359 	tf = thr == kdb_thread ? kdb_frame : NULL;
360 	return (db_backtrace(thr, tf, (struct amd64_frame *)ctx->pcb_rbp,
361 	    ctx->pcb_rip, ctx->pcb_rsp, count));
362 }
363 
364 void
365 db_md_list_watchpoints(void)
366 {
367 
368 	dbreg_list_watchpoints();
369 }
370