xref: /freebsd/sys/amd64/amd64/db_trace.c (revision 0957b409)
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/smp.h>
35 #include <sys/stack.h>
36 #include <sys/sysent.h>
37 
38 #include <machine/cpu.h>
39 #include <machine/md_var.h>
40 #include <machine/pcb.h>
41 #include <machine/reg.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 #define	TRAP_INTERRUPT	5
127 
128 static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *);
129 static void db_print_stack_entry(const char *, db_addr_t, void *);
130 static void decode_syscall(int, struct thread *);
131 
132 static const char * watchtype_str(int type);
133 int  amd64_set_watch(int watchnum, unsigned long watchaddr, int size,
134 		    int access, struct dbreg *d);
135 int  amd64_clr_watch(int watchnum, struct dbreg *d);
136 
137 static void
138 db_print_stack_entry(const char *name, db_addr_t callpc, void *frame)
139 {
140 
141 	db_printf("%s() at ", name != NULL ? name : "??");
142 	db_printsym(callpc, DB_STGY_PROC);
143 	if (frame != NULL)
144 		db_printf("/frame 0x%lx", (register_t)frame);
145 	db_printf("\n");
146 }
147 
148 static void
149 decode_syscall(int number, struct thread *td)
150 {
151 	struct proc *p;
152 	c_db_sym_t sym;
153 	db_expr_t diff;
154 	sy_call_t *f;
155 	const char *symname;
156 
157 	db_printf(" (%d", number);
158 	p = (td != NULL) ? td->td_proc : NULL;
159 	if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
160 		f = p->p_sysent->sv_table[number].sy_call;
161 		sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
162 		if (sym != DB_SYM_NULL && diff == 0) {
163 			db_symbol_values(sym, &symname, NULL);
164 			db_printf(", %s, %s", p->p_sysent->sv_name, symname);
165 		}
166 	}
167 	db_printf(")");
168 }
169 
170 /*
171  * Figure out the next frame up in the call stack.
172  */
173 static void
174 db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td)
175 {
176 	struct trapframe *tf;
177 	int frame_type;
178 	long rip, rsp, rbp;
179 	db_expr_t offset;
180 	c_db_sym_t sym;
181 	const char *name;
182 
183 	rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
184 	rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
185 
186 	/*
187 	 * Figure out frame type.  We look at the address just before
188 	 * the saved instruction pointer as the saved EIP is after the
189 	 * call function, and if the function being called is marked as
190 	 * dead (such as panic() at the end of dblfault_handler()), then
191 	 * the instruction at the saved EIP will be part of a different
192 	 * function (syscall() in this example) rather than the one that
193 	 * actually made the call.
194 	 */
195 	frame_type = NORMAL;
196 	sym = db_search_symbol(rip - 1, DB_STGY_ANY, &offset);
197 	db_symbol_values(sym, &name, NULL);
198 	if (name != NULL) {
199 		if (strcmp(name, "calltrap") == 0 ||
200 		    strcmp(name, "fork_trampoline") == 0 ||
201 		    strcmp(name, "mchk_calltrap") == 0 ||
202 		    strcmp(name, "nmi_calltrap") == 0 ||
203 		    strcmp(name, "Xdblfault") == 0)
204 			frame_type = TRAP;
205 		else if (strncmp(name, "Xatpic_intr", 11) == 0 ||
206 		    strncmp(name, "Xapic_isr", 9) == 0 ||
207 		    strcmp(name, "Xtimerint") == 0 ||
208 		    strcmp(name, "Xipi_intr_bitmap_handler") == 0 ||
209 		    strcmp(name, "Xcpustop") == 0 ||
210 		    strcmp(name, "Xcpususpend") == 0 ||
211 		    strcmp(name, "Xrendezvous") == 0)
212 			frame_type = INTERRUPT;
213 		else if (strcmp(name, "Xfast_syscall") == 0 ||
214 		    strcmp(name, "Xfast_syscall_pti") == 0 ||
215 		    strcmp(name, "fast_syscall_common") == 0)
216 			frame_type = SYSCALL;
217 #ifdef COMPAT_FREEBSD32
218 		else if (strcmp(name, "Xint0x80_syscall") == 0)
219 			frame_type = SYSCALL;
220 #endif
221 		/* XXX: These are interrupts with trap frames. */
222 		else if (strcmp(name, "Xtimerint") == 0 ||
223 		    strcmp(name, "Xcpustop") == 0 ||
224 		    strcmp(name, "Xcpususpend") == 0 ||
225 		    strcmp(name, "Xrendezvous") == 0 ||
226 		    strcmp(name, "Xipi_intr_bitmap_handler") == 0)
227 			frame_type = TRAP_INTERRUPT;
228 	}
229 
230 	/*
231 	 * Normal frames need no special processing.
232 	 */
233 	if (frame_type == NORMAL) {
234 		*ip = (db_addr_t) rip;
235 		*fp = (struct amd64_frame *) rbp;
236 		return;
237 	}
238 
239 	db_print_stack_entry(name, rip, &(*fp)->f_frame);
240 
241 	/*
242 	 * Point to base of trapframe which is just above the
243 	 * current frame.
244 	 */
245 	tf = (struct trapframe *)((long)*fp + 16);
246 
247 	if (INKERNEL((long) tf)) {
248 		rsp = tf->tf_rsp;
249 		rip = tf->tf_rip;
250 		rbp = tf->tf_rbp;
251 		switch (frame_type) {
252 		case TRAP:
253 			db_printf("--- trap %#r", tf->tf_trapno);
254 			break;
255 		case SYSCALL:
256 			db_printf("--- syscall");
257 			decode_syscall(tf->tf_rax, td);
258 			break;
259 		case TRAP_INTERRUPT:
260 		case INTERRUPT:
261 			db_printf("--- interrupt");
262 			break;
263 		default:
264 			panic("The moon has moved again.");
265 		}
266 		db_printf(", rip = %#lr, rsp = %#lr, rbp = %#lr ---\n", rip,
267 		    rsp, rbp);
268 	}
269 
270 	*ip = (db_addr_t) rip;
271 	*fp = (struct amd64_frame *) rbp;
272 }
273 
274 static int
275 db_backtrace(struct thread *td, struct trapframe *tf, struct amd64_frame *frame,
276     db_addr_t pc, register_t sp, int count)
277 {
278 	struct amd64_frame *actframe;
279 	const char *name;
280 	db_expr_t offset;
281 	c_db_sym_t sym;
282 	boolean_t first;
283 
284 	if (count == -1)
285 		count = 1024;
286 
287 	first = TRUE;
288 	while (count-- && !db_pager_quit) {
289 		sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
290 		db_symbol_values(sym, &name, NULL);
291 
292 		/*
293 		 * Attempt to determine a (possibly fake) frame that gives
294 		 * the caller's pc.  It may differ from `frame' if the
295 		 * current function never sets up a standard frame or hasn't
296 		 * set one up yet or has just discarded one.  The last two
297 		 * cases can be guessed fairly reliably for code generated
298 		 * by gcc.  The first case is too much trouble to handle in
299 		 * general because the amount of junk on the stack depends
300 		 * on the pc (the special handling of "calltrap", etc. in
301 		 * db_nextframe() works because the `next' pc is special).
302 		 */
303 		actframe = frame;
304 		if (first) {
305 			first = FALSE;
306 			if (sym == C_DB_SYM_NULL && sp != 0) {
307 				/*
308 				 * If a symbol couldn't be found, we've probably
309 				 * jumped to a bogus location, so try and use
310 				 * the return address to find our caller.
311 				 */
312 				db_print_stack_entry(name, pc, NULL);
313 				pc = db_get_value(sp, 8, FALSE);
314 				if (db_search_symbol(pc, DB_STGY_PROC,
315 				    &offset) == C_DB_SYM_NULL)
316 					break;
317 				continue;
318 			} else if (tf != NULL) {
319 				int instr;
320 
321 				instr = db_get_value(pc, 4, FALSE);
322 				if ((instr & 0xffffffff) == 0xe5894855) {
323 					/* pushq %rbp; movq %rsp, %rbp */
324 					actframe = (void *)(tf->tf_rsp - 8);
325 				} else if ((instr & 0xffffff) == 0xe58948) {
326 					/* movq %rsp, %rbp */
327 					actframe = (void *)tf->tf_rsp;
328 					if (tf->tf_rbp == 0) {
329 						/* Fake frame better. */
330 						frame = actframe;
331 					}
332 				} else if ((instr & 0xff) == 0xc3) {
333 					/* ret */
334 					actframe = (void *)(tf->tf_rsp - 8);
335 				} else if (offset == 0) {
336 					/* Probably an assembler symbol. */
337 					actframe = (void *)(tf->tf_rsp - 8);
338 				}
339 			} else if (name != NULL &&
340 			    strcmp(name, "fork_trampoline") == 0) {
341 				/*
342 				 * Don't try to walk back on a stack for a
343 				 * process that hasn't actually been run yet.
344 				 */
345 				db_print_stack_entry(name, pc, actframe);
346 				break;
347 			}
348 		}
349 
350 		db_print_stack_entry(name, pc, actframe);
351 
352 		if (actframe != frame) {
353 			/* `frame' belongs to caller. */
354 			pc = (db_addr_t)
355 			    db_get_value((long)&actframe->f_retaddr, 8, FALSE);
356 			continue;
357 		}
358 
359 		db_nextframe(&frame, &pc, td);
360 
361 		if (INKERNEL((long)pc) && !INKERNEL((long)frame)) {
362 			sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
363 			db_symbol_values(sym, &name, NULL);
364 			db_print_stack_entry(name, pc, frame);
365 			break;
366 		}
367 		if (!INKERNEL((long) frame)) {
368 			break;
369 		}
370 	}
371 
372 	return (0);
373 }
374 
375 void
376 db_trace_self(void)
377 {
378 	struct amd64_frame *frame;
379 	db_addr_t callpc;
380 	register_t rbp;
381 
382 	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
383 	frame = (struct amd64_frame *)rbp;
384 	callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
385 	frame = frame->f_frame;
386 	db_backtrace(curthread, NULL, frame, callpc, 0, -1);
387 }
388 
389 int
390 db_trace_thread(struct thread *thr, int count)
391 {
392 	struct pcb *ctx;
393 	struct trapframe *tf;
394 
395 	ctx = kdb_thr_ctx(thr);
396 	tf = thr == kdb_thread ? kdb_frame : NULL;
397 	return (db_backtrace(thr, tf, (struct amd64_frame *)ctx->pcb_rbp,
398 	    ctx->pcb_rip, ctx->pcb_rsp, count));
399 }
400 
401 int
402 amd64_set_watch(watchnum, watchaddr, size, access, d)
403 	int watchnum;
404 	unsigned long watchaddr;
405 	int size;
406 	int access;
407 	struct dbreg *d;
408 {
409 	int i, len;
410 
411 	if (watchnum == -1) {
412 		for (i = 0; i < 4; i++)
413 			if (!DBREG_DR7_ENABLED(d->dr[7], i))
414 				break;
415 		if (i < 4)
416 			watchnum = i;
417 		else
418 			return (-1);
419 	}
420 
421 	switch (access) {
422 	case DBREG_DR7_EXEC:
423 		size = 1; /* size must be 1 for an execution breakpoint */
424 		/* fall through */
425 	case DBREG_DR7_WRONLY:
426 	case DBREG_DR7_RDWR:
427 		break;
428 	default:
429 		return (-1);
430 	}
431 
432 	/*
433 	 * we can watch a 1, 2, 4, or 8 byte sized location
434 	 */
435 	switch (size) {
436 	case 1:
437 		len = DBREG_DR7_LEN_1;
438 		break;
439 	case 2:
440 		len = DBREG_DR7_LEN_2;
441 		break;
442 	case 4:
443 		len = DBREG_DR7_LEN_4;
444 		break;
445 	case 8:
446 		len = DBREG_DR7_LEN_8;
447 		break;
448 	default:
449 		return (-1);
450 	}
451 
452 	/* clear the bits we are about to affect */
453 	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
454 
455 	/* set drN register to the address, N=watchnum */
456 	DBREG_DRX(d, watchnum) = watchaddr;
457 
458 	/* enable the watchpoint */
459 	d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
460 	    DBREG_DR7_GLOBAL_ENABLE);
461 
462 	return (watchnum);
463 }
464 
465 
466 int
467 amd64_clr_watch(watchnum, d)
468 	int watchnum;
469 	struct dbreg *d;
470 {
471 
472 	if (watchnum < 0 || watchnum >= 4)
473 		return (-1);
474 
475 	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
476 	DBREG_DRX(d, watchnum) = 0;
477 
478 	return (0);
479 }
480 
481 
482 int
483 db_md_set_watchpoint(addr, size)
484 	db_expr_t addr;
485 	db_expr_t size;
486 {
487 	struct dbreg *d;
488 	struct pcpu *pc;
489 	int avail, c, cpu, i, wsize;
490 
491 	d = (struct dbreg *)PCPU_PTR(dbreg);
492 	cpu = PCPU_GET(cpuid);
493 	fill_dbregs(NULL, d);
494 
495 	avail = 0;
496 	for (i = 0; i < 4; i++) {
497 		if (!DBREG_DR7_ENABLED(d->dr[7], i))
498 			avail++;
499 	}
500 
501 	if (avail * 8 < size)
502 		return (-1);
503 
504 	for (i = 0; i < 4 && size > 0; i++) {
505 		if (!DBREG_DR7_ENABLED(d->dr[7], i)) {
506 			if (size >= 8 || (avail == 1 && size > 4))
507 				wsize = 8;
508 			else if (size > 2)
509 				wsize = 4;
510 			else
511 				wsize = size;
512 			amd64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, d);
513 			addr += wsize;
514 			size -= wsize;
515 			avail--;
516 		}
517 	}
518 
519 	set_dbregs(NULL, d);
520 	CPU_FOREACH(c) {
521 		if (c == cpu)
522 			continue;
523 		pc = pcpu_find(c);
524 		memcpy(pc->pc_dbreg, d, sizeof(*d));
525 		pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
526 	}
527 
528 	return (0);
529 }
530 
531 int
532 db_md_clr_watchpoint(addr, size)
533 	db_expr_t addr;
534 	db_expr_t size;
535 {
536 	struct dbreg *d;
537 	struct pcpu *pc;
538 	int i, c, cpu;
539 
540 	d = (struct dbreg *)PCPU_PTR(dbreg);
541 	cpu = PCPU_GET(cpuid);
542 	fill_dbregs(NULL, d);
543 
544 	for (i = 0; i < 4; i++) {
545 		if (DBREG_DR7_ENABLED(d->dr[7], i)) {
546 			if (DBREG_DRX((d), i) >= addr &&
547 			    DBREG_DRX((d), i) < addr + size)
548 				amd64_clr_watch(i, d);
549 
550 		}
551 	}
552 
553 	set_dbregs(NULL, d);
554 	CPU_FOREACH(c) {
555 		if (c == cpu)
556 			continue;
557 		pc = pcpu_find(c);
558 		memcpy(pc->pc_dbreg, d, sizeof(*d));
559 		pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
560 	}
561 
562 	return (0);
563 }
564 
565 
566 static const char *
567 watchtype_str(type)
568 	int type;
569 {
570 	switch (type) {
571 		case DBREG_DR7_EXEC   : return "execute";    break;
572 		case DBREG_DR7_RDWR   : return "read/write"; break;
573 		case DBREG_DR7_WRONLY : return "write";	     break;
574 		default		      : return "invalid";    break;
575 	}
576 }
577 
578 
579 void
580 db_md_list_watchpoints(void)
581 {
582 	struct dbreg d;
583 	int i, len, type;
584 
585 	fill_dbregs(NULL, &d);
586 
587 	db_printf("\nhardware watchpoints:\n");
588 	db_printf("  watch    status        type  len             address\n");
589 	db_printf("  -----  --------  ----------  ---  ------------------\n");
590 	for (i = 0; i < 4; i++) {
591 		if (DBREG_DR7_ENABLED(d.dr[7], i)) {
592 			type = DBREG_DR7_ACCESS(d.dr[7], i);
593 			len = DBREG_DR7_LEN(d.dr[7], i);
594 			if (len == DBREG_DR7_LEN_8)
595 				len = 8;
596 			else
597 				len++;
598 			db_printf("  %-5d  %-8s  %10s  %3d  ",
599 			    i, "enabled", watchtype_str(type), len);
600 			db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
601 			db_printf("\n");
602 		} else {
603 			db_printf("  %-5d  disabled\n", i);
604 		}
605 	}
606 
607 	db_printf("\ndebug register values:\n");
608 	for (i = 0; i < 8; i++)
609 		if (i != 4 && i != 5)
610 			db_printf("  dr%d 0x%016lx\n", i, DBREG_DRX(&d, i));
611 	db_printf("\n");
612 }
613 
614 void
615 amd64_db_resume_dbreg(void)
616 {
617 	struct dbreg *d;
618 
619 	switch (PCPU_GET(dbreg_cmd)) {
620 	case PC_DBREG_CMD_LOAD:
621 		d = (struct dbreg *)PCPU_PTR(dbreg);
622 		set_dbregs(NULL, d);
623 		PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
624 		break;
625 	}
626 }
627