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