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