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