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