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