]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/db_trace.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / i386 / db_trace.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58 /*
59 */
60
61 #include <string.h>
62
63 #include <mach/boolean.h>
64 #include <vm/vm_map.h>
65 #include <kern/thread.h>
66 #include <kern/task.h>
67
68 #include <machine/asm.h>
69 #include <machine/db_machdep.h>
70 #include <machine/setjmp.h>
71 #include <mach/machine.h>
72
73 #include <ddb/db_access.h>
74 #include <ddb/db_sym.h>
75 #include <ddb/db_variables.h>
76 #include <ddb/db_command.h>
77 #include <ddb/db_task_thread.h>
78 #include <ddb/db_output.h>
79
80 extern jmp_buf_t *db_recover;
81 extern struct i386_saved_state *saved_state[];
82
83 struct i386_kernel_state ddb_null_kregs;
84
85 /*
86 * Stack trace.
87 */
88
89 extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */
90 #define INKSERVER(va) (((vm_offset_t)(va)) >= vm_min_inks_addr)
91
92 extern vm_offset_t interrupt_stack[];
93 #define ININTSTACK(va) \
94 (((vm_offset_t)(va)) >= interrupt_stack[cpu_number()] &&\
95 (((vm_offset_t)(va)) < interrupt_stack[cpu_number()] + \
96 INTSTACK_SIZE))
97
98 #define INKERNELSTACK(va, th) \
99 (th == THREAD_NULL || \
100 (((vm_offset_t)(va)) >= th->thread->kernel_stack && \
101 (((vm_offset_t)(va)) < th->thread->kernel_stack + \
102 KERNEL_STACK_SIZE)) || \
103 ININTSTACK(va))
104
105 struct i386_frame {
106 struct i386_frame *f_frame;
107 int f_retaddr;
108 int f_arg0;
109 };
110
111 #define TRAP 1
112 #define INTERRUPT 2
113 #define SYSCALL 3
114
115 db_addr_t db_user_trap_symbol_value = 0;
116 db_addr_t db_kernel_trap_symbol_value = 0;
117 db_addr_t db_interrupt_symbol_value = 0;
118 db_addr_t db_return_to_iret_symbol_value = 0;
119 db_addr_t db_syscall_symbol_value = 0;
120 boolean_t db_trace_symbols_found = FALSE;
121
122 struct i386_kregs {
123 char *name;
124 int offset;
125 } i386_kregs[] = {
126 { "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
127 { "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
128 { "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
129 { "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
130 { "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
131 { "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
132 { 0 },
133 };
134
135 /* Forward */
136
137 extern int * db_lookup_i386_kreg(
138 char *name,
139 int *kregp);
140 extern int db_i386_reg_value(
141 struct db_variable * vp,
142 db_expr_t * val,
143 int flag,
144 db_var_aux_param_t ap);
145 extern void db_find_trace_symbols(void);
146 extern int db_numargs(
147 struct i386_frame *fp,
148 task_t task);
149 extern void db_nextframe(
150 struct i386_frame **lfp,
151 struct i386_frame **fp,
152 db_addr_t *ip,
153 int frame_type,
154 thread_t thr_act);
155 extern int _setjmp(
156 jmp_buf_t * jb);
157
158 /*
159 * Machine register set.
160 */
161 struct db_variable db_regs[] = {
162 { "cs", (int *)&ddb_regs.cs, db_i386_reg_value, 0, 0, 0, 0, TRUE },
163 { "ds", (int *)&ddb_regs.ds, db_i386_reg_value, 0, 0, 0, 0, TRUE },
164 { "es", (int *)&ddb_regs.es, db_i386_reg_value, 0, 0, 0, 0, TRUE },
165 { "fs", (int *)&ddb_regs.fs, db_i386_reg_value, 0, 0, 0, 0, TRUE },
166 { "gs", (int *)&ddb_regs.gs, db_i386_reg_value, 0, 0, 0, 0, TRUE },
167 { "ss", (int *)&ddb_regs.ss, db_i386_reg_value, 0, 0, 0, 0, TRUE },
168 { "eax",(int *)&ddb_regs.eax, db_i386_reg_value, 0, 0, 0, 0, TRUE },
169 { "ecx",(int *)&ddb_regs.ecx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
170 { "edx",(int *)&ddb_regs.edx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
171 { "ebx",(int *)&ddb_regs.ebx, db_i386_reg_value, 0, 0, 0, 0, TRUE },
172 { "esp",(int *)&ddb_regs.uesp,db_i386_reg_value, 0, 0, 0, 0, TRUE },
173 { "ebp",(int *)&ddb_regs.ebp, db_i386_reg_value, 0, 0, 0, 0, TRUE },
174 { "esi",(int *)&ddb_regs.esi, db_i386_reg_value, 0, 0, 0, 0, TRUE },
175 { "edi",(int *)&ddb_regs.edi, db_i386_reg_value, 0, 0, 0, 0, TRUE },
176 { "eip",(int *)&ddb_regs.eip, db_i386_reg_value, 0, 0, 0, 0, TRUE },
177 { "efl",(int *)&ddb_regs.efl, db_i386_reg_value, 0, 0, 0, 0, TRUE },
178 };
179 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
180
181 int *
182 db_lookup_i386_kreg(
183 char *name,
184 int *kregp)
185 {
186 register struct i386_kregs *kp;
187
188 for (kp = i386_kregs; kp->name; kp++) {
189 if (strcmp(name, kp->name) == 0)
190 return((int *)((int)kregp + kp->offset));
191 }
192 return(0);
193 }
194
195 int
196 db_i386_reg_value(
197 struct db_variable *vp,
198 db_expr_t *valuep,
199 int flag,
200 db_var_aux_param_t ap)
201 {
202 extern char etext;
203 int *dp = 0;
204 db_expr_t null_reg = 0;
205 register thread_t thr_act = ap->thr_act;
206 extern unsigned int_stack_high;
207 int cpu;
208
209 if (db_option(ap->modif, 'u')) {
210 if (thr_act == THREAD_NULL) {
211 if ((thr_act = current_thread()) == THREAD_NULL)
212 db_error("no user registers\n");
213 }
214 if (thr_act == current_thread()) {
215 if (IS_USER_TRAP(&ddb_regs, &etext))
216 dp = vp->valuep;
217 else if (ddb_regs.ebp < int_stack_high)
218 db_error("cannot get/set user registers in nested interrupt\n");
219 }
220 } else {
221 if (thr_act == THREAD_NULL || thr_act == current_thread()) {
222 dp = vp->valuep;
223 } else {
224 if (thr_act->thread &&
225 !(thr_act->thread->state & TH_STACK_HANDOFF) &&
226 thr_act->thread->kernel_stack) {
227 int cpu;
228
229 for (cpu = 0; cpu < real_ncpus; cpu++) {
230 if (cpu_datap(cpu)->cpu_running == TRUE &&
231 cpu_datap(cpu)->cpu_active_thread == thr_act->thread && saved_state[cpu]) {
232 dp = (int *) (((int)saved_state[cpu]) +
233 (((int) vp->valuep) -
234 (int) &ddb_regs));
235 break;
236 }
237 }
238 if (dp == 0 && thr_act && thr_act->thread)
239 dp = db_lookup_i386_kreg(vp->name,
240 (int *)(STACK_IKS(thr_act->thread->kernel_stack)));
241 if (dp == 0)
242 dp = &null_reg;
243 } else if (thr_act->thread &&
244 (thr_act->thread->state&TH_STACK_HANDOFF)){
245 /* only EIP is valid */
246 if (vp->valuep == (int *) &ddb_regs.eip) {
247 dp = (int *)(&thr_act->thread->continuation);
248 } else {
249 dp = &null_reg;
250 }
251 }
252 }
253 }
254 if (dp == 0) {
255 int cpu;
256
257 if (!db_option(ap->modif, 'u')) {
258 for (cpu = 0; cpu < real_ncpus; cpu++) {
259 if (cpu_datap(cpu)->cpu_running == TRUE &&
260 cpu_datap(cpu)->cpu_active_thread == thr_act->thread && saved_state[cpu]) {
261 dp = (int *) (((int)saved_state[cpu]) +
262 (((int) vp->valuep) -
263 (int) &ddb_regs));
264 break;
265 }
266 }
267 }
268 if (dp == 0) {
269 if (!thr_act || thr_act->machine.pcb == 0)
270 db_error("no pcb\n");
271 dp = (int *)((int)(&thr_act->machine.pcb->iss) +
272 ((int)vp->valuep - (int)&ddb_regs));
273 }
274 }
275 if (flag == DB_VAR_SET)
276 *dp = *valuep;
277 else
278 *valuep = *dp;
279 return(0);
280 }
281
282 void
283 db_find_trace_symbols(void)
284 {
285 db_expr_t value;
286 boolean_t found_some;
287
288 found_some = FALSE;
289 if (db_value_of_name(CC_SYM_PREFIX "user_trap", &value)) {
290 db_user_trap_symbol_value = (db_addr_t) value;
291 found_some = TRUE;
292 }
293 if (db_value_of_name(CC_SYM_PREFIX "kernel_trap", &value)) {
294 db_kernel_trap_symbol_value = (db_addr_t) value;
295 found_some = TRUE;
296 }
297 if (db_value_of_name(CC_SYM_PREFIX "interrupt", &value)) {
298 db_interrupt_symbol_value = (db_addr_t) value;
299 found_some = TRUE;
300 }
301 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
302 db_return_to_iret_symbol_value = (db_addr_t) value;
303 found_some = TRUE;
304 }
305 if (db_value_of_name(CC_SYM_PREFIX "syscall", &value)) {
306 db_syscall_symbol_value = (db_addr_t) value;
307 found_some = TRUE;
308 }
309 if (found_some)
310 db_trace_symbols_found = TRUE;
311 }
312
313 /*
314 * Figure out how many arguments were passed into the frame at "fp".
315 */
316 int db_numargs_default = 5;
317
318 int
319 db_numargs(
320 struct i386_frame *fp,
321 task_t task)
322 {
323 int *argp;
324 int inst;
325 int args;
326 extern char etext;
327
328 argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
329 if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
330 args = db_numargs_default;
331 else if (!DB_CHECK_ACCESS((int)argp, 4, task))
332 args = db_numargs_default;
333 else {
334 inst = db_get_task_value((int)argp, 4, FALSE, task);
335 if ((inst & 0xff) == 0x59) /* popl %ecx */
336 args = 1;
337 else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
338 args = ((inst >> 16) & 0xff) / 4;
339 else
340 args = db_numargs_default;
341 }
342 return (args);
343 }
344
345 struct interrupt_frame {
346 struct i386_frame *if_frame; /* point to next frame */
347 int if_retaddr; /* return address to _interrupt */
348 int if_unit; /* unit number */
349 int if_spl; /* saved spl */
350 int if_iretaddr; /* _return_to_{iret,iret_i} */
351 int if_edx; /* old sp(iret) or saved edx(iret_i) */
352 int if_ecx; /* saved ecx(iret_i) */
353 int if_eax; /* saved eax(iret_i) */
354 int if_eip; /* saved eip(iret_i) */
355 int if_cs; /* saved cs(iret_i) */
356 int if_efl; /* saved efl(iret_i) */
357 };
358
359 /*
360 * Figure out the next frame up in the call stack.
361 * For trap(), we print the address of the faulting instruction and
362 * proceed with the calling frame. We return the ip that faulted.
363 * If the trap was caused by jumping through a bogus pointer, then
364 * the next line in the backtrace will list some random function as
365 * being called. It should get the argument list correct, though.
366 * It might be possible to dig out from the next frame up the name
367 * of the function that faulted, but that could get hairy.
368 */
369 void
370 db_nextframe(
371 struct i386_frame **lfp, /* in/out */
372 struct i386_frame **fp, /* in/out */
373 db_addr_t *ip, /* out */
374 int frame_type, /* in */
375 thread_t thr_act) /* in */
376 {
377 extern char * trap_type[];
378 extern int TRAP_TYPES;
379
380 struct i386_saved_state *saved_regs;
381 struct interrupt_frame *ifp;
382 struct i386_interrupt_state *isp;
383 task_t task = (thr_act != THREAD_NULL)? thr_act->task: TASK_NULL;
384
385 switch(frame_type) {
386 case TRAP:
387 /*
388 * We know that trap() has 1 argument and we know that
389 * it is an (strcut i386_saved_state *).
390 */
391 saved_regs = (struct i386_saved_state *)
392 db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
393 if (saved_regs->trapno >= 0 && saved_regs->trapno < TRAP_TYPES) {
394 db_printf(">>>>> %s trap at ",
395 trap_type[saved_regs->trapno]);
396 } else {
397 db_printf(">>>>> trap (number %d) at ",
398 saved_regs->trapno & 0xffff);
399 }
400 db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
401 db_printf(" <<<<<\n");
402 *fp = (struct i386_frame *)saved_regs->ebp;
403 *ip = (db_addr_t)saved_regs->eip;
404 break;
405 case INTERRUPT:
406 if (*lfp == 0) {
407 db_printf(">>>>> interrupt <<<<<\n");
408 goto miss_frame;
409 }
410 db_printf(">>>>> interrupt at ");
411 ifp = (struct interrupt_frame *)(*lfp);
412 *fp = ifp->if_frame;
413 if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
414 *ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
415 else
416 *ip = (db_addr_t) ifp->if_eip;
417 db_task_printsym(*ip, DB_STGY_PROC, task);
418 db_printf(" <<<<<\n");
419 break;
420 case SYSCALL:
421 if (thr_act != THREAD_NULL && thr_act->machine.pcb) {
422 *ip = (db_addr_t) thr_act->machine.pcb->iss.eip;
423 *fp = (struct i386_frame *) thr_act->machine.pcb->iss.ebp;
424 break;
425 }
426 /* falling down for unknown case */
427 default:
428 miss_frame:
429 *ip = (db_addr_t)
430 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
431 *lfp = *fp;
432 *fp = (struct i386_frame *)
433 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
434 break;
435 }
436 }
437
438 void
439 db_stack_trace_cmd(
440 db_expr_t addr,
441 boolean_t have_addr,
442 db_expr_t count,
443 char *modif)
444 {
445 struct i386_frame *frame, *lastframe;
446 int *argp;
447 db_addr_t callpc, lastcallpc;
448 int frame_type;
449 boolean_t kernel_only = TRUE;
450 boolean_t trace_thread = FALSE;
451 boolean_t trace_all_threads = FALSE;
452 int thcount = 0;
453 char *filename;
454 int linenum;
455 task_t task;
456 thread_t th, top_act;
457 int user_frame;
458 int frame_count;
459 jmp_buf_t *prev;
460 jmp_buf_t db_jmp_buf;
461 queue_entry_t act_list;
462
463 if (!db_trace_symbols_found)
464 db_find_trace_symbols();
465
466 {
467 register char *cp = modif;
468 register char c;
469
470 while ((c = *cp++) != 0) {
471 if (c == 't')
472 trace_thread = TRUE;
473 if (c == 'T') {
474 trace_all_threads = TRUE;
475 trace_thread = TRUE;
476 }
477 if (c == 'u')
478 kernel_only = FALSE;
479 }
480 }
481
482 if (trace_all_threads) {
483 if (!have_addr && !trace_thread) {
484 have_addr = TRUE;
485 trace_thread = TRUE;
486 act_list = &(current_task()->thr_acts);
487 addr = (db_expr_t) queue_first(act_list);
488 } else if (trace_thread) {
489 if (have_addr) {
490 if (!db_check_act_address_valid((thread_t)addr)) {
491 if (db_lookup_task((task_t)addr) == -1)
492 return;
493 act_list = &(((task_t)addr)->thr_acts);
494 addr = (db_expr_t) queue_first(act_list);
495 } else {
496 act_list = &(((thread_t)addr)->task->thr_acts);
497 thcount = db_lookup_task_act(((thread_t)addr)->task,
498 (thread_t)addr);
499 }
500 } else {
501 th = db_default_act;
502 if (th == THREAD_NULL)
503 th = current_thread();
504 if (th == THREAD_NULL) {
505 db_printf("no active thr_act\n");
506 return;
507 }
508 have_addr = TRUE;
509 act_list = &th->task->thr_acts;
510 addr = (db_expr_t) queue_first(act_list);
511 }
512 }
513 }
514
515 if (count == -1)
516 count = 65535;
517
518 next_thread:
519 top_act = THREAD_NULL;
520
521 user_frame = 0;
522 frame_count = count;
523
524 if (!have_addr && !trace_thread) {
525 frame = (struct i386_frame *)ddb_regs.ebp;
526 callpc = (db_addr_t)ddb_regs.eip;
527 th = current_thread();
528 task = (th != THREAD_NULL)? th->task: TASK_NULL;
529 } else if (trace_thread) {
530 if (have_addr) {
531 th = (thread_t) addr;
532 if (!db_check_act_address_valid(th))
533 return;
534 } else {
535 th = db_default_act;
536 if (th == THREAD_NULL)
537 th = current_thread();
538 if (th == THREAD_NULL) {
539 db_printf("no active thread\n");
540 return;
541 }
542 }
543 if (trace_all_threads)
544 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
545 addr, thcount, th->task->thr_act_count);
546
547 next_activation:
548 user_frame = 0;
549
550 task = th->task;
551 if (th == current_thread()) {
552 frame = (struct i386_frame *)ddb_regs.ebp;
553 callpc = (db_addr_t)ddb_regs.eip;
554 } else {
555 if (th->machine.pcb == 0) {
556 db_printf("thread has no pcb\n");
557 return;
558 }
559 if (!th->thread) {
560 register struct i386_saved_state *iss =
561 &th->machine.pcb->iss;
562
563 db_printf("thread has no shuttle\n");
564 #if 0
565 frame = (struct i386_frame *) (iss->ebp);
566 callpc = (db_addr_t) (iss->eip);
567 #else
568 goto thread_done;
569 #endif
570 }
571 else if ((th->thread->state & TH_STACK_HANDOFF) ||
572 th->thread->kernel_stack == 0) {
573 register struct i386_saved_state *iss =
574 &th->machine.pcb->iss;
575
576 db_printf("Continuation ");
577 db_task_printsym((db_expr_t)th->thread->continuation,
578 DB_STGY_PROC, task);
579 db_printf("\n");
580 frame = (struct i386_frame *) (iss->ebp);
581 callpc = (db_addr_t) (iss->eip);
582 } else {
583 int cpu;
584
585 for (cpu = 0; cpu < real_ncpus; cpu++) {
586 if (cpu_datap(cpu)->cpu_running == TRUE &&
587 cpu_datap(cpu)->cpu_active_thread == th->thread &&
588 saved_state[cpu]) {
589 break;
590 }
591 }
592 if (top_act != THREAD_NULL) {
593 /*
594 * Trying to get the backtrace of an activation
595 * which is not the top_most one in the RPC chain:
596 * use the activation's pcb.
597 */
598 register struct i386_saved_state *iss =
599 &th->machine.pcb->iss;
600 frame = (struct i386_frame *) (iss->ebp);
601 callpc = (db_addr_t) (iss->eip);
602 } else {
603 if (cpu == NCPUS) {
604 register struct i386_kernel_state *iks;
605 int r;
606
607 iks = STACK_IKS(th->thread->kernel_stack);
608 prev = db_recover;
609 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
610 frame = (struct i386_frame *) (iks->k_ebp);
611 callpc = (db_addr_t) (iks->k_eip);
612 } else {
613 /*
614 * The kernel stack has probably been
615 * paged out (swapped out activation).
616 */
617 db_recover = prev;
618 if (r == 2) /* 'q' from db_more() */
619 db_error(0);
620 db_printf("<kernel stack (0x%x) error "
621 "(probably swapped out)>\n",
622 iks);
623 goto thread_done;
624 }
625 db_recover = prev;
626 } else {
627 db_printf(">>>>> active on cpu %d <<<<<\n",
628 cpu);
629 frame = (struct i386_frame *)
630 saved_state[cpu]->ebp;
631 callpc = (db_addr_t) saved_state[cpu]->eip;
632 }
633 }
634 }
635 }
636 } else {
637 frame = (struct i386_frame *)addr;
638 th = (db_default_act)? db_default_act: current_thread();
639 task = (th != THREAD_NULL)? th->task: TASK_NULL;
640 callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr,
641 4,
642 FALSE,
643 (user_frame) ? task : 0);
644 }
645
646 if (!INKERNELSTACK((unsigned)frame, th)) {
647 db_printf(">>>>> user space <<<<<\n");
648 if (kernel_only)
649 goto thread_done;
650 user_frame++;
651 } else if (INKSERVER(callpc) && INKSERVER(frame)) {
652 db_printf(">>>>> INKserver space <<<<<\n");
653 }
654
655 lastframe = 0;
656 lastcallpc = (db_addr_t) 0;
657 while (frame_count-- && frame != 0) {
658 int narg;
659 char * name;
660 db_expr_t offset;
661 db_addr_t call_func = 0;
662 int r;
663
664 db_symbol_values(NULL,
665 db_search_task_symbol_and_line(
666 callpc,
667 DB_STGY_XTRN,
668 &offset,
669 &filename,
670 &linenum,
671 (user_frame) ? task : 0,
672 &narg),
673 &name, (db_expr_t *)&call_func);
674 if (user_frame == 0) {
675 if (call_func == db_user_trap_symbol_value ||
676 call_func == db_kernel_trap_symbol_value) {
677 frame_type = TRAP;
678 narg = 1;
679 } else if (call_func == db_interrupt_symbol_value) {
680 frame_type = INTERRUPT;
681 goto next_frame;
682 } else if (call_func == db_syscall_symbol_value) {
683 frame_type = SYSCALL;
684 goto next_frame;
685 } else {
686 frame_type = 0;
687 prev = db_recover;
688 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
689 if (narg < 0)
690 narg = db_numargs(frame,
691 (user_frame) ? task : 0);
692 db_recover = prev;
693 } else {
694 db_recover = prev;
695 goto thread_done;
696 }
697 }
698 } else {
699 frame_type = 0;
700 prev = db_recover;
701 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
702 if (narg < 0)
703 narg = db_numargs(frame,
704 (user_frame) ? task : 0);
705 db_recover = prev;
706 } else {
707 db_recover = prev;
708 goto thread_done;
709 }
710 }
711
712 if (name == 0 || offset > db_maxoff) {
713 db_printf("0x%x 0x%x(", frame, callpc);
714 offset = 0;
715 } else
716 db_printf("0x%x %s(", frame, name);
717
718 argp = &frame->f_arg0;
719 while (narg > 0) {
720 int value;
721
722 prev = db_recover;
723 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
724 value = db_get_task_value((int)argp,
725 4,
726 FALSE,
727 (user_frame) ? task : 0);
728 } else {
729 db_recover = prev;
730 if (r == 2) /* 'q' from db_more() */
731 db_error(0);
732 db_printf("... <stack error>)");
733 if (offset)
734 db_printf("+%x", offset);
735 if (filename) {
736 db_printf(" [%s", filename);
737 if (linenum > 0)
738 db_printf(":%d", linenum);
739 db_printf("]");
740 }
741 db_printf("\n");
742 goto thread_done;
743 }
744 db_recover = prev;
745 db_printf("%x", value);
746 argp++;
747 if (--narg != 0)
748 db_printf(",");
749 }
750 if (narg < 0)
751 db_printf("...");
752 db_printf(")");
753 if (offset) {
754 db_printf("+%x", offset);
755 }
756 if (filename) {
757 db_printf(" [%s", filename);
758 if (linenum > 0)
759 db_printf(":%d", linenum);
760 db_printf("]");
761 }
762 db_printf("\n");
763
764 next_frame:
765 lastcallpc = callpc;
766 db_nextframe(&lastframe, &frame, &callpc, frame_type,
767 (user_frame) ? th : THREAD_NULL);
768
769 if (frame == 0) {
770 if (th->lower != THREAD_NULL) {
771 if (top_act == THREAD_NULL)
772 top_act = th;
773 th = th->lower;
774 db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
775 th,
776 db_lookup_task(th->task),
777 db_lookup_task_act(th->task, th));
778 goto next_activation;
779 }
780 /* end of chain */
781 break;
782 }
783 if (!INKERNELSTACK(lastframe, th) ||
784 !INKERNELSTACK((unsigned)frame, th))
785 user_frame++;
786 if (user_frame == 1) {
787 db_printf(">>>>> user space <<<<<\n");
788 if (kernel_only)
789 break;
790 } else if ((!INKSERVER(lastframe) || !INKSERVER(lastcallpc)) &&
791 (INKSERVER(callpc) && INKSERVER(frame))) {
792 db_printf(">>>>> inkserver space <<<<<\n");
793 }
794 if (frame <= lastframe) {
795 if ((INKERNELSTACK(lastframe, th) &&
796 !INKERNELSTACK(frame, th)) ||
797 (INKSERVER(lastframe) ^ INKSERVER(frame)))
798 continue;
799 db_printf("Bad frame pointer: 0x%x\n", frame);
800 break;
801 }
802 }
803
804 thread_done:
805 if (trace_all_threads) {
806 if (top_act != THREAD_NULL)
807 th = top_act;
808 th = (thread_t) queue_next(&th->thr_acts);
809 if (! queue_end(act_list, (queue_entry_t) th)) {
810 db_printf("\n");
811 addr = (db_expr_t) th;
812 thcount++;
813 goto next_thread;
814
815 }
816 }
817 }