FreeBSD/Linux Kernel Cross Reference
sys/i386/db_trace.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,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 "AS IS"
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 Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_trace.c,v $
29 * Revision 2.14 93/11/17 16:35:37 dbg
30 * Reorganized a little, splitting out db_i386_stack_trace().
31 * Added Cthreads debugging support.
32 * [93/09/24 af]
33 *
34 * Revision 2.13 93/05/17 17:13:23 rvb
35 * machparam.h -> machspl.h
36 * Cleanup's to make gcc generate less warnings.
37 *
38 * Revision 2.12 93/01/14 17:28:48 danner
39 * Proper spl typing. db_symbol_values() changed.
40 * [92/11/30 af]
41 *
42 * Revision 2.11 92/03/10 16:25:36 jsb
43 * Changed db_numargs to use patchable variable db_numargs_default
44 * when it needs to guess the number of arguments, instead of just
45 * using the embedded constant '5'.
46 * [92/03/10 14:21:55 jsb]
47 *
48 * Revision 2.10 91/11/12 11:50:39 rvb
49 * Removed redundant printing of the continuation.
50 * Fixed the log.
51 * [91/11/07 rpd]
52 *
53 * Revision 2.9 91/10/09 16:06:49 af
54 * Supported stack trace and register access of non current thread.
55 * Supported user register access.
56 * Fixed incorrect next frame check.
57 * [91/08/29 tak]
58 *
59 * Fixed stack tracing for threads without kernel stacks. Yes, again.
60 * [91/09/26 rpd]
61 *
62 * Revision 2.8 91/08/28 11:11:34 jsb
63 * In stack traces, print file/line info if available.
64 * [91/08/13 18:15:57 jsb]
65 *
66 * Revision 2.7 91/05/14 16:06:12 mrt
67 * Correcting copyright
68 *
69 * Revision 2.6 91/02/05 17:11:21 mrt
70 * Changed to new Mach copyright
71 * [91/02/01 17:31:32 mrt]
72 *
73 * Revision 2.5 91/01/09 19:55:27 rpd
74 * Fixed stack tracing for threads without kernel stacks.
75 * [91/01/09 rpd]
76 *
77 * Revision 2.4 91/01/08 15:10:22 rpd
78 * Reorganized the pcb.
79 * [90/12/11 rpd]
80 *
81 * Revision 2.3 90/11/05 14:27:07 rpd
82 * If we can not guess the number of args to a function, use 5 vs 0.
83 * [90/11/02 rvb]
84 *
85 * Revision 2.2 90/08/27 21:56:20 dbg
86 * Import db_sym.h.
87 * [90/08/21 dbg]
88 * Fix includes.
89 * [90/08/08 dbg]
90 * Created from rvb's code for new debugger.
91 * [90/07/11 dbg]
92 *
93 */
94
95 #include <mach/boolean.h>
96 #include <vm/vm_map.h>
97 #include <kern/thread.h>
98 #include <kern/task.h>
99
100 #include <machine/db_machdep.h>
101 #include <machine/machspl.h>
102
103 #include <ddb/db_access.h>
104 #include <ddb/db_command.h>
105 #include <ddb/db_output.h>
106 #include <ddb/db_sym.h>
107 #include <ddb/db_variables.h>
108 #include <ddb/db_task_thread.h>
109
110 void db_i386_reg_value(
111 struct db_variable *vp,
112 db_expr_t *valuep,
113 int flag,
114 struct db_var_aux_param *ap); /* forward */
115
116 /*
117 * Machine register set.
118 */
119 struct db_variable db_regs[] = {
120 { "cs", (int *)&ddb_regs.cs, db_i386_reg_value },
121 { "ds", (int *)&ddb_regs.ds, db_i386_reg_value },
122 { "es", (int *)&ddb_regs.es, db_i386_reg_value },
123 { "fs", (int *)&ddb_regs.fs, db_i386_reg_value },
124 { "gs", (int *)&ddb_regs.gs, db_i386_reg_value },
125 { "ss", (int *)&ddb_regs.ss, db_i386_reg_value },
126 { "eax",(int *)&ddb_regs.eax, db_i386_reg_value },
127 { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value },
128 { "edx",(int *)&ddb_regs.edx, db_i386_reg_value },
129 { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value },
130 { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value },
131 { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value },
132 { "esi",(int *)&ddb_regs.esi, db_i386_reg_value },
133 { "edi",(int *)&ddb_regs.edi, db_i386_reg_value },
134 { "eip",(int *)&ddb_regs.eip, db_i386_reg_value },
135 { "efl",(int *)&ddb_regs.efl, db_i386_reg_value },
136 };
137 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
138
139 /*
140 * Stack trace.
141 */
142 #define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
143
144 struct i386_frame {
145 struct i386_frame *f_frame;
146 int f_retaddr;
147 int f_arg0;
148 };
149
150 #define TRAP 1
151 #define INTERRUPT 2
152 #define SYSCALL 3
153
154 db_addr_t db_user_trap_symbol_value = 0;
155 db_addr_t db_kernel_trap_symbol_value = 0;
156 db_addr_t db_interrupt_symbol_value = 0;
157 db_addr_t db_return_to_iret_symbol_value = 0;
158 db_addr_t db_syscall_symbol_value = 0;
159 boolean_t db_trace_symbols_found = FALSE;
160
161 struct i386_kregs {
162 char *name;
163 int offset;
164 } i386_kregs[] = {
165 { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
166 { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
167 { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
168 { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
169 { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
170 { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
171 { 0 },
172 };
173
174 int *
175 db_lookup_i386_kreg(
176 char *name,
177 int *kregp)
178 {
179 register struct i386_kregs *kp;
180
181 for (kp = i386_kregs; kp->name; kp++) {
182 if (strcmp(name, kp->name) == 0)
183 return (int *)((int)kregp + kp->offset);
184 }
185 return 0;
186 }
187
188 void
189 db_i386_reg_value(
190 struct db_variable *vp,
191 db_expr_t *valuep,
192 int flag,
193 db_var_aux_param_t ap)
194 {
195 int *dp = 0;
196 db_expr_t null_reg = 0;
197 register thread_t thread = ap->thread;
198 extern unsigned int_stack_high;
199
200 if (db_option(ap->modif, 'u')) {
201 if (thread == THREAD_NULL) {
202 if ((thread = current_thread()) == THREAD_NULL)
203 db_error("no user registers\n");
204 }
205 if (thread == current_thread()) {
206 if (ddb_regs.cs & 0x3)
207 dp = vp->valuep;
208 else if (ddb_regs.ebp < int_stack_high)
209 db_error("cannot get/set user registers in nested interrupt\n");
210 }
211 } else {
212 if (thread == THREAD_NULL || thread == current_thread()) {
213 dp = vp->valuep;
214 } else if ((thread->state & TH_SWAPPED) == 0 &&
215 thread->kernel_stack) {
216 dp = db_lookup_i386_kreg(vp->name,
217 (int *)(STACK_IKS(thread->kernel_stack)));
218 if (dp == 0)
219 dp = &null_reg;
220 } else if ((thread->state & TH_SWAPPED) &&
221 thread->swap_func != thread_exception_return) {
222 /*.....this breaks t/t $taskN.0...*/
223 /* only EIP is valid */
224 if (vp->valuep == (int *) &ddb_regs.eip) {
225 dp = (int *)(&thread->swap_func);
226 } else {
227 dp = &null_reg;
228 }
229 }
230 }
231 if (dp == 0) {
232 if (thread->pcb == 0)
233 db_error("no pcb\n");
234 dp = (int *)((int)(&thread->pcb->iss) +
235 ((int)vp->valuep - (int)&ddb_regs));
236 }
237 if (flag == DB_VAR_SET)
238 *dp = *valuep;
239 else
240 *valuep = *dp;
241 }
242
243 void
244 db_find_trace_symbols(void)
245 {
246 db_expr_t value;
247 if (db_value_of_name("_user_trap", &value))
248 db_user_trap_symbol_value = (db_addr_t) value;
249 if (db_value_of_name("_kernel_trap", &value))
250 db_kernel_trap_symbol_value = (db_addr_t) value;
251 if (db_value_of_name("_interrupt", &value))
252 db_interrupt_symbol_value = (db_addr_t) value;
253 if (db_value_of_name("_return_to_iret", &value))
254 db_return_to_iret_symbol_value = (db_addr_t) value;
255 if (db_value_of_name("_syscall", &value))
256 db_syscall_symbol_value = (db_addr_t) value;
257 db_trace_symbols_found = TRUE;
258 }
259
260 /*
261 * Figure out how many arguments were passed into the frame at "fp".
262 */
263 int db_numargs_default = 5;
264
265 int
266 db_numargs(
267 struct i386_frame *fp,
268 task_t task)
269 {
270 int *argp;
271 int inst;
272 int args;
273 extern char etext[];
274
275 argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
276 if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
277 args = db_numargs_default;
278 else if (!DB_CHECK_ACCESS((int)argp, 4, task))
279 args = db_numargs_default;
280 else {
281 inst = db_get_task_value((int)argp, 4, FALSE, task);
282 if ((inst & 0xff) == 0x59) /* popl %ecx */
283 args = 1;
284 else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
285 args = ((inst >> 16) & 0xff) / 4;
286 else
287 args = db_numargs_default;
288 }
289 return args;
290 }
291
292 struct interrupt_frame {
293 struct i386_frame *if_frame; /* point to next frame */
294 int if_retaddr; /* return address to _interrupt */
295 int if_unit; /* unit number */
296 spl_t if_spl; /* saved spl */
297 int if_iretaddr; /* _return_to_{iret,iret_i} */
298 int if_edx; /* old sp(iret) or saved edx(iret_i) */
299 int if_ecx; /* saved ecx(iret_i) */
300 int if_eax; /* saved eax(iret_i) */
301 int if_eip; /* saved eip(iret_i) */
302 int if_cs; /* saved cs(iret_i) */
303 int if_efl; /* saved efl(iret_i) */
304 };
305
306 /*
307 * Figure out the next frame up in the call stack.
308 * For trap(), we print the address of the faulting instruction and
309 * proceed with the calling frame. We return the ip that faulted.
310 * If the trap was caused by jumping through a bogus pointer, then
311 * the next line in the backtrace will list some random function as
312 * being called. It should get the argument list correct, though.
313 * It might be possible to dig out from the next frame up the name
314 * of the function that faulted, but that could get hairy.
315 */
316 void
317 db_nextframe(
318 struct i386_frame **lfp, /* in/out */
319 struct i386_frame **fp, /* in/out */
320 db_addr_t *ip, /* out */
321 int frame_type, /* in */
322 thread_t thread) /* in */
323 {
324 extern char * trap_type[];
325 extern int TRAP_TYPES;
326
327 struct i386_saved_state *saved_regs;
328 struct interrupt_frame *ifp;
329 task_t task = (thread != THREAD_NULL)? thread->task: TASK_NULL;
330
331 switch(frame_type) {
332 case TRAP:
333 /*
334 * We know that trap() has 1 argument and we know that
335 * it is an (struct i386_saved_state *).
336 */
337 saved_regs = (struct i386_saved_state *)
338 db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
339 if (saved_regs->trapno < TRAP_TYPES) { /* trapno is unsigned */
340 db_printf(">>>>> %s trap at ",
341 trap_type[saved_regs->trapno]);
342 } else {
343 db_printf(">>>>> trap (number %d) at ",
344 saved_regs->trapno & 0xffff);
345 }
346 db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
347 db_printf(" <<<<<\n");
348 *fp = (struct i386_frame *)saved_regs->ebp;
349 *ip = (db_addr_t)saved_regs->eip;
350 break;
351 case INTERRUPT:
352 if (*lfp == 0) {
353 db_printf(">>>>> interrupt <<<<<\n");
354 goto miss_frame;
355 }
356 db_printf(">>>>> interrupt at ");
357 ifp = (struct interrupt_frame *)(*lfp);
358 *fp = ifp->if_frame;
359 if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
360 *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
361 else
362 *ip = (db_addr_t) ifp->if_eip;
363 db_task_printsym(*ip, DB_STGY_PROC, task);
364 db_printf(" <<<<<\n");
365 break;
366 case SYSCALL:
367 if (thread != THREAD_NULL && thread->pcb) {
368 *ip = (db_addr_t) thread->pcb->iss.eip;
369 *fp = (struct i386_frame *) thread->pcb->iss.ebp;
370 break;
371 }
372 /* falling down for unknown case */
373 default:
374 miss_frame:
375 *ip = (db_addr_t)
376 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
377 *lfp = *fp;
378 *fp = (struct i386_frame *)
379 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
380 break;
381 }
382 }
383
384 void
385 db_i386_stack_trace(
386 thread_t th,
387 struct i386_frame *frame,
388 db_addr_t callpc,
389 db_expr_t count,
390 int flags); /* forward */
391
392 #define F_USER_TRACE 1
393 #define F_TRACE_THREAD 2
394
395 void
396 db_stack_trace_cmd(
397 db_expr_t addr,
398 boolean_t have_addr,
399 db_expr_t count,
400 char *modif)
401 {
402 boolean_t trace_thread = FALSE;
403 struct i386_frame *frame;
404 db_addr_t callpc;
405 int flags = 0;
406 thread_t th;
407
408 {
409 register char *cp = modif;
410 register char c;
411
412 while ((c = *cp++) != 0) {
413 if (c == 't')
414 trace_thread = TRUE;
415 if (c == 'u')
416 flags |= F_USER_TRACE;
417 }
418 }
419
420 if (!have_addr && !trace_thread) {
421 frame = (struct i386_frame *)ddb_regs.ebp;
422 callpc = (db_addr_t)ddb_regs.eip;
423 th = current_thread();
424 } else if (trace_thread) {
425 if (have_addr) {
426 th = (thread_t) addr;
427 if (!db_check_thread_address_valid((db_addr_t)th))
428 return;
429 } else {
430 th = db_default_thread;
431 if (th == THREAD_NULL)
432 th = current_thread();
433 if (th == THREAD_NULL) {
434 db_printf("no active thread\n");
435 return;
436 }
437 }
438 if (th == current_thread()) {
439 frame = (struct i386_frame *)ddb_regs.ebp;
440 callpc = (db_addr_t)ddb_regs.eip;
441 } else {
442 if (th->pcb == 0) {
443 db_printf("thread has no pcb\n");
444 return;
445 }
446 if ((th->state & TH_SWAPPED) || th->kernel_stack == 0) {
447 register struct i386_saved_state *iss = &th->pcb->iss;
448
449 db_printf("Continuation ");
450 db_task_printsym((db_expr_t)th->swap_func,
451 DB_STGY_PROC,
452 th->task);
453 db_printf("\n");
454
455 frame = (struct i386_frame *) (iss->ebp);
456 callpc = (db_addr_t) (iss->eip);
457 } else {
458 register struct i386_kernel_state *iks;
459 iks = STACK_IKS(th->kernel_stack);
460 frame = (struct i386_frame *) (iks->k_ebp);
461 callpc = (db_addr_t) (iks->k_eip);
462 }
463 }
464 } else {
465 frame = (struct i386_frame *)addr;
466 th = (db_default_thread)? db_default_thread: current_thread();
467 callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, 4,
468 FALSE,
469 (th == THREAD_NULL) ? TASK_NULL : th->task);
470 }
471
472 db_i386_stack_trace( th, frame, callpc, count, flags );
473 }
474
475
476 void
477 db_i386_stack_trace(
478 thread_t th,
479 struct i386_frame *frame,
480 db_addr_t callpc,
481 db_expr_t count,
482 int flags)
483 {
484 task_t task;
485 boolean_t kernel_only;
486 int *argp;
487 int user_frame = 0;
488 struct i386_frame *lastframe;
489 int frame_type;
490 char *filename;
491 int linenum;
492 extern unsigned int db_maxoff;
493
494 if (count == -1)
495 count = 65535;
496
497 kernel_only = (flags & F_USER_TRACE) == 0;
498
499 task = (th == THREAD_NULL) ? TASK_NULL : th->task;
500
501 if (!db_trace_symbols_found)
502 db_find_trace_symbols();
503
504 if (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)) {
505 db_printf(">>>>> user space <<<<<\n");
506 user_frame++;
507 }
508
509 lastframe = 0;
510 while (count-- && frame != 0) {
511 register int narg;
512 char * name;
513 db_expr_t offset;
514
515 if (INKERNEL((unsigned)callpc) && user_frame == 0) {
516 db_addr_t call_func = 0;
517
518 db_symbol_values(0, db_search_task_symbol(callpc,
519 DB_STGY_XTRN, (db_addr_t *)&offset,
520 TASK_NULL),
521 &name, (db_expr_t *)&call_func);
522 if (call_func == db_user_trap_symbol_value ||
523 call_func == db_kernel_trap_symbol_value) {
524 frame_type = TRAP;
525 narg = 1;
526 } else if (call_func == db_interrupt_symbol_value) {
527 frame_type = INTERRUPT;
528 goto next_frame;
529 } else if (call_func == db_syscall_symbol_value) {
530 frame_type = SYSCALL;
531 goto next_frame;
532 } else {
533 frame_type = 0;
534 narg = db_numargs(frame, task);
535 }
536 } else if (INKERNEL((unsigned)callpc) ^ INKERNEL((unsigned)frame)) {
537 frame_type = 0;
538 narg = -1;
539 } else {
540 frame_type = 0;
541 narg = db_numargs(frame, task);
542 }
543
544 db_find_task_sym_and_offset(callpc, &name,
545 (db_addr_t *)&offset, task);
546 if (name == 0 || offset > db_maxoff) {
547 db_printf("0x%x(", callpc);
548 offset = 0;
549 } else
550 db_printf("%s(", name);
551
552 argp = &frame->f_arg0;
553 while (narg > 0) {
554 db_printf("%x", db_get_task_value((int)argp,4,FALSE,task));
555 argp++;
556 if (--narg != 0)
557 db_printf(",");
558 }
559 if (narg < 0)
560 db_printf("...");
561 db_printf(")");
562 if (offset) {
563 db_printf("+%x", offset);
564 }
565 if (db_line_at_pc(0, &filename, &linenum, callpc)) {
566 db_printf(" [%s", filename);
567 if (linenum > 0)
568 db_printf(":%d", linenum);
569 db_printf("]");
570 }
571 db_printf("\n");
572
573 next_frame:
574 db_nextframe(&lastframe, &frame, &callpc, frame_type, th);
575
576 if (frame == 0) {
577 /* end of chain */
578 break;
579 }
580 if (!INKERNEL(lastframe) ||
581 (!INKERNEL((unsigned)callpc) && !INKERNEL((unsigned)frame)))
582 user_frame++;
583 if (user_frame == 1) {
584 db_printf(">>>>> user space <<<<<\n");
585 if (kernel_only)
586 break;
587 }
588 if (frame <= lastframe) {
589 if (INKERNEL(lastframe) && !INKERNEL(frame))
590 continue;
591 db_printf("Bad frame pointer: 0x%x\n", frame);
592 break;
593 }
594 }
595 }
596
597 #define CTHREADS_SUPPORT 1
598
599 #if CTHREADS_SUPPORT
600
601 thread_t
602 db_find_kthread(
603 vm_offset_t ustack_base,
604 vm_size_t ustack_top,
605 task_t task)
606 {
607 thread_t thread;
608
609 queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
610 vm_offset_t usp = thread->pcb->iss.uesp/*ebp works*/;
611 if (usp >= ustack_base && usp < ustack_top)
612 return thread;
613 }
614 return THREAD_NULL;
615 }
616
617 static void db_cproc_state(
618 int state,
619 char s[4])
620 {
621 if (state == 0) {
622 *s++ = 'R';
623 } else {
624 if (state & 1) *s++ = 'S';
625 if (state & 2) *s++ = 'B';
626 if (state & 4) *s++ = 'C';
627 }
628 *s = 0;
629 }
630
631 /* offsets in a cproc structure */
632 int db_cproc_next_offset = 0 * 4;
633 int db_cproc_incarnation_offset = 1 * 4;
634 int db_cproc_list_offset = 2 * 4;
635 int db_cproc_wait_offset = 3 * 4;
636 int db_cproc_context_offset = 5 * 4;
637 int db_cproc_state_offset = 7 * 4;
638 int db_cproc_stack_base_offset = 10 * 4 + sizeof(mach_msg_header_t);
639 int db_cproc_stack_size_offset = 11 * 4 + sizeof(mach_msg_header_t);
640
641 /* offsets in a cproc_switch context structure */
642 int db_cprocsw_framep_offset = 3 * 4;
643 int db_cprocsw_pc_offset = 4 * 4;
644
645 #include <machine/setjmp.h>
646
647 extern jmp_buf_t *db_recover;
648
649 void db_trace_cproc(
650 vm_offset_t cproc,
651 thread_t thread)
652 {
653 jmp_buf_t db_jmpbuf;
654 jmp_buf_t *prev = db_recover;
655 task_t task;
656 db_addr_t pc, fp;
657
658 task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
659
660 if (!_setjmp(db_recover = &db_jmpbuf)) {
661 char pstate[4];
662 unsigned int s, w, n, c, cth;
663
664 s = db_get_task_value(cproc + db_cproc_state_offset, 4, FALSE, task);
665 w = db_get_task_value(cproc + db_cproc_wait_offset, 4, FALSE, task);
666 n = db_get_task_value(cproc + db_cproc_next_offset, 4, FALSE, task);
667 c = db_get_task_value(cproc + db_cproc_context_offset, 4, FALSE, task);
668 cth = db_get_task_value(cproc + db_cproc_incarnation_offset, 4, FALSE, task);
669
670 db_cproc_state(s, pstate);
671
672 db_printf("CThread %x (cproc %x) %s", cth, cproc, pstate);
673 if (w) db_printf(" awaits %x", w);
674 if (n) db_printf(" next %x", n);
675 db_printf("\n");
676
677 if ((s != 0) && (c != 0)) {
678 pc = db_get_task_value(c + db_cprocsw_pc_offset, 4, FALSE, task);
679 fp = c + db_cprocsw_framep_offset;
680 } else {
681 db_addr_t sb;
682 vm_size_t ss;
683
684 sb = db_get_task_value(cproc + db_cproc_stack_base_offset, sizeof(db_expr_t), FALSE, task);
685 ss = db_get_task_value(cproc + db_cproc_stack_size_offset, sizeof(db_expr_t), FALSE, task);
686 db_printf(" Stack base: %x\n", sb);
687 /*
688 * Lessee now..
689 */
690 thread = db_find_kthread(sb, sb+ss, task);
691 if (thread != THREAD_NULL) {
692 pc = thread->pcb->iss.eip;
693 fp = thread->pcb->iss.ebp;
694 } else
695 fp = -1;
696 }
697
698 if (fp != -1)
699 db_i386_stack_trace(thread, (struct i386_frame*)fp, pc,
700 -1, F_USER_TRACE);
701 }
702
703 db_recover = prev;
704 }
705
706 void db_all_cprocs(
707 task_t task,
708 db_expr_t cproc_list)
709 {
710 jmp_buf_t db_jmpbuf;
711 jmp_buf_t *prev = db_recover;
712 thread_t thread;
713 db_expr_t cproc, next;
714
715
716 if (task != TASK_NULL) {
717 thread = (thread_t) queue_first(&task->thread_list);
718 } else
719 thread = current_thread();
720
721 if (cproc_list != 0)
722 next = cproc_list;
723 else
724 if (!db_value_of_name("unix::cproc_list", &next)) {
725 db_printf("No cprocs.\n");
726 return;
727 }
728
729
730 while (next) {
731 if (_setjmp(db_recover = &db_jmpbuf))
732 break;
733
734 cproc = db_get_task_value(next, 4, FALSE, TASK_NULL);
735 if (cproc == 0) break;
736 next = cproc + db_cproc_list_offset;
737
738 db_trace_cproc(cproc, thread);
739 }
740
741 db_recover = prev;
742 }
743
744 #endif /* CTHREADS_SUPPORT */
Cache object: b36f021c36ad0e32c0e3ea17c36d9dba
|