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