]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/db_trace.c
8b46071b35d8b3316591cd9503875bd3ef1dcd88
[apple/xnu.git] / osfmk / ppc / 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 #include <string.h>
35
36 #include <mach/boolean.h>
37 #include <vm/vm_map.h>
38 #include <kern/thread.h>
39 #include <kern/processor.h>
40 #include <kern/task.h>
41
42 #include <ppc/cpu_internal.h>
43 #include <ppc/exception.h>
44 #include <machine/asm.h>
45 #include <machine/db_machdep.h>
46 #include <machine/setjmp.h>
47 #include <mach/machine.h>
48
49 #include <ddb/db_access.h>
50 #include <ddb/db_sym.h>
51 #include <ddb/db_variables.h>
52 #include <ddb/db_command.h>
53 #include <ddb/db_task_thread.h>
54 #include <ddb/db_output.h>
55
56 extern jmp_buf_t *db_recover;
57
58 struct savearea ddb_null_kregs;
59
60 extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */
61
62 #define DB_NUMARGS_MAX 5
63
64
65 #define INFIXEDSTACK(va) 0 \
66
67 #define INKERNELSTACK(va, th) 1
68
69 struct db_ppc_frame {
70 struct db_ppc_frame *f_frame;
71 int pad1;
72 uint32_t f_retaddr;
73 int pad3;
74 int pad4;
75 int pad5;
76 uint32_t f_arg[DB_NUMARGS_MAX];
77 };
78
79 #define TRAP 1
80 #define INTERRUPT 2
81 #define SYSCALL 3
82
83 db_addr_t db_user_trap_symbol_value = 0;
84 db_addr_t db_kernel_trap_symbol_value = 0;
85 db_addr_t db_interrupt_symbol_value = 0;
86 db_addr_t db_return_to_iret_symbol_value = 0;
87 db_addr_t db_syscall_symbol_value = 0;
88 boolean_t db_trace_symbols_found = FALSE;
89
90 extern int db_ppc_reg_value(
91 struct db_variable * vp,
92 db_expr_t * val,
93 int flag,
94 db_var_aux_param_t ap);
95 extern void db_find_trace_symbols(void);
96 extern int db_numargs(
97 struct db_ppc_frame *fp,
98 task_t task);
99 extern boolean_t db_find_arg(
100 struct db_ppc_frame *frame,
101 db_addr_t calleepc,
102 task_t task,
103 int narg,
104 db_addr_t *arg);
105 extern void db_nextframe(
106 struct db_ppc_frame **lfp,
107 struct db_ppc_frame **fp,
108 db_addr_t *ip,
109 int frame_type,
110 thread_act_t thr_act,
111 db_addr_t linkpc);
112 extern int _setjmp(
113 jmp_buf_t * jb);
114
115 /*
116 * Machine register set.
117 */
118 struct db_variable db_regs[] = {
119 /* XXX "pc" is an alias to "srr0"... */
120 { "pc", &ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
121 { "srr0", &ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
122 { "srr1", &ddb_regs.save_srr1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
123 { "r0", &ddb_regs.save_r0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
124 { "r1", &ddb_regs.save_r1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
125 { "r2", &ddb_regs.save_r2, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
126 { "r3", &ddb_regs.save_r3, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
127 { "r4", &ddb_regs.save_r4, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
128 { "r5", &ddb_regs.save_r5, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
129 { "r6", &ddb_regs.save_r6, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
130 { "r7", &ddb_regs.save_r7, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
131 { "r8", &ddb_regs.save_r8, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
132 { "r9", &ddb_regs.save_r9, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
133 { "r10", &ddb_regs.save_r10, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
134 { "r11", &ddb_regs.save_r11, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
135 { "r12", &ddb_regs.save_r12, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
136 { "r13", &ddb_regs.save_r13, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
137 { "r14", &ddb_regs.save_r14, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
138 { "r15", &ddb_regs.save_r15, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
139 { "r16", &ddb_regs.save_r16, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
140 { "r17", &ddb_regs.save_r17, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
141 { "r18", &ddb_regs.save_r18, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
142 { "r19", &ddb_regs.save_r19, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
143 { "r20", &ddb_regs.save_r20, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
144 { "r21", &ddb_regs.save_r21, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
145 { "r22", &ddb_regs.save_r22, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
146 { "r23", &ddb_regs.save_r23, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
147 { "r24", &ddb_regs.save_r24, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
148 { "r25", &ddb_regs.save_r25, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
149 { "r26", &ddb_regs.save_r26, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
150 { "r27", &ddb_regs.save_r27, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
151 { "r28", &ddb_regs.save_r28, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
152 { "r29", &ddb_regs.save_r29, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
153 { "r30", &ddb_regs.save_r30, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
154 { "r31", &ddb_regs.save_r31, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
155 { "cr", &ddb_regs.save_cr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
156 { "xer", &ddb_regs.save_xer, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
157 { "lr", &ddb_regs.save_lr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
158 { "ctr", &ddb_regs.save_ctr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
159 };
160 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
161
162 int
163 db_ppc_reg_value(
164 struct db_variable *vp,
165 db_expr_t *valuep,
166 int flag,
167 db_var_aux_param_t ap)
168 {
169 db_expr_t *dp = 0;
170 db_expr_t null_reg = 0;
171 uint32_t *dp32;
172
173 register thread_act_t thr_act = ap->thr_act;
174 int cpu;
175
176 if (db_option(ap->modif, 'u')) {
177 if (thr_act == THR_ACT_NULL) {
178 if ((thr_act = current_thread()) == THR_ACT_NULL)
179 db_error("no user registers\n");
180 }
181 if (thr_act == current_thread()) {
182 if (IS_USER_TRAP((&ddb_regs))) dp = vp->valuep;
183 else if (INFIXEDSTACK(ddb_regs.save_r1))
184 db_error("cannot get/set user registers in nested interrupt\n");
185 }
186 }
187 else {
188 if (thr_act == THR_ACT_NULL || thr_act == current_thread()) {
189 dp = vp->valuep;
190 }
191 else {
192 if (thr_act->kernel_stack) {
193
194 int cpu;
195
196 for (cpu = 0; cpu < real_ncpus; cpu++) {
197 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
198 cpu_to_processor(cpu)->active_thread == thr_act &&
199 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
200
201 dp = (db_expr_t)(((uint32_t)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
202 (((uint32_t) vp->valuep) -
203 (uint32_t) &ddb_regs));
204 break;
205 }
206 }
207
208 if (dp == 0) dp = &null_reg;
209 }
210 else {
211 /* only PC is valid */
212 if (vp->valuep == (int *) &ddb_regs.save_srr0) {
213 dp = (int *)(&thr_act->continuation);
214 }
215 else {
216 dp = &null_reg;
217 }
218 }
219 }
220 }
221 if (dp == 0) {
222
223 if (!db_option(ap->modif, 'u')) {
224 for (cpu = 0; cpu < real_ncpus; cpu++) {
225 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
226 cpu_to_processor(cpu)->active_thread == thr_act &&
227 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
228 dp = (int *) (((int)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
229 (((int) vp->valuep) - (int) &ddb_regs));
230 break;
231 }
232 }
233 }
234 if (dp == 0) {
235 if (!thr_act || thr_act->machine.pcb == 0) db_error("no pcb\n");
236 dp = (int *)((int)thr_act->machine.pcb + ((int)vp->valuep - (int)&ddb_regs));
237 }
238 }
239
240 if(vp->valuep == (int *) &ddb_regs.save_cr) { /* Is this the CR we are doing? */
241 dp32 = (uint32_t *)dp; /* Make this easier */
242 if (flag == DB_VAR_SET) *dp32 = *valuep;
243 else *valuep = *dp32;
244 }
245 else { /* Normal 64-bit registers */
246 if (flag == DB_VAR_SET) *dp = *valuep;
247 else *valuep = *(unsigned long long *)dp;
248 }
249
250 return(0);
251 }
252
253
254 void
255 db_find_trace_symbols(void)
256 {
257 db_expr_t value;
258 boolean_t found_some;
259
260 found_some = FALSE;
261 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
262 db_user_trap_symbol_value = (db_addr_t) value;
263 found_some = TRUE;
264 }
265 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
266 db_kernel_trap_symbol_value = (db_addr_t) value;
267 found_some = TRUE;
268 }
269 if (db_value_of_name(CC_SYM_PREFIX "ihandler", &value)) {
270 db_interrupt_symbol_value = (db_addr_t) value;
271 found_some = TRUE;
272 }
273 #if 0
274 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
275 db_return_to_iret_symbol_value = (db_addr_t) value;
276 found_some = TRUE;
277 }
278 #endif
279 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
280 db_syscall_symbol_value = (db_addr_t) value;
281 found_some = TRUE;
282 }
283 if (found_some)
284 db_trace_symbols_found = TRUE;
285 }
286
287 int
288 db_numargs(
289 struct db_ppc_frame *fp,
290 task_t task)
291 {
292 return (DB_NUMARGS_MAX);
293 }
294
295 boolean_t
296 db_find_arg(
297 struct db_ppc_frame *fp,
298 db_addr_t calleepc,
299 task_t task,
300 int narg,
301 db_addr_t *arg)
302 {
303 db_addr_t argp;
304 db_addr_t calleep;
305 db_addr_t offset;
306 int i;
307 int inst;
308 char *name;
309
310 #if 0
311 db_find_task_sym_and_offset(calleepc, &name, &offset, task);
312 calleep = calleepc-offset;
313
314 for (i = 0; calleep < calleepc; i++, calleep++) {
315 if (!DB_CHECK_ACCESS((int) calleep, 4, task)) {
316 continue;
317 }
318 inst = db_get_task_value(calleep, 4, FALSE, task);
319 if ((inst & 0xffff0000) == (0x907f0000 + (narg << 21)) ||
320 (inst & 0xffff0000) == (0x90610000 + (narg << 21))) {
321 argp = (db_addr_t) &(fp->f_arg[narg]);
322 *arg = argp;
323 return TRUE;
324 }
325 }
326 #endif
327 return FALSE;
328 }
329
330 /*
331 * Figure out the next frame up in the call stack.
332 * For trap(), we print the address of the faulting instruction and
333 * proceed with the calling frame. We return the ip that faulted.
334 * If the trap was caused by jumping through a bogus pointer, then
335 * the next line in the backtrace will list some random function as
336 * being called. It should get the argument list correct, though.
337 * It might be possible to dig out from the next frame up the name
338 * of the function that faulted, but that could get hairy.
339 */
340 void
341 db_nextframe(
342 struct db_ppc_frame **lfp, /* in/out */
343 struct db_ppc_frame **fp, /* in/out */
344 db_addr_t *ip, /* out */
345 int frame_type, /* in */
346 thread_act_t thr_act,
347 db_addr_t linkpc) /* in */
348 {
349 extern char * trap_type[];
350 extern int TRAP_TYPES;
351
352 struct savearea *saved_regs;
353
354 task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL;
355
356 switch(frame_type) {
357 case TRAP:
358
359 db_printf(">>>>> trap <<<<<\n");
360 goto miss_frame;
361 break;
362 case INTERRUPT:
363 if (*lfp == 0) {
364 db_printf(">>>>> interrupt <<<<<\n");
365 goto miss_frame;
366 }
367 db_printf(">>>>> interrupt <<<<<\n");
368 goto miss_frame;
369 break;
370 case SYSCALL:
371 if (thr_act != THR_ACT_NULL && thr_act->machine.pcb) {
372 *ip = (db_addr_t) thr_act->machine.pcb->save_srr0;
373 *fp = (struct db_ppc_frame *) (thr_act->machine.pcb->save_r1);
374 break;
375 }
376 /* falling down for unknown case */
377 default:
378 miss_frame:
379
380 if(!pmap_find_phys(kernel_pmap, (addr64_t)*fp)) { /* Check if this is valid */
381 db_printf("Frame not mapped %08X\n",*fp); /* Say not found */
382 *fp = 0; /* Show not found */
383 break; /* Out of here */
384 }
385
386 if ((*fp)->f_frame)
387 *ip = (db_addr_t)
388 db_get_task_value((int)&(*fp)->f_frame->f_retaddr,
389 4, FALSE, task);
390 else
391 *ip = (db_addr_t)
392 db_get_task_value((int)&(*fp)->f_retaddr,
393 4, FALSE, task);
394
395 *lfp = *fp;
396 *fp = (struct db_ppc_frame *)
397 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
398 break;
399 }
400 }
401
402 void
403 db_stack_trace_cmd(
404 db_expr_t addr,
405 boolean_t have_addr,
406 db_expr_t count,
407 char *modif)
408 {
409 struct db_ppc_frame *frame, *lastframe;
410 db_addr_t callpc, linkpc, lastcallpc;
411 int frame_type;
412 boolean_t kernel_only = TRUE;
413 boolean_t trace_thread = FALSE;
414 boolean_t trace_all_threads = FALSE;
415 int thcount = 0;
416 char *filename;
417 int linenum;
418 task_t task;
419 thread_act_t th, top_act;
420 int user_frame;
421 int frame_count;
422 jmp_buf_t *prev;
423 jmp_buf_t db_jmp_buf;
424 queue_entry_t act_list;
425
426 if (!db_trace_symbols_found)
427 db_find_trace_symbols();
428 {
429 register char *cp = modif;
430 register char c;
431
432 while ((c = *cp++) != 0) {
433 if (c == 't')
434 trace_thread = TRUE;
435 if (c == 'T') {
436 trace_all_threads = TRUE;
437 trace_thread = TRUE;
438 }
439 if (c == 'u')
440 kernel_only = FALSE;
441 }
442 }
443
444 if (trace_all_threads) {
445 if (!have_addr && !trace_thread) {
446 have_addr = TRUE;
447 trace_thread = TRUE;
448 act_list = &(current_task()->threads);
449 addr = (db_expr_t) queue_first(act_list);
450 }
451 else if (trace_thread) {
452 if (have_addr) {
453 if (!db_check_act_address_valid((thread_act_t)addr)) {
454 if (db_lookup_task((task_t)addr) == -1)
455 return;
456 act_list = &(((task_t)addr)->threads);
457 addr = (db_expr_t) queue_first(act_list);
458 }
459 else {
460 act_list = &(((thread_act_t)addr)->task->threads);
461 thcount = db_lookup_task_act(((thread_act_t)addr)->task,
462 (thread_act_t)addr);
463 }
464 }
465 else {
466 th = db_default_act;
467 if (th == THR_ACT_NULL)
468 th = current_thread();
469 if (th == THR_ACT_NULL) {
470 db_printf("no active thr_act\n");
471 return;
472 }
473 have_addr = TRUE;
474 act_list = &th->task->threads;
475 addr = (db_expr_t) queue_first(act_list);
476 }
477 }
478 }
479
480 if (count == -1)
481 count = 65535;
482
483 next_thread:
484 top_act = THR_ACT_NULL;
485
486 user_frame = 0;
487 frame_count = count;
488
489 if (!have_addr && !trace_thread) {
490 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
491 callpc = (db_addr_t)ddb_regs.save_srr0;
492 linkpc = (db_addr_t)ddb_regs.save_lr;
493 th = current_thread();
494 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
495 }
496 else if (trace_thread) {
497 if (have_addr) {
498 th = (thread_act_t) addr;
499 if (!db_check_act_address_valid(th))
500 return;
501 }
502 else {
503 th = db_default_act;
504 if (th == THR_ACT_NULL)
505 th = current_thread();
506 if (th == THR_ACT_NULL) {
507 db_printf("no active thread\n");
508 return;
509 }
510 }
511 if (trace_all_threads)
512 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
513 addr, thcount, th->task->thread_count);
514
515 next_activation:
516
517 user_frame = 0;
518
519 task = th->task;
520 if (th == current_thread()) {
521 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
522 callpc = (db_addr_t)ddb_regs.save_srr0;
523 linkpc = (db_addr_t)ddb_regs.save_lr;
524 }
525 else {
526 if (th->machine.pcb == 0) {
527 db_printf("thread has no pcb\n");
528 goto thread_done;
529 }
530 if (th->kernel_stack == 0) {
531 register struct savearea *pss =
532 th->machine.pcb;
533
534 db_printf("Continuation ");
535 db_task_printsym((db_expr_t)th->continuation,
536 DB_STGY_PROC, task);
537 db_printf("\n");
538 frame = (struct db_ppc_frame *) (pss->save_r1);
539 callpc = (db_addr_t) (pss->save_srr0);
540 linkpc = (db_addr_t) (pss->save_lr);
541 }
542 else {
543 int cpu;
544
545 for (cpu = 0; cpu < real_ncpus; cpu++) {
546 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
547 cpu_to_processor(cpu)->active_thread == th &&
548 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
549 break;
550 }
551 }
552 if (top_act != THR_ACT_NULL) {
553 /*
554 * Trying to get the backtrace of an activation
555 * which is not the top_most one in the RPC chain:
556 * use the activation's pcb.
557 */
558 struct savearea *pss;
559
560 pss = th->machine.pcb;
561 frame = (struct db_ppc_frame *) (pss->save_r1);
562 callpc = (db_addr_t) (pss->save_srr0);
563 linkpc = (db_addr_t) (pss->save_lr);
564 } else {
565 if (cpu == real_ncpus) {
566 register struct savearea *iks;
567 int r;
568
569 iks = th->machine.pcb;
570 prev = db_recover;
571 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
572 frame = (struct db_ppc_frame *) (iks->save_r1);
573 callpc = (db_addr_t) (iks->save_lr);
574 linkpc = 0;
575 } else {
576 /*
577 * The kernel stack has probably been
578 * paged out (swapped out activation).
579 */
580 db_recover = prev;
581 if (r == 2) /* 'q' from db_more() */
582 db_error(0);
583 db_printf("<kernel stack (0x%x) error "
584 "(probably swapped out)>\n",
585 iks);
586 goto next_act;
587 }
588 db_recover = prev;
589 } else {
590 db_printf(">>>>> active on cpu %d <<<<<\n",
591 cpu);
592 frame = (struct db_ppc_frame *)
593 (PerProcTable[cpu].ppe_vaddr->db_saved_state->save_r1);
594 callpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_srr0;
595 linkpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_lr;
596 }
597 }
598 }
599 }
600 } else {
601 frame = (struct db_ppc_frame *)addr;
602 th = (db_default_act)? db_default_act: current_thread();
603 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
604 if (frame->f_frame) {
605 callpc = (db_addr_t)db_get_task_value
606 ((int)&frame->f_frame->f_retaddr,
607 4, FALSE, (user_frame) ? task : 0);
608 callpc = callpc-sizeof(callpc);
609 } else
610 callpc =0;
611 linkpc = 0;
612 }
613
614 if (!INKERNELSTACK((unsigned)frame, th)) {
615 db_printf(">>>>> user space <<<<<\n");
616 if (kernel_only)
617 goto thread_done;
618 user_frame++;
619 }
620
621 lastframe = 0;
622 lastcallpc = (db_addr_t) 0;
623 while (frame_count-- && frame != 0) {
624 int narg = DB_NUMARGS_MAX;
625 int arg;
626 char * name;
627 db_expr_t offset;
628 db_addr_t call_func = 0;
629 int r;
630 db_addr_t off;
631
632 db_symbol_values(NULL,
633 db_search_task_symbol_and_line(
634 callpc, DB_STGY_XTRN, &offset, &filename,
635 &linenum, (user_frame) ? task : 0, &narg),
636 &name, (db_expr_t *)&call_func);
637 if ( name == NULL) {
638 db_find_task_sym_and_offset(callpc,
639 &name, &off, (user_frame) ? task : 0);
640 offset = (db_expr_t) off;
641 }
642
643 if (user_frame == 0) {
644 if (call_func &&
645 (call_func == db_user_trap_symbol_value ||
646 call_func == db_kernel_trap_symbol_value)) {
647 frame_type = TRAP;
648 narg = 1;
649 } else if (call_func &&
650 call_func == db_interrupt_symbol_value) {
651 frame_type = INTERRUPT;
652 goto next_frame;
653 } else if (call_func &&
654 call_func == db_syscall_symbol_value) {
655 frame_type = SYSCALL;
656 goto next_frame;
657 } else {
658 frame_type = 0;
659 prev = db_recover;
660 if ((r = _setjmp(db_recover = &db_jmp_buf))
661 == 0) {
662 if (narg < 0)
663 narg = db_numargs(frame,
664 (user_frame) ? task : 0);
665 db_recover = prev;
666 } else {
667 db_recover = prev;
668 goto next_act;
669 }
670 }
671 } else {
672 frame_type = 0;
673 prev = db_recover;
674 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
675 if (narg < 0)
676 narg = db_numargs(frame,
677 (user_frame) ? task : 0);
678 db_recover = prev;
679 } else {
680 db_recover = prev;
681 goto next_act;
682 }
683 }
684
685 if (name == 0 || offset > db_maxoff) {
686 db_printf("[%08X]0x%08X(", frame, callpc);
687 } else {
688 db_printf("[%08X]%s", frame, name);
689 if (offset)
690 db_printf("+%llx", offset);
691 db_printf("(");
692 };
693
694 narg = db_numargs(frame, (user_frame) ? task : 0);
695
696 for (arg =0; arg < narg; arg++) {
697 db_addr_t argp;
698 int value;
699 boolean_t found;
700
701 prev = db_recover;
702 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
703 found = FALSE;
704 if (lastframe)
705 found = db_find_arg(frame, lastframe->f_retaddr,
706 (user_frame) ? task : 0, arg, &argp);
707 if (found)
708 value = db_get_task_value(argp, 4, FALSE,
709 (user_frame) ? task : 0);
710 } else {
711 db_recover = prev;
712 if (r == 2) /* 'q' from db_more() */
713 db_error(0);
714 db_printf("... <stack error>)");
715 db_printf("\n");
716 goto next_act;
717 }
718 db_recover = prev;
719 if (found)
720 db_printf("%08X", value);
721 else
722 db_printf("??");
723 argp = argp + sizeof(argp);
724 if (arg < narg-1)
725 db_printf(",");
726 }
727 if (arg != narg)
728 db_printf("...");
729 db_printf(")");
730 db_printf("\n");
731
732 next_frame:
733 lastcallpc = callpc;
734 prev = db_recover;
735 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
736 db_nextframe(&lastframe, &frame, &callpc, frame_type,
737 (user_frame) ? th : THR_ACT_NULL, linkpc);
738 callpc = callpc-sizeof(callpc);
739 db_recover = prev;
740 } else {
741 db_recover = prev;
742 frame = 0;
743 }
744 linkpc = 0;
745
746 if (frame == 0) {
747 next_act:
748 /* end of chain */
749 break;
750 }
751 if (!INKERNELSTACK(lastframe, th) ||
752 !INKERNELSTACK((unsigned)frame, th))
753 user_frame++;
754 if (user_frame == 1) {
755 db_printf(">>>>> user space <<<<<\n");
756 if (kernel_only)
757 break;
758 }
759
760 if (frame <= lastframe) {
761 if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th))) continue;
762 db_printf("Bad frame pointer: 0x%x\n", frame);
763 break;
764 }
765 }
766
767 thread_done:
768 if (trace_all_threads) {
769 if (top_act != THR_ACT_NULL)
770 th = top_act;
771 th = (thread_act_t) queue_next(&th->task_threads);
772 if (! queue_end(act_list, (queue_entry_t) th)) {
773 db_printf("\n");
774 addr = (db_expr_t) th;
775 thcount++;
776 goto next_thread;
777
778 }
779 }
780 }