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