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: releng/5.1/sys/i386/i386/db_trace.c 108338 2002-12-28 01:23:07Z julian $
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/sysent.h>
33
34 #include <machine/cpu.h>
35 #include <machine/md_var.h>
36 #include <machine/pcb.h>
37 #include <machine/reg.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_param.h>
41 #include <vm/pmap.h>
42
43 #include <ddb/ddb.h>
44 #include <ddb/db_access.h>
45 #include <ddb/db_sym.h>
46 #include <ddb/db_variables.h>
47
48 db_varfcn_t db_dr0;
49 db_varfcn_t db_dr1;
50 db_varfcn_t db_dr2;
51 db_varfcn_t db_dr3;
52 db_varfcn_t db_dr4;
53 db_varfcn_t db_dr5;
54 db_varfcn_t db_dr6;
55 db_varfcn_t db_dr7;
56
57 /*
58 * Machine register set.
59 */
60 struct db_variable db_regs[] = {
61 { "cs", &ddb_regs.tf_cs, FCN_NULL },
62 { "ds", &ddb_regs.tf_ds, FCN_NULL },
63 { "es", &ddb_regs.tf_es, FCN_NULL },
64 { "fs", &ddb_regs.tf_fs, FCN_NULL },
65 #if 0
66 { "gs", &ddb_regs.tf_gs, FCN_NULL },
67 #endif
68 { "ss", &ddb_regs.tf_ss, FCN_NULL },
69 { "eax", &ddb_regs.tf_eax, FCN_NULL },
70 { "ecx", &ddb_regs.tf_ecx, FCN_NULL },
71 { "edx", &ddb_regs.tf_edx, FCN_NULL },
72 { "ebx", &ddb_regs.tf_ebx, FCN_NULL },
73 { "esp", &ddb_regs.tf_esp, FCN_NULL },
74 { "ebp", &ddb_regs.tf_ebp, FCN_NULL },
75 { "esi", &ddb_regs.tf_esi, FCN_NULL },
76 { "edi", &ddb_regs.tf_edi, FCN_NULL },
77 { "eip", &ddb_regs.tf_eip, FCN_NULL },
78 { "efl", &ddb_regs.tf_eflags, FCN_NULL },
79 { "dr0", NULL, db_dr0 },
80 { "dr1", NULL, db_dr1 },
81 { "dr2", NULL, db_dr2 },
82 { "dr3", NULL, db_dr3 },
83 { "dr4", NULL, db_dr4 },
84 { "dr5", NULL, db_dr5 },
85 { "dr6", NULL, db_dr6 },
86 { "dr7", NULL, db_dr7 },
87 };
88 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
89
90 /*
91 * Stack trace.
92 */
93 #define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
94
95 struct i386_frame {
96 struct i386_frame *f_frame;
97 int f_retaddr;
98 int f_arg0;
99 };
100
101 #define NORMAL 0
102 #define TRAP 1
103 #define INTERRUPT 2
104 #define SYSCALL 3
105
106 static void db_nextframe(struct i386_frame **, db_addr_t *, struct proc *);
107 static int db_numargs(struct i386_frame *);
108 static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t);
109 static void decode_syscall(int, struct proc *);
110 static void db_trace_one_stack(int count, boolean_t have_addr,
111 struct proc *p, struct i386_frame *frame, db_addr_t callpc);
112
113
114 static char * watchtype_str(int type);
115 int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
116 struct dbreg * d);
117 int i386_clr_watch(int watchnum, struct dbreg * d);
118 int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
119 int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
120 void db_md_list_watchpoints(void);
121
122
123 /*
124 * Figure out how many arguments were passed into the frame at "fp".
125 */
126 static int
127 db_numargs(fp)
128 struct i386_frame *fp;
129 {
130 int *argp;
131 int inst;
132 int args;
133
134 argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
135 /*
136 * XXX etext is wrong for LKMs. We should attempt to interpret
137 * the instruction at the return address in all cases. This
138 * may require better fault handling.
139 */
140 if (argp < (int *)btext || argp >= (int *)etext) {
141 args = 5;
142 } else {
143 inst = db_get_value((int)argp, 4, FALSE);
144 if ((inst & 0xff) == 0x59) /* popl %ecx */
145 args = 1;
146 else if ((inst & 0xffff) == 0xc483) /* addl $Ibs, %esp */
147 args = ((inst >> 16) & 0xff) / 4;
148 else
149 args = 5;
150 }
151 return (args);
152 }
153
154 static void
155 db_print_stack_entry(name, narg, argnp, argp, callpc)
156 const char *name;
157 int narg;
158 char **argnp;
159 int *argp;
160 db_addr_t callpc;
161 {
162 db_printf("%s(", name);
163 while (narg) {
164 if (argnp)
165 db_printf("%s=", *argnp++);
166 db_printf("%r", db_get_value((int)argp, 4, FALSE));
167 argp++;
168 if (--narg != 0)
169 db_printf(",");
170 }
171 db_printf(") at ");
172 db_printsym(callpc, DB_STGY_PROC);
173 db_printf("\n");
174 }
175
176 static void
177 decode_syscall(number, p)
178 int number;
179 struct proc *p;
180 {
181 c_db_sym_t sym;
182 db_expr_t diff;
183 sy_call_t *f;
184 const char *symname;
185
186 db_printf(" (%d", number);
187 if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
188 f = p->p_sysent->sv_table[number].sy_call;
189 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
190 if (sym != DB_SYM_NULL && diff == 0) {
191 db_symbol_values(sym, &symname, NULL);
192 db_printf(", %s, %s", p->p_sysent->sv_name, symname);
193 }
194 }
195 db_printf(")");
196 }
197
198 /*
199 * Figure out the next frame up in the call stack.
200 */
201 static void
202 db_nextframe(fp, ip, p)
203 struct i386_frame **fp; /* in/out */
204 db_addr_t *ip; /* out */
205 struct proc *p; /* in */
206 {
207 struct trapframe *tf;
208 int frame_type;
209 int eip, esp, ebp;
210 db_expr_t offset;
211 c_db_sym_t sym;
212 const char *name;
213
214 eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
215 ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE);
216
217 /*
218 * Figure out frame type.
219 */
220 frame_type = NORMAL;
221 sym = db_search_symbol(eip, 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 frame_type = TRAP;
227 else if (strncmp(name, "Xintr", 5) == 0 ||
228 strncmp(name, "Xfastintr", 9) == 0)
229 frame_type = INTERRUPT;
230 else if (strcmp(name, "Xlcall_syscall") == 0 ||
231 strcmp(name, "Xint0x80_syscall") == 0)
232 frame_type = SYSCALL;
233 }
234
235 /*
236 * Normal frames need no special processing.
237 */
238 if (frame_type == NORMAL) {
239 *ip = (db_addr_t) eip;
240 *fp = (struct i386_frame *) ebp;
241 return;
242 }
243
244 db_print_stack_entry(name, 0, 0, 0, eip);
245
246 /*
247 * Point to base of trapframe which is just above the
248 * current frame.
249 */
250 if (frame_type == INTERRUPT)
251 tf = (struct trapframe *)((int)*fp + 12);
252 else
253 tf = (struct trapframe *)((int)*fp + 8);
254
255 if (INKERNEL((int) tf)) {
256 esp = (ISPL(tf->tf_cs) == SEL_UPL) ?
257 tf->tf_esp : (int)&tf->tf_esp;
258 eip = tf->tf_eip;
259 ebp = tf->tf_ebp;
260 switch (frame_type) {
261 case TRAP:
262 db_printf("--- trap %#r", tf->tf_trapno);
263 break;
264 case SYSCALL:
265 db_printf("--- syscall");
266 decode_syscall(tf->tf_eax, p);
267 break;
268 case INTERRUPT:
269 db_printf("--- interrupt");
270 break;
271 default:
272 panic("The moon has moved again.");
273 }
274 db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip,
275 esp, ebp);
276 }
277
278 *ip = (db_addr_t) eip;
279 *fp = (struct i386_frame *) ebp;
280 }
281
282 void
283 db_stack_trace_cmd(addr, have_addr, count, modif)
284 db_expr_t addr;
285 boolean_t have_addr;
286 db_expr_t count;
287 char *modif;
288 {
289 struct i386_frame *frame;
290 struct proc *p;
291 struct pcb *pcb;
292 struct thread *td;
293 db_addr_t callpc;
294 pid_t pid;
295
296 if (count == -1)
297 count = 1024;
298
299 if (!have_addr) {
300 td = curthread;
301 p = td->td_proc;
302 frame = (struct i386_frame *)ddb_regs.tf_ebp;
303 if (frame == NULL)
304 frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
305 callpc = (db_addr_t)ddb_regs.tf_eip;
306 } else if (!INKERNEL(addr)) {
307 pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
308 ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
309 ((addr >> 16) % 16) * 10000;
310 /*
311 * The pcb for curproc is not valid at this point,
312 * so fall back to the default case.
313 */
314 if (pid == curthread->td_proc->p_pid) {
315 td = curthread;
316 p = td->td_proc;
317 frame = (struct i386_frame *)ddb_regs.tf_ebp;
318 if (frame == NULL)
319 frame = (struct i386_frame *)
320 (ddb_regs.tf_esp - 4);
321 callpc = (db_addr_t)ddb_regs.tf_eip;
322 } else {
323
324 /* sx_slock(&allproc_lock); */
325 LIST_FOREACH(p, &allproc, p_list) {
326 if (p->p_pid == pid)
327 break;
328 }
329 /* sx_sunlock(&allproc_lock); */
330 if (p == NULL) {
331 db_printf("pid %d not found\n", pid);
332 return;
333 }
334 if ((p->p_sflag & PS_INMEM) == 0) {
335 db_printf("pid %d swapped out\n", pid);
336 return;
337 }
338 pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */
339 frame = (struct i386_frame *)pcb->pcb_ebp;
340 if (frame == NULL)
341 frame = (struct i386_frame *)
342 (pcb->pcb_esp - 4);
343 callpc = (db_addr_t)pcb->pcb_eip;
344 }
345 } else {
346 p = NULL;
347 frame = (struct i386_frame *)addr;
348 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
349 frame = frame->f_frame;
350 }
351 db_trace_one_stack(count, have_addr, p, frame, callpc);
352 }
353
354 void
355 db_stack_thread(db_expr_t addr, boolean_t have_addr,
356 db_expr_t count, char *modif)
357 {
358 struct i386_frame *frame;
359 struct thread *td;
360 struct proc *p;
361 struct pcb *pcb;
362 db_addr_t callpc;
363
364 if (!have_addr)
365 return;
366 if (!INKERNEL(addr)) {
367 printf("bad thread address");
368 return;
369 }
370 td = (struct thread *)addr;
371 /* quick sanity check */
372 if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
373 return;
374 if (TD_IS_SWAPPED(td)) {
375 db_printf("thread at %p swapped out\n", td);
376 return;
377 }
378 if (td == curthread) {
379 frame = (struct i386_frame *)ddb_regs.tf_ebp;
380 if (frame == NULL)
381 frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
382 callpc = (db_addr_t)ddb_regs.tf_eip;
383 } else {
384 pcb = td->td_pcb;
385 frame = (struct i386_frame *)pcb->pcb_ebp;
386 if (frame == NULL)
387 frame = (struct i386_frame *) (pcb->pcb_esp - 4);
388 callpc = (db_addr_t)pcb->pcb_eip;
389 }
390 db_trace_one_stack(count, have_addr, p, frame, callpc);
391 }
392
393 static void
394 db_trace_one_stack(int count, boolean_t have_addr,
395 struct proc *p, struct i386_frame *frame, db_addr_t callpc)
396 {
397 int *argp;
398 boolean_t first;
399
400 first = TRUE;
401 while (count--) {
402 struct i386_frame *actframe;
403 int narg;
404 const char * name;
405 db_expr_t offset;
406 c_db_sym_t sym;
407 #define MAXNARG 16
408 char *argnames[MAXNARG], **argnp = NULL;
409
410 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
411 db_symbol_values(sym, &name, NULL);
412
413 /*
414 * Attempt to determine a (possibly fake) frame that gives
415 * the caller's pc. It may differ from `frame' if the
416 * current function never sets up a standard frame or hasn't
417 * set one up yet or has just discarded one. The last two
418 * cases can be guessed fairly reliably for code generated
419 * by gcc. The first case is too much trouble to handle in
420 * general because the amount of junk on the stack depends
421 * on the pc (the special handling of "calltrap", etc. in
422 * db_nextframe() works because the `next' pc is special).
423 */
424 actframe = frame;
425 if (first) {
426 if (!have_addr) {
427 int instr;
428
429 instr = db_get_value(callpc, 4, FALSE);
430 if ((instr & 0x00ffffff) == 0x00e58955) {
431 /* pushl %ebp; movl %esp, %ebp */
432 actframe = (struct i386_frame *)
433 (ddb_regs.tf_esp - 4);
434 } else if ((instr & 0x0000ffff) == 0x0000e589) {
435 /* movl %esp, %ebp */
436 actframe = (struct i386_frame *)
437 ddb_regs.tf_esp;
438 if (ddb_regs.tf_ebp == 0) {
439 /* Fake caller's frame better. */
440 frame = actframe;
441 }
442 } else if ((instr & 0x000000ff) == 0x000000c3) {
443 /* ret */
444 actframe = (struct i386_frame *)
445 (ddb_regs.tf_esp - 4);
446 } else if (offset == 0) {
447 /* Probably a symbol in assembler code. */
448 actframe = (struct i386_frame *)
449 (ddb_regs.tf_esp - 4);
450 }
451 } else if (strcmp(name, "fork_trampoline") == 0) {
452 /*
453 * Don't try to walk back on a stack for a
454 * process that hasn't actually been run yet.
455 */
456 db_print_stack_entry(name, 0, 0, 0, callpc);
457 break;
458 }
459 first = FALSE;
460 }
461
462 argp = &actframe->f_arg0;
463 narg = MAXNARG;
464 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
465 argnp = argnames;
466 } else {
467 narg = db_numargs(frame);
468 }
469
470 db_print_stack_entry(name, narg, argnp, argp, callpc);
471
472 if (actframe != frame) {
473 /* `frame' belongs to caller. */
474 callpc = (db_addr_t)
475 db_get_value((int)&actframe->f_retaddr, 4, FALSE);
476 continue;
477 }
478
479 db_nextframe(&frame, &callpc, p);
480
481 if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) {
482 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
483 db_symbol_values(sym, &name, NULL);
484 db_print_stack_entry(name, 0, 0, 0, callpc);
485 break;
486 }
487 if (!INKERNEL((int) frame)) {
488 break;
489 }
490 }
491 }
492
493 void
494 db_print_backtrace(void)
495 {
496 register_t ebp;
497
498 __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
499 db_stack_trace_cmd(ebp, 1, -1, NULL);
500 }
501
502 #define DB_DRX_FUNC(reg) \
503 int \
504 db_ ## reg (vp, valuep, op) \
505 struct db_variable *vp; \
506 db_expr_t * valuep; \
507 int op; \
508 { \
509 if (op == DB_VAR_GET) \
510 *valuep = r ## reg (); \
511 else \
512 load_ ## reg (*valuep); \
513 return (0); \
514 }
515
516 DB_DRX_FUNC(dr0)
517 DB_DRX_FUNC(dr1)
518 DB_DRX_FUNC(dr2)
519 DB_DRX_FUNC(dr3)
520 DB_DRX_FUNC(dr4)
521 DB_DRX_FUNC(dr5)
522 DB_DRX_FUNC(dr6)
523 DB_DRX_FUNC(dr7)
524
525 int
526 i386_set_watch(watchnum, watchaddr, size, access, d)
527 int watchnum;
528 unsigned int watchaddr;
529 int size;
530 int access;
531 struct dbreg * d;
532 {
533 int i;
534 unsigned int mask;
535
536 if (watchnum == -1) {
537 for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
538 if ((d->dr[7] & mask) == 0)
539 break;
540 if (i < 4)
541 watchnum = i;
542 else
543 return (-1);
544 }
545
546 switch (access) {
547 case DBREG_DR7_EXEC:
548 size = 1; /* size must be 1 for an execution breakpoint */
549 /* fall through */
550 case DBREG_DR7_WRONLY:
551 case DBREG_DR7_RDWR:
552 break;
553 default : return (-1); break;
554 }
555
556 /*
557 * we can watch a 1, 2, or 4 byte sized location
558 */
559 switch (size) {
560 case 1 : mask = 0x00; break;
561 case 2 : mask = 0x01 << 2; break;
562 case 4 : mask = 0x03 << 2; break;
563 default : return (-1); break;
564 }
565
566 mask |= access;
567
568 /* clear the bits we are about to affect */
569 d->dr[7] &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
570
571 /* set drN register to the address, N=watchnum */
572 DBREG_DRX(d,watchnum) = watchaddr;
573
574 /* enable the watchpoint */
575 d->dr[7] |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
576
577 return (watchnum);
578 }
579
580
581 int
582 i386_clr_watch(watchnum, d)
583 int watchnum;
584 struct dbreg * d;
585 {
586
587 if (watchnum < 0 || watchnum >= 4)
588 return (-1);
589
590 d->dr[7] = d->dr[7] & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
591 DBREG_DRX(d,watchnum) = 0;
592
593 return (0);
594 }
595
596
597 int
598 db_md_set_watchpoint(addr, size)
599 db_expr_t addr;
600 db_expr_t size;
601 {
602 int avail, wsize;
603 int i;
604 struct dbreg d;
605
606 fill_dbregs(NULL, &d);
607
608 avail = 0;
609 for(i=0; i<4; i++) {
610 if ((d.dr[7] & (3 << (i*2))) == 0)
611 avail++;
612 }
613
614 if (avail*4 < size)
615 return (-1);
616
617 for (i=0; i<4 && (size != 0); i++) {
618 if ((d.dr[7] & (3<<(i*2))) == 0) {
619 if (size > 4)
620 wsize = 4;
621 else
622 wsize = size;
623 if (wsize == 3)
624 wsize++;
625 i386_set_watch(i, addr, wsize,
626 DBREG_DR7_WRONLY, &d);
627 addr += wsize;
628 size -= wsize;
629 }
630 }
631
632 set_dbregs(NULL, &d);
633
634 return(0);
635 }
636
637
638 int
639 db_md_clr_watchpoint(addr, size)
640 db_expr_t addr;
641 db_expr_t size;
642 {
643 int i;
644 struct dbreg d;
645
646 fill_dbregs(NULL, &d);
647
648 for(i=0; i<4; i++) {
649 if (d.dr[7] & (3 << (i*2))) {
650 if ((DBREG_DRX((&d), i) >= addr) &&
651 (DBREG_DRX((&d), i) < addr+size))
652 i386_clr_watch(i, &d);
653
654 }
655 }
656
657 set_dbregs(NULL, &d);
658
659 return(0);
660 }
661
662
663 static
664 char *
665 watchtype_str(type)
666 int type;
667 {
668 switch (type) {
669 case DBREG_DR7_EXEC : return "execute"; break;
670 case DBREG_DR7_RDWR : return "read/write"; break;
671 case DBREG_DR7_WRONLY : return "write"; break;
672 default : return "invalid"; break;
673 }
674 }
675
676
677 void
678 db_md_list_watchpoints()
679 {
680 int i;
681 struct dbreg d;
682
683 fill_dbregs(NULL, &d);
684
685 db_printf("\nhardware watchpoints:\n");
686 db_printf(" watch status type len address\n");
687 db_printf(" ----- -------- ---------- --- ----------\n");
688 for (i=0; i<4; i++) {
689 if (d.dr[7] & (0x03 << (i*2))) {
690 unsigned type, len;
691 type = (d.dr[7] >> (16+(i*4))) & 3;
692 len = (d.dr[7] >> (16+(i*4)+2)) & 3;
693 db_printf(" %-5d %-8s %10s %3d 0x%08x\n",
694 i, "enabled", watchtype_str(type),
695 len+1, DBREG_DRX((&d),i));
696 }
697 else {
698 db_printf(" %-5d disabled\n", i);
699 }
700 }
701
702 db_printf("\ndebug register values:\n");
703 for (i=0; i<8; i++) {
704 db_printf(" dr%d 0x%08x\n", i, DBREG_DRX((&d),i));
705 }
706 db_printf("\n");
707 }
708
709
Cache object: fad656e0e7eb4b46b9f9c9fde8042070
|