]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/db_trace.c
xnu-344.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 <machine/asm.h>
35 #include <machine/db_machdep.h>
36 #include <machine/setjmp.h>
37 #include <mach/machine.h>
38
39 #include <ddb/db_access.h>
40 #include <ddb/db_sym.h>
41 #include <ddb/db_variables.h>
42 #include <ddb/db_command.h>
43 #include <ddb/db_task_thread.h>
44 #include <ddb/db_output.h>
45
46 extern jmp_buf_t *db_recover;
47 extern struct savearea *saved_state[];
48
49 struct savearea ddb_null_kregs;
50
51 extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */
52
53 #define DB_NUMARGS_MAX 5
54
55
56 extern char FixedStackStart[], FixedStackEnd[];
57 #define INFIXEDSTACK(va) \
58 ((((vm_offset_t)(va)) >= (vm_offset_t)&FixedStackStart) && \
59 (((vm_offset_t)(va)) < ((vm_offset_t)&FixedStackEnd)))
60
61 #if 0
62
63 #define INKERNELSTACK(va, th) \
64 (th == THR_ACT_NULL || \
65 (((vm_offset_t)(va)) >= th->thread->kernel_stack && \
66 (((vm_offset_t)(va)) < th->thread->kernel_stack + \
67 KERNEL_STACK_SIZE)) || \
68 INFIXEDSTACK(va))
69 #else
70 #define INKERNELSTACK(va, th) 1
71
72 #endif
73
74 #ifdef __MACHO__
75 struct db_ppc_frame {
76 struct db_ppc_frame *f_frame;
77 int pad1;
78 db_addr_t f_retaddr;
79 int pad3;
80 int pad4;
81 int pad5;
82 db_addr_t f_arg[DB_NUMARGS_MAX];
83 };
84 #endif
85
86 #define TRAP 1
87 #define INTERRUPT 2
88 #define SYSCALL 3
89
90 db_addr_t db_user_trap_symbol_value = 0;
91 db_addr_t db_kernel_trap_symbol_value = 0;
92 db_addr_t db_interrupt_symbol_value = 0;
93 db_addr_t db_return_to_iret_symbol_value = 0;
94 db_addr_t db_syscall_symbol_value = 0;
95 boolean_t db_trace_symbols_found = FALSE;
96
97 extern int db_ppc_reg_value(
98 struct db_variable * vp,
99 db_expr_t * val,
100 int flag,
101 db_var_aux_param_t ap);
102 extern void db_find_trace_symbols(void);
103 extern int db_numargs(
104 struct db_ppc_frame *fp,
105 task_t task);
106 extern boolean_t db_find_arg(
107 struct db_ppc_frame *frame,
108 db_addr_t calleepc,
109 task_t task,
110 int narg,
111 db_addr_t *arg);
112 extern void db_nextframe(
113 struct db_ppc_frame **lfp,
114 struct db_ppc_frame **fp,
115 db_addr_t *ip,
116 int frame_type,
117 thread_act_t thr_act,
118 db_addr_t linkpc);
119 extern int _setjmp(
120 jmp_buf_t * jb);
121
122 /*
123 * Machine register set.
124 */
125 struct db_variable db_regs[] = {
126 /* XXX "pc" is an alias to "srr0"... */
127 { "pc", (int *)&ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
128 { "srr0", (int *)&ddb_regs.save_srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
129 { "srr1", (int *)&ddb_regs.save_srr1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
130 { "r0", (int *)&ddb_regs.save_r0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
131 { "r1", (int *)&ddb_regs.save_r1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
132 { "r2", (int *)&ddb_regs.save_r2, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
133 { "r3", (int *)&ddb_regs.save_r3, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
134 { "r4", (int *)&ddb_regs.save_r4, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
135 { "r5", (int *)&ddb_regs.save_r5, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
136 { "r6", (int *)&ddb_regs.save_r6, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
137 { "r7", (int *)&ddb_regs.save_r7, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
138 { "r8", (int *)&ddb_regs.save_r8, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
139 { "r9", (int *)&ddb_regs.save_r9, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
140 { "r10", (int *)&ddb_regs.save_r10, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
141 { "r11", (int *)&ddb_regs.save_r11, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
142 { "r12", (int *)&ddb_regs.save_r12, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
143 { "r13", (int *)&ddb_regs.save_r13, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
144 { "r14", (int *)&ddb_regs.save_r14, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
145 { "r15", (int *)&ddb_regs.save_r15, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
146 { "r16", (int *)&ddb_regs.save_r16, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
147 { "r17", (int *)&ddb_regs.save_r17, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
148 { "r18", (int *)&ddb_regs.save_r18, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
149 { "r19", (int *)&ddb_regs.save_r19, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
150 { "r20", (int *)&ddb_regs.save_r20, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
151 { "r21", (int *)&ddb_regs.save_r21, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
152 { "r22", (int *)&ddb_regs.save_r22, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
153 { "r23", (int *)&ddb_regs.save_r23, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
154 { "r24", (int *)&ddb_regs.save_r24, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
155 { "r25", (int *)&ddb_regs.save_r25, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
156 { "r26", (int *)&ddb_regs.save_r26, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
157 { "r27", (int *)&ddb_regs.save_r27, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
158 { "r28", (int *)&ddb_regs.save_r28, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
159 { "r29", (int *)&ddb_regs.save_r29, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
160 { "r30", (int *)&ddb_regs.save_r30, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
161 { "r31", (int *)&ddb_regs.save_r31, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
162 { "cr", (int *)&ddb_regs.save_cr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
163 { "xer", (int *)&ddb_regs.save_xer, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
164 { "lr", (int *)&ddb_regs.save_lr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
165 { "ctr", (int *)&ddb_regs.save_ctr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
166 };
167 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
168
169 int
170 db_ppc_reg_value(
171 struct db_variable *vp,
172 db_expr_t *valuep,
173 int flag,
174 db_var_aux_param_t ap)
175 {
176 int *dp = 0;
177 db_expr_t null_reg = 0;
178 register thread_act_t thr_act = ap->thr_act;
179 int cpu;
180
181 if (db_option(ap->modif, 'u')) {
182 if (thr_act == THR_ACT_NULL) {
183 if ((thr_act = current_act()) == THR_ACT_NULL)
184 db_error("no user registers\n");
185 }
186 if (thr_act == current_act()) {
187 if (IS_USER_TRAP((&ddb_regs)))
188 dp = vp->valuep;
189 else if (INFIXEDSTACK(ddb_regs.save_r1))
190 db_error("cannot get/set user registers in nested interrupt\n");
191 }
192 } else {
193 if (thr_act == THR_ACT_NULL || thr_act == current_act()) {
194 dp = vp->valuep;
195 } else {
196 if (thr_act->thread &&
197 !(thr_act->thread->state & TH_STACK_HANDOFF) &&
198 thr_act->thread->kernel_stack) {
199 int cpu;
200
201 for (cpu = 0; cpu < NCPUS; cpu++) {
202 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
203 cpu_to_processor(cpu)->cpu_data->active_thread == thr_act->thread && saved_state[cpu]) {
204 dp = (int *) (((int)saved_state[cpu]) +
205 (((int) vp->valuep) -
206 (int) &ddb_regs));
207 break;
208 }
209 }
210
211 if (dp == 0)
212 dp = &null_reg;
213 } else if (thr_act->thread &&
214 (thr_act->thread->state&TH_STACK_HANDOFF)){
215 /* only PC is valid */
216 if (vp->valuep == (int *) &ddb_regs.save_srr0) {
217 dp = (int *)(&thr_act->thread->continuation);
218 } else {
219 dp = &null_reg;
220 }
221 }
222 }
223 }
224 if (dp == 0) {
225 int cpu;
226
227 if (!db_option(ap->modif, 'u')) {
228 for (cpu = 0; cpu < NCPUS; cpu++) {
229 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
230 cpu_to_processor(cpu)->cpu_data->active_thread == thr_act->thread && saved_state[cpu]) {
231 dp = (int *) (((int)saved_state[cpu]) +
232 (((int) vp->valuep) -
233 (int) &ddb_regs));
234 break;
235 }
236 }
237 }
238 if (dp == 0) {
239 if (!thr_act || thr_act->mact.pcb == 0)
240 db_error("no pcb\n");
241 dp = (int *)((int)thr_act->mact.pcb +
242 ((int)vp->valuep - (int)&ddb_regs));
243 }
244 }
245 if (flag == DB_VAR_SET)
246 *dp = *valuep;
247 else
248 *valuep = *dp;
249 return(0);
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 XXX_BS
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->mact.pcb) {
370 *ip = (db_addr_t) thr_act->mact.pcb->save_srr0;
371 *fp = (struct db_ppc_frame *) (thr_act->mact.pcb->save_r1);
372 break;
373 }
374 /* falling down for unknown case */
375 default:
376 miss_frame:
377 if ((*fp)->f_frame)
378 *ip = (db_addr_t)
379 db_get_task_value((int)&(*fp)->f_frame->f_retaddr,
380 4, FALSE, task);
381 else
382 *ip = (db_addr_t)
383 db_get_task_value((int)&(*fp)->f_retaddr,
384 4, FALSE, task);
385
386 *lfp = *fp;
387 *fp = (struct db_ppc_frame *)
388 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
389 break;
390 }
391 }
392
393 void
394 db_stack_trace_cmd(
395 db_expr_t addr,
396 boolean_t have_addr,
397 db_expr_t count,
398 char *modif)
399 {
400 struct db_ppc_frame *frame, *lastframe;
401 db_addr_t callpc, linkpc, lastcallpc;
402 int frame_type;
403 boolean_t kernel_only = TRUE;
404 boolean_t trace_thread = FALSE;
405 boolean_t trace_all_threads = FALSE;
406 int thcount = 0;
407 char *filename;
408 int linenum;
409 task_t task;
410 thread_act_t th, top_act;
411 int user_frame;
412 int frame_count;
413 jmp_buf_t *prev;
414 jmp_buf_t db_jmp_buf;
415 queue_entry_t act_list;
416
417 if (!db_trace_symbols_found)
418 db_find_trace_symbols();
419 {
420 register char *cp = modif;
421 register char c;
422
423 while ((c = *cp++) != 0) {
424 if (c == 't')
425 trace_thread = TRUE;
426 if (c == 'T') {
427 trace_all_threads = TRUE;
428 trace_thread = TRUE;
429 }
430 if (c == 'u')
431 kernel_only = FALSE;
432 }
433 }
434
435 if (trace_all_threads) {
436 if (!have_addr && !trace_thread) {
437 have_addr = TRUE;
438 trace_thread = TRUE;
439 act_list = &(current_task()->thr_acts);
440 addr = (db_expr_t) queue_first(act_list);
441 }
442 else if (trace_thread) {
443 if (have_addr) {
444 if (!db_check_act_address_valid((thread_act_t)addr)) {
445 if (db_lookup_task((task_t)addr) == -1)
446 return;
447 act_list = &(((task_t)addr)->thr_acts);
448 addr = (db_expr_t) queue_first(act_list);
449 }
450 else {
451 act_list = &(((thread_act_t)addr)->task->thr_acts);
452 thcount = db_lookup_task_act(((thread_act_t)addr)->task,
453 (thread_act_t)addr);
454 }
455 }
456 else {
457 th = db_default_act;
458 if (th == THR_ACT_NULL)
459 th = current_act();
460 if (th == THR_ACT_NULL) {
461 db_printf("no active thr_act\n");
462 return;
463 }
464 have_addr = TRUE;
465 act_list = &th->task->thr_acts;
466 addr = (db_expr_t) queue_first(act_list);
467 }
468 }
469 }
470
471 if (count == -1)
472 count = 65535;
473
474 next_thread:
475 top_act = THR_ACT_NULL;
476
477 user_frame = 0;
478 frame_count = count;
479
480 if (!have_addr && !trace_thread) {
481 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
482 callpc = (db_addr_t)ddb_regs.save_srr0;
483 linkpc = (db_addr_t)ddb_regs.save_lr;
484 th = current_act();
485 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
486 }
487 else if (trace_thread) {
488 if (have_addr) {
489 th = (thread_act_t) addr;
490 if (!db_check_act_address_valid(th))
491 return;
492 }
493 else {
494 th = db_default_act;
495 if (th == THR_ACT_NULL)
496 th = current_act();
497 if (th == THR_ACT_NULL) {
498 db_printf("no active thread\n");
499 return;
500 }
501 }
502 if (trace_all_threads)
503 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
504 addr, thcount, th->task->thr_act_count);
505
506 next_activation:
507
508 user_frame = 0;
509
510 task = th->task;
511 if (th == current_act()) {
512 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
513 callpc = (db_addr_t)ddb_regs.save_srr0;
514 linkpc = (db_addr_t)ddb_regs.save_lr;
515 }
516 else {
517 if (th->mact.pcb == 0) {
518 db_printf("thread has no pcb\n");
519 goto thread_done;
520 }
521 if (!th->thread) {
522 register struct savearea *pss =
523 th->mact.pcb;
524
525 db_printf("thread has no shuttle\n");
526 goto thread_done;
527 }
528 else if ((th->thread->state & TH_STACK_HANDOFF) ||
529 th->thread->kernel_stack == 0) {
530 register struct savearea *pss =
531 th->mact.pcb;
532
533 db_printf("Continuation ");
534 db_task_printsym((db_expr_t)th->thread->continuation,
535 DB_STGY_PROC, task);
536 db_printf("\n");
537 frame = (struct db_ppc_frame *) (pss->save_r1);
538 callpc = (db_addr_t) (pss->save_srr0);
539 linkpc = (db_addr_t) (pss->save_lr);
540 }
541 else {
542 int cpu;
543
544 for (cpu = 0; cpu < NCPUS; cpu++) {
545 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
546 cpu_to_processor(cpu)->cpu_data->active_thread == th->thread &&
547 saved_state[cpu]) {
548 break;
549 }
550 }
551 if (top_act != THR_ACT_NULL) {
552 /*
553 * Trying to get the backtrace of an activation
554 * which is not the top_most one in the RPC chain:
555 * use the activation's pcb.
556 */
557 struct savearea *pss;
558
559 pss = th->mact.pcb;
560 frame = (struct db_ppc_frame *) (pss->save_r1);
561 callpc = (db_addr_t) (pss->save_srr0);
562 linkpc = (db_addr_t) (pss->save_lr);
563 } else {
564 if (cpu == NCPUS) {
565 register struct savearea *iks;
566 int r;
567
568 iks = th->mact.pcb;
569 prev = db_recover;
570 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
571 frame = (struct db_ppc_frame *) (iks->save_r1);
572 callpc = (db_addr_t) (iks->save_lr);
573 linkpc = 0;
574 } else {
575 /*
576 * The kernel stack has probably been
577 * paged out (swapped out activation).
578 */
579 db_recover = prev;
580 if (r == 2) /* 'q' from db_more() */
581 db_error(0);
582 db_printf("<kernel stack (0x%x) error "
583 "(probably swapped out)>\n",
584 iks);
585 goto next_act;
586 }
587 db_recover = prev;
588 } else {
589 db_printf(">>>>> active on cpu %d <<<<<\n",
590 cpu);
591 frame = (struct db_ppc_frame *)
592 (saved_state[cpu]->save_r1);
593 callpc = (db_addr_t) saved_state[cpu]->save_srr0;
594 linkpc = (db_addr_t) saved_state[cpu]->save_lr;
595 }
596 }
597 }
598 }
599 } else {
600 frame = (struct db_ppc_frame *)addr;
601 th = (db_default_act)? db_default_act: current_act();
602 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
603 if (frame->f_frame) {
604 callpc = (db_addr_t)db_get_task_value
605 ((int)&frame->f_frame->f_retaddr,
606 4, FALSE, (user_frame) ? task : 0);
607 callpc = callpc-sizeof(callpc);
608 } else
609 callpc =0;
610 linkpc = 0;
611 }
612
613 if (!INKERNELSTACK((unsigned)frame, th)) {
614 db_printf(">>>>> user space <<<<<\n");
615 if (kernel_only)
616 goto thread_done;
617 user_frame++;
618 }
619
620 lastframe = 0;
621 lastcallpc = (db_addr_t) 0;
622 while (frame_count-- && frame != 0) {
623 int narg = DB_NUMARGS_MAX;
624 int arg;
625 char * name;
626 db_expr_t offset;
627 db_addr_t call_func = 0;
628 int r;
629 db_addr_t off;
630
631 db_symbol_values(NULL,
632 db_search_task_symbol_and_line(
633 callpc, DB_STGY_XTRN, &offset, &filename,
634 &linenum, (user_frame) ? task : 0, &narg),
635 &name, (db_expr_t *)&call_func);
636 if ( name == NULL) {
637 db_find_task_sym_and_offset(callpc,
638 &name, &off, (user_frame) ? task : 0);
639 offset = (db_expr_t) off;
640 }
641
642 if (user_frame == 0) {
643 if (call_func &&
644 (call_func == db_user_trap_symbol_value ||
645 call_func == db_kernel_trap_symbol_value)) {
646 frame_type = TRAP;
647 narg = 1;
648 } else if (call_func &&
649 call_func == db_interrupt_symbol_value) {
650 frame_type = INTERRUPT;
651 goto next_frame;
652 } else if (call_func &&
653 call_func == db_syscall_symbol_value) {
654 frame_type = SYSCALL;
655 goto next_frame;
656 } else {
657 frame_type = 0;
658 prev = db_recover;
659 if ((r = _setjmp(db_recover = &db_jmp_buf))
660 == 0) {
661 if (narg < 0)
662 narg = db_numargs(frame,
663 (user_frame) ? task : 0);
664 db_recover = prev;
665 } else {
666 db_recover = prev;
667 goto next_act;
668 }
669 }
670 } else {
671 frame_type = 0;
672 prev = db_recover;
673 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
674 if (narg < 0)
675 narg = db_numargs(frame,
676 (user_frame) ? task : 0);
677 db_recover = prev;
678 } else {
679 db_recover = prev;
680 goto next_act;
681 }
682 }
683
684 if (name == 0 || offset > db_maxoff) {
685 db_printf("[%08X]0x%08X(", frame, callpc);
686 } else {
687 db_printf("[%08X]%s", frame, name);
688 if (offset)
689 db_printf("+%x", offset);
690 db_printf("(");
691 };
692
693 narg = db_numargs(frame, (user_frame) ? task : 0);
694
695 for (arg =0; arg < narg; arg++) {
696 db_addr_t argp;
697 int value;
698 boolean_t found;
699
700 prev = db_recover;
701 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
702 found = FALSE;
703 if (lastframe)
704 found = db_find_arg(frame, lastframe->f_retaddr,
705 (user_frame) ? task : 0, arg, &argp);
706 if (found)
707 value = db_get_task_value(argp, 4, FALSE,
708 (user_frame) ? task : 0);
709 } else {
710 db_recover = prev;
711 if (r == 2) /* 'q' from db_more() */
712 db_error(0);
713 db_printf("... <stack error>)");
714 db_printf("\n");
715 goto next_act;
716 }
717 db_recover = prev;
718 if (found)
719 db_printf("%08X", value);
720 else
721 db_printf("??");
722 argp = argp + sizeof(argp);
723 if (arg < narg-1)
724 db_printf(",");
725 }
726 if (arg != narg)
727 db_printf("...");
728 db_printf(")");
729 db_printf("\n");
730
731 next_frame:
732 lastcallpc = callpc;
733 prev = db_recover;
734 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
735 db_nextframe(&lastframe, &frame, &callpc, frame_type,
736 (user_frame) ? th : THR_ACT_NULL, linkpc);
737 callpc = callpc-sizeof(callpc);
738 db_recover = prev;
739 } else {
740 db_recover = prev;
741 frame = 0;
742 }
743 linkpc = 0;
744
745 if (frame == 0) {
746 next_act:
747 if (th->lower != THR_ACT_NULL) {
748 if (top_act == THR_ACT_NULL)
749 top_act = th;
750 th = th->lower;
751 db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
752 th,
753 db_lookup_task(th->task),
754 db_lookup_task_act(th->task, th));
755 goto next_activation;
756 }
757 /* end of chain */
758 break;
759 }
760 if (!INKERNELSTACK(lastframe, th) ||
761 !INKERNELSTACK((unsigned)frame, th))
762 user_frame++;
763 if (user_frame == 1) {
764 db_printf(">>>>> user space <<<<<\n");
765 if (kernel_only)
766 break;
767 }
768
769 if (frame <= lastframe) {
770 if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th))) continue;
771 db_printf("Bad frame pointer: 0x%x\n", frame);
772 break;
773 }
774 }
775
776 thread_done:
777 if (trace_all_threads) {
778 if (top_act != THR_ACT_NULL)
779 th = top_act;
780 th = (thread_act_t) queue_next(&th->thr_acts);
781 if (! queue_end(act_list, (queue_entry_t) th)) {
782 db_printf("\n");
783 addr = (db_expr_t) th;
784 thcount++;
785 goto next_thread;
786
787 }
788 }
789 }