]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/db_trace.c
Provide access to the IA32 hardware debug registers from the ddb
[FreeBSD/FreeBSD.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  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker_set.h>
32 #include <sys/proc.h>
33 #include <sys/sysent.h>
34 #include <sys/user.h>
35
36 #include <machine/cpu.h>
37
38 #include <vm/vm.h>
39 #include <vm/vm_param.h>
40 #include <vm/pmap.h>
41 #include <ddb/ddb.h>
42
43 #include <ddb/db_access.h>
44 #include <ddb/db_sym.h>
45 #include <ddb/db_variables.h>
46
47 db_varfcn_t db_dr0;
48 db_varfcn_t db_dr1;
49 db_varfcn_t db_dr2;
50 db_varfcn_t db_dr3;
51 db_varfcn_t db_dr4;
52 db_varfcn_t db_dr5;
53 db_varfcn_t db_dr6;
54 db_varfcn_t db_dr7;
55
56 /*
57  * Machine register set.
58  */
59 struct db_variable db_regs[] = {
60         { "cs",         &ddb_regs.tf_cs,     FCN_NULL },
61         { "ds",         &ddb_regs.tf_ds,     FCN_NULL },
62         { "es",         &ddb_regs.tf_es,     FCN_NULL },
63         { "fs",         &ddb_regs.tf_fs,     FCN_NULL },
64 #if 0
65         { "gs",         &ddb_regs.tf_gs,     FCN_NULL },
66 #endif
67         { "ss",         &ddb_regs.tf_ss,     FCN_NULL },
68         { "eax",        &ddb_regs.tf_eax,    FCN_NULL },
69         { "ecx",        &ddb_regs.tf_ecx,    FCN_NULL },
70         { "edx",        &ddb_regs.tf_edx,    FCN_NULL },
71         { "ebx",        &ddb_regs.tf_ebx,    FCN_NULL },
72         { "esp",        &ddb_regs.tf_esp,    FCN_NULL },
73         { "ebp",        &ddb_regs.tf_ebp,    FCN_NULL },
74         { "esi",        &ddb_regs.tf_esi,    FCN_NULL },
75         { "edi",        &ddb_regs.tf_edi,    FCN_NULL },
76         { "eip",        &ddb_regs.tf_eip,    FCN_NULL },
77         { "efl",        &ddb_regs.tf_eflags, FCN_NULL },
78         { "dr0",        NULL,                db_dr0 },
79         { "dr1",        NULL,                db_dr1 },
80         { "dr2",        NULL,                db_dr2 },
81         { "dr3",        NULL,                db_dr3 },
82         { "dr4",        NULL,                db_dr4 },
83         { "dr5",        NULL,                db_dr5 },
84         { "dr6",        NULL,                db_dr6 },
85         { "dr7",        NULL,                db_dr7 },
86 };
87 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
88
89 /*
90  * Stack trace.
91  */
92 #define INKERNEL(va)    (((vm_offset_t)(va)) >= USRSTACK)
93
94 struct i386_frame {
95         struct i386_frame       *f_frame;
96         int                     f_retaddr;
97         int                     f_arg0;
98 };
99
100 #define NORMAL          0
101 #define TRAP            1
102 #define INTERRUPT       2
103 #define SYSCALL         3
104
105 static void db_nextframe __P((struct i386_frame **, db_addr_t *, struct proc *));
106 static int db_numargs __P((struct i386_frame *));
107 static void db_print_stack_entry __P((const char *, int, char **, int *, db_addr_t));
108 static void decode_syscall __P((int, struct proc *));
109
110 /*
111  * Figure out how many arguments were passed into the frame at "fp".
112  */
113 static int
114 db_numargs(fp)
115         struct i386_frame *fp;
116 {
117         int     *argp;
118         int     inst;
119         int     args;
120
121         argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
122         /*
123          * XXX etext is wrong for LKMs.  We should attempt to interpret
124          * the instruction at the return address in all cases.  This
125          * may require better fault handling.
126          */
127         if (argp < (int *)btext || argp >= (int *)etext) {
128                 args = 5;
129         } else {
130                 inst = db_get_value((int)argp, 4, FALSE);
131                 if ((inst & 0xff) == 0x59)      /* popl %ecx */
132                         args = 1;
133                 else if ((inst & 0xffff) == 0xc483)     /* addl $Ibs, %esp */
134                         args = ((inst >> 16) & 0xff) / 4;
135                 else
136                         args = 5;
137         }
138         return (args);
139 }
140
141 static void
142 db_print_stack_entry(name, narg, argnp, argp, callpc)
143         const char *name;
144         int narg;
145         char **argnp;
146         int *argp;
147         db_addr_t callpc;
148 {
149         db_printf("%s(", name);
150         while (narg) {
151                 if (argnp)
152                         db_printf("%s=", *argnp++);
153                 db_printf("%r", db_get_value((int)argp, 4, FALSE));
154                 argp++;
155                 if (--narg != 0)
156                         db_printf(",");
157         }
158         db_printf(") at ");
159         db_printsym(callpc, DB_STGY_PROC);
160         db_printf("\n");
161 }
162
163 static void
164 decode_syscall(number, p)
165         int number;
166         struct proc *p;
167 {
168         c_db_sym_t sym;
169         db_expr_t diff;
170         sy_call_t *f;
171         const char *symname;
172
173         db_printf(" (%d", number);
174         if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
175                 f = p->p_sysent->sv_table[number].sy_call;
176                 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
177                 if (sym != DB_SYM_NULL && diff == 0) {
178                         db_symbol_values(sym, &symname, NULL);
179                         db_printf(", %s, %s", p->p_sysent->sv_name, symname);
180                 }
181         }
182         db_printf(")"); 
183 }
184
185 /*
186  * Figure out the next frame up in the call stack.
187  */
188 static void
189 db_nextframe(fp, ip, p)
190         struct i386_frame **fp;         /* in/out */
191         db_addr_t       *ip;            /* out */
192         struct proc     *p;             /* in */
193 {
194         struct trapframe *tf;
195         int frame_type;
196         int eip, esp, ebp;
197         db_expr_t offset;
198         const char *sym, *name;
199
200         eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
201         ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE);
202
203         /*
204          * Figure out frame type.
205          */
206
207         frame_type = NORMAL;
208
209         sym = db_search_symbol(eip, DB_STGY_ANY, &offset);
210         db_symbol_values(sym, &name, NULL);
211         if (name != NULL) {
212                 if (!strcmp(name, "calltrap")) {
213                         frame_type = TRAP;
214                 } else if (!strncmp(name, "Xresume", 7)) {
215                         frame_type = INTERRUPT;
216                 } else if (!strcmp(name, "syscall_with_err_pushed")) {
217                         frame_type = SYSCALL;
218                 }
219         }
220
221         /*
222          * Normal frames need no special processing.
223          */
224         if (frame_type == NORMAL) {
225                 *ip = (db_addr_t) eip;
226                 *fp = (struct i386_frame *) ebp;
227                 return;
228         }
229
230         db_print_stack_entry(name, 0, 0, 0, eip);
231
232         /*
233          * Point to base of trapframe which is just above the
234          * current frame.
235          */
236         if (frame_type == INTERRUPT)
237                 tf = (struct trapframe *)((int)*fp + 12);
238         else
239                 tf = (struct trapframe *)((int)*fp + 8);
240
241         if (INKERNEL((int) tf)) {
242                 esp = (ISPL(tf->tf_cs) == SEL_UPL) ?
243                     tf->tf_esp : (int)&tf->tf_esp;
244                 eip = tf->tf_eip;
245                 ebp = tf->tf_ebp;
246                
247                 switch (frame_type) {
248                 case TRAP:
249                         db_printf("--- trap %#r", tf->tf_trapno);
250                         break;
251                 case SYSCALL:
252                         db_printf("--- syscall");
253                         decode_syscall(tf->tf_eax, p);
254                         break;
255                 case INTERRUPT:
256                         db_printf("--- interrupt");
257                         break;
258                 default:
259                         panic("The moon has moved again.");
260                 }
261                 db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip,
262                     esp, ebp);
263         }
264
265         *ip = (db_addr_t) eip;
266         *fp = (struct i386_frame *) ebp;
267 }
268
269 void
270 db_stack_trace_cmd(addr, have_addr, count, modif)
271         db_expr_t addr;
272         boolean_t have_addr;
273         db_expr_t count;
274         char *modif;
275 {
276         struct i386_frame *frame;
277         int *argp;
278         db_addr_t callpc;
279         boolean_t first;
280         struct pcb *pcb;
281         struct proc *p;
282         pid_t pid;
283
284         if (count == -1)
285                 count = 1024;
286
287         if (!have_addr) {
288                 p = curproc;
289                 frame = (struct i386_frame *)ddb_regs.tf_ebp;
290                 if (frame == NULL)
291                         frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
292                 callpc = (db_addr_t)ddb_regs.tf_eip;
293         } else if (!INKERNEL(addr)) {
294                 pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
295                     ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
296                     ((addr >> 16) % 16) * 10000;
297                 /*
298                  * The pcb for curproc is not valid at this point,
299                  * so fall back to the default case.
300                  */
301                 if (pid == curproc->p_pid) {
302                         p = curproc;
303                         frame = (struct i386_frame *)ddb_regs.tf_ebp;
304                         if (frame == NULL)
305                                 frame = (struct i386_frame *)
306                                     (ddb_regs.tf_esp - 4);
307                         callpc = (db_addr_t)ddb_regs.tf_eip;
308                 } else {
309
310                         /* sx_slock(&allproc_lock); */
311                         LIST_FOREACH(p, &allproc, p_list) {
312                                 if (p->p_pid == pid)
313                                         break;
314                         }
315                         /* sx_sunlock(&allproc_lock); */
316                         if (p == NULL) {
317                                 db_printf("pid %d not found\n", pid);
318                                 return;
319                         }
320                         if ((p->p_sflag & PS_INMEM) == 0) {
321                                 db_printf("pid %d swapped out\n", pid);
322                                 return;
323                         }
324                         pcb = &p->p_addr->u_pcb;
325                         frame = (struct i386_frame *)pcb->pcb_ebp;
326                         if (frame == NULL)
327                                 frame = (struct i386_frame *)
328                                     (pcb->pcb_esp - 4);
329                         callpc = (db_addr_t)pcb->pcb_eip;
330                 }
331         } else {
332                 p = NULL;
333                 frame = (struct i386_frame *)addr;
334                 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
335         }
336
337         first = TRUE;
338         while (count--) {
339                 struct i386_frame *actframe;
340                 int             narg;
341                 const char *    name;
342                 db_expr_t       offset;
343                 c_db_sym_t      sym;
344 #define MAXNARG 16
345                 char    *argnames[MAXNARG], **argnp = NULL;
346
347                 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
348                 db_symbol_values(sym, &name, NULL);
349
350                 /*
351                  * Attempt to determine a (possibly fake) frame that gives
352                  * the caller's pc.  It may differ from `frame' if the
353                  * current function never sets up a standard frame or hasn't
354                  * set one up yet or has just discarded one.  The last two
355                  * cases can be guessed fairly reliably for code generated
356                  * by gcc.  The first case is too much trouble to handle in
357                  * general because the amount of junk on the stack depends
358                  * on the pc (the special handling of "calltrap", etc. in
359                  * db_nextframe() works because the `next' pc is special).
360                  */
361                 actframe = frame;
362                 if (first) {
363                         if (!have_addr) {
364                                 int instr;
365
366                                 instr = db_get_value(callpc, 4, FALSE);
367                                 if ((instr & 0x00ffffff) == 0x00e58955) {
368                                         /* pushl %ebp; movl %esp, %ebp */
369                                         actframe = (struct i386_frame *)
370                                             (ddb_regs.tf_esp - 4);
371                                 } else if ((instr & 0x0000ffff) == 0x0000e589) {
372                                         /* movl %esp, %ebp */
373                                         actframe = (struct i386_frame *)
374                                             ddb_regs.tf_esp;
375                                         if (ddb_regs.tf_ebp == 0) {
376                                                 /* Fake caller's frame better. */
377                                                 frame = actframe;
378                                         }
379                                 } else if ((instr & 0x000000ff) == 0x000000c3) {
380                                         /* ret */
381                                         actframe = (struct i386_frame *)
382                                             (ddb_regs.tf_esp - 4);
383                                 } else if (offset == 0) {
384                                         /* Probably a symbol in assembler code. */
385                                         actframe = (struct i386_frame *)
386                                             (ddb_regs.tf_esp - 4);
387                                 }
388                         } else if (!strcmp(name, "fork_trampoline")) {
389                                 /*
390                                  * Don't try to walk back on a stack for a
391                                  * process that hasn't actually been run yet.
392                                  */
393                                 db_print_stack_entry(name, 0, 0, 0, callpc);
394                                 break;
395                         }
396                         first = FALSE;
397                 }
398
399                 argp = &actframe->f_arg0;
400                 narg = MAXNARG;
401                 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
402                         argnp = argnames;
403                 } else {
404                         narg = db_numargs(frame);
405                 }
406
407                 db_print_stack_entry(name, narg, argnp, argp, callpc);
408
409                 if (actframe != frame) {
410                         /* `frame' belongs to caller. */
411                         callpc = (db_addr_t)
412                             db_get_value((int)&actframe->f_retaddr, 4, FALSE);
413                         continue;
414                 }
415
416                 db_nextframe(&frame, &callpc, p);
417
418                 if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) {
419                         sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
420                         db_symbol_values(sym, &name, NULL);
421                         db_print_stack_entry(name, 0, 0, 0, callpc);
422                         break;
423                 }
424                 if (!INKERNEL((int) frame)) {
425                         break;
426                 }
427         }
428 }
429
430 #define DB_DRX_FUNC(reg)                \
431 int                                     \
432 db_ ## reg (vp, valuep, op)             \
433         struct db_variable *vp;         \
434         db_expr_t * valuep;             \
435         int op;                         \
436 {                                       \
437         if (op == DB_VAR_GET)           \
438                 *valuep = r ## reg ();  \
439         else                            \
440                 load_ ## reg (*valuep); \
441                                         \
442         return(0);                      \
443
444
445 DB_DRX_FUNC(dr0)
446 DB_DRX_FUNC(dr1)
447 DB_DRX_FUNC(dr2)
448 DB_DRX_FUNC(dr3)
449 DB_DRX_FUNC(dr4)
450 DB_DRX_FUNC(dr5)
451 DB_DRX_FUNC(dr6)
452 DB_DRX_FUNC(dr7)