]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/db_trace.c
xnu-1228.tar.gz
[apple/xnu.git] / osfmk / ppc / db_trace.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31
32#include <string.h>
33
34#include <mach/boolean.h>
2d21ac55
A
35#include <mach/machine.h>
36
1c79356b 37#include <vm/vm_map.h>
2d21ac55 38
1c79356b 39#include <kern/thread.h>
9bccf70c 40#include <kern/processor.h>
1c79356b
A
41#include <kern/task.h>
42
91447636
A
43#include <ppc/cpu_internal.h>
44#include <ppc/exception.h>
2d21ac55 45
1c79356b
A
46#include <machine/asm.h>
47#include <machine/db_machdep.h>
48#include <machine/setjmp.h>
1c79356b
A
49
50#include <ddb/db_access.h>
51#include <ddb/db_sym.h>
52#include <ddb/db_variables.h>
53#include <ddb/db_command.h>
54#include <ddb/db_task_thread.h>
55#include <ddb/db_output.h>
56
57extern jmp_buf_t *db_recover;
1c79356b 58
9bccf70c 59struct savearea ddb_null_kregs;
1c79356b
A
60
61extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */
62
63#define DB_NUMARGS_MAX 5
64
91447636 65#define INFIXEDSTACK(va) 0 \
1c79356b 66
1c79356b
A
67#define INKERNELSTACK(va, th) 1
68
1c79356b
A
69struct db_ppc_frame {
70 struct db_ppc_frame *f_frame;
71 int pad1;
55e303ae 72 uint32_t f_retaddr;
1c79356b
A
73 int pad3;
74 int pad4;
75 int pad5;
55e303ae 76 uint32_t f_arg[DB_NUMARGS_MAX];
1c79356b 77};
1c79356b
A
78
79#define TRAP 1
80#define INTERRUPT 2
81#define SYSCALL 3
82
83db_addr_t db_user_trap_symbol_value = 0;
84db_addr_t db_kernel_trap_symbol_value = 0;
85db_addr_t db_interrupt_symbol_value = 0;
86db_addr_t db_return_to_iret_symbol_value = 0;
87db_addr_t db_syscall_symbol_value = 0;
88boolean_t db_trace_symbols_found = FALSE;
89
2d21ac55 90static int db_ppc_reg_value(
1c79356b
A
91 struct db_variable * vp,
92 db_expr_t * val,
93 int flag,
94 db_var_aux_param_t ap);
2d21ac55
A
95static void db_find_trace_symbols(void);
96static int db_numargs(
1c79356b
A
97 struct db_ppc_frame *fp,
98 task_t task);
2d21ac55 99static boolean_t db_find_arg(
1c79356b
A
100 struct db_ppc_frame *frame,
101 db_addr_t calleepc,
102 task_t task,
103 int narg,
104 db_addr_t *arg);
2d21ac55 105static void db_nextframe(
1c79356b
A
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);
1c79356b
A
112
113/*
114 * Machine register set.
115 */
116struct db_variable db_regs[] = {
117 /* XXX "pc" is an alias to "srr0"... */
2d21ac55
A
118 {
119 .name = "pc",
120 .valuep = &ddb_regs.save_srr0,
121 .fcn = db_ppc_reg_value,
122 .min_level = 0,
123 .max_level = 0,
124 .low = 0,
125 .high = 0,
126 .hidden_level = TRUE,
127 },
128 {
129 .name = "srr0",
130 .valuep = &ddb_regs.save_srr0,
131 .fcn = db_ppc_reg_value,
132 .min_level = 0,
133 .max_level = 0,
134 .low = 0,
135 .high = 0,
136 .hidden_level = TRUE,
137 },
138 {
139 .name = "srr1",
140 .valuep = &ddb_regs.save_srr1,
141 .fcn = db_ppc_reg_value,
142 .min_level = 0,
143 .max_level = 0,
144 .low = 0,
145 .high = 0,
146 .hidden_level = TRUE,
147 },
148 {
149 .name = "r0",
150 .valuep = &ddb_regs.save_r0,
151 .fcn = db_ppc_reg_value,
152 .min_level = 0,
153 .max_level = 0,
154 .low = 0,
155 .high = 0,
156 .hidden_level = TRUE,
157 },
158 {
159 .name = "r1",
160 .valuep = &ddb_regs.save_r1,
161 .fcn = db_ppc_reg_value,
162 .min_level = 0,
163 .max_level = 0,
164 .low = 0,
165 .high = 0,
166 .hidden_level = TRUE,
167 },
168 {
169 .name = "r2",
170 .valuep = &ddb_regs.save_r2,
171 .fcn = db_ppc_reg_value,
172 .min_level = 0,
173 .max_level = 0,
174 .low = 0,
175 .high = 0,
176 .hidden_level = TRUE,
177 },
178 {
179 .name = "r3",
180 .valuep = &ddb_regs.save_r3,
181 .fcn = db_ppc_reg_value,
182 .min_level = 0,
183 .max_level = 0,
184 .low = 0,
185 .high = 0,
186 .hidden_level = TRUE,
187 },
188 {
189 .name = "r4",
190 .valuep = &ddb_regs.save_r4,
191 .fcn = db_ppc_reg_value,
192 .min_level = 0,
193 .max_level = 0,
194 .low = 0,
195 .high = 0,
196 .hidden_level = TRUE,
197 },
198 {
199 .name = "r5",
200 .valuep = &ddb_regs.save_r5,
201 .fcn = db_ppc_reg_value,
202 .min_level = 0,
203 .max_level = 0,
204 .low = 0,
205 .high = 0,
206 .hidden_level = TRUE,
207 },
208 {
209 .name = "r6",
210 .valuep = &ddb_regs.save_r6,
211 .fcn = db_ppc_reg_value,
212 .min_level = 0,
213 .max_level = 0,
214 .low = 0,
215 .high = 0,
216 .hidden_level = TRUE,
217 },
218 {
219 .name = "r7",
220 .valuep = &ddb_regs.save_r7,
221 .fcn = db_ppc_reg_value,
222 .min_level = 0,
223 .max_level = 0,
224 .low = 0,
225 .high = 0,
226 .hidden_level = TRUE,
227 },
228 {
229 .name = "r8",
230 .valuep = &ddb_regs.save_r8,
231 .fcn = db_ppc_reg_value,
232 .min_level = 0,
233 .max_level = 0,
234 .low = 0,
235 .high = 0,
236 .hidden_level = TRUE,
237 },
238 {
239 .name = "r9",
240 .valuep = &ddb_regs.save_r9,
241 .fcn = db_ppc_reg_value,
242 .min_level = 0,
243 .max_level = 0,
244 .low = 0,
245 .high = 0,
246 .hidden_level = TRUE,
247 },
248 {
249 .name = "r10",
250 .valuep = &ddb_regs.save_r10,
251 .fcn = db_ppc_reg_value,
252 .min_level = 0,
253 .max_level = 0,
254 .low = 0,
255 .high = 0,
256 .hidden_level = TRUE,
257 },
258 {
259 .name = "r11",
260 .valuep = &ddb_regs.save_r11,
261 .fcn = db_ppc_reg_value,
262 .min_level = 0,
263 .max_level = 0,
264 .low = 0,
265 .high = 0,
266 .hidden_level = TRUE,
267 },
268 {
269 .name = "r12",
270 .valuep = &ddb_regs.save_r12,
271 .fcn = db_ppc_reg_value,
272 .min_level = 0,
273 .max_level = 0,
274 .low = 0,
275 .high = 0,
276 .hidden_level = TRUE,
277 },
278 {
279 .name = "r13",
280 .valuep = &ddb_regs.save_r13,
281 .fcn = db_ppc_reg_value,
282 .min_level = 0,
283 .max_level = 0,
284 .low = 0,
285 .high = 0,
286 .hidden_level = TRUE,
287 },
288 {
289 .name = "r14",
290 .valuep = &ddb_regs.save_r14,
291 .fcn = db_ppc_reg_value,
292 .min_level = 0,
293 .max_level = 0,
294 .low = 0,
295 .high = 0,
296 .hidden_level = TRUE,
297 },
298 {
299 .name = "r15",
300 .valuep = &ddb_regs.save_r15,
301 .fcn = db_ppc_reg_value,
302 .min_level = 0,
303 .max_level = 0,
304 .low = 0,
305 .high = 0,
306 .hidden_level = TRUE,
307 },
308 {
309 .name = "r16",
310 .valuep = &ddb_regs.save_r16,
311 .fcn = db_ppc_reg_value,
312 .min_level = 0,
313 .max_level = 0,
314 .low = 0,
315 .high = 0,
316 .hidden_level = TRUE,
317 },
318 {
319 .name = "r17",
320 .valuep = &ddb_regs.save_r17,
321 .fcn = db_ppc_reg_value,
322 .min_level = 0,
323 .max_level = 0,
324 .low = 0,
325 .high = 0,
326 .hidden_level = TRUE,
327 },
328 {
329 .name = "r18",
330 .valuep = &ddb_regs.save_r18,
331 .fcn = db_ppc_reg_value,
332 .min_level = 0,
333 .max_level = 0,
334 .low = 0,
335 .high = 0,
336 .hidden_level = TRUE,
337 },
338 {
339 .name = "r19",
340 .valuep = &ddb_regs.save_r19,
341 .fcn = db_ppc_reg_value,
342 .min_level = 0,
343 .max_level = 0,
344 .low = 0,
345 .high = 0,
346 .hidden_level = TRUE,
347 },
348 {
349 .name = "r20",
350 .valuep = &ddb_regs.save_r20,
351 .fcn = db_ppc_reg_value,
352 .min_level = 0,
353 .max_level = 0,
354 .low = 0,
355 .high = 0,
356 .hidden_level = TRUE,
357 },
358 {
359 .name = "r21",
360 .valuep = &ddb_regs.save_r21,
361 .fcn = db_ppc_reg_value,
362 .min_level = 0,
363 .max_level = 0,
364 .low = 0,
365 .high = 0,
366 .hidden_level = TRUE,
367 },
368 {
369 .name = "r22",
370 .valuep = &ddb_regs.save_r22,
371 .fcn = db_ppc_reg_value,
372 .min_level = 0,
373 .max_level = 0,
374 .low = 0,
375 .high = 0,
376 .hidden_level = TRUE,
377 },
378 {
379 .name = "r23",
380 .valuep = &ddb_regs.save_r23,
381 .fcn = db_ppc_reg_value,
382 .min_level = 0,
383 .max_level = 0,
384 .low = 0,
385 .high = 0,
386 .hidden_level = TRUE,
387 },
388 {
389 .name = "r24",
390 .valuep = &ddb_regs.save_r24,
391 .fcn = db_ppc_reg_value,
392 .min_level = 0,
393 .max_level = 0,
394 .low = 0,
395 .high = 0,
396 .hidden_level = TRUE,
397 },
398 {
399 .name = "r25",
400 .valuep = &ddb_regs.save_r25,
401 .fcn = db_ppc_reg_value,
402 .min_level = 0,
403 .max_level = 0,
404 .low = 0,
405 .high = 0,
406 .hidden_level = TRUE,
407 },
408 {
409 .name = "r26",
410 .valuep = &ddb_regs.save_r26,
411 .fcn = db_ppc_reg_value,
412 .min_level = 0,
413 .max_level = 0,
414 .low = 0,
415 .high = 0,
416 .hidden_level = TRUE,
417 },
418 {
419 .name = "r27",
420 .valuep = &ddb_regs.save_r27,
421 .fcn = db_ppc_reg_value,
422 .min_level = 0,
423 .max_level = 0,
424 .low = 0,
425 .high = 0,
426 .hidden_level = TRUE,
427 },
428 {
429 .name = "r28",
430 .valuep = &ddb_regs.save_r28,
431 .fcn = db_ppc_reg_value,
432 .min_level = 0,
433 .max_level = 0,
434 .low = 0,
435 .high = 0,
436 .hidden_level = TRUE,
437 },
438 {
439 .name = "r29",
440 .valuep = &ddb_regs.save_r29,
441 .fcn = db_ppc_reg_value,
442 .min_level = 0,
443 .max_level = 0,
444 .low = 0,
445 .high = 0,
446 .hidden_level = TRUE,
447 },
448 {
449 .name = "r30",
450 .valuep = &ddb_regs.save_r30,
451 .fcn = db_ppc_reg_value,
452 .min_level = 0,
453 .max_level = 0,
454 .low = 0,
455 .high = 0,
456 .hidden_level = TRUE,
457 },
458 {
459 .name = "r31",
460 .valuep = &ddb_regs.save_r31,
461 .fcn = db_ppc_reg_value,
462 .min_level = 0,
463 .max_level = 0,
464 .low = 0,
465 .high = 0,
466 .hidden_level = TRUE,
467 },
468 {
469 .name = "cr",
470 .valuep = (db_expr_t *)&ddb_regs.save_cr,
471 .fcn = db_ppc_reg_value,
472 .min_level = 0,
473 .max_level = 0,
474 .low = 0,
475 .high = 0,
476 .hidden_level = TRUE,
477 },
478 {
479 .name = "xer",
480 .valuep = &ddb_regs.save_xer,
481 .fcn = db_ppc_reg_value,
482 .min_level = 0,
483 .max_level = 0,
484 .low = 0,
485 .high = 0,
486 .hidden_level = TRUE,
487 },
488 {
489 .name = "lr",
490 .valuep = &ddb_regs.save_lr,
491 .fcn = db_ppc_reg_value,
492 .min_level = 0,
493 .max_level = 0,
494 .low = 0,
495 .high = 0,
496 .hidden_level = TRUE,
497 },
498 {
499 .name = "ctr",
500 .valuep = &ddb_regs.save_ctr,
501 .fcn = db_ppc_reg_value,
502 .min_level = 0,
503 .max_level = 0,
504 .low = 0,
505 .high = 0,
506 .hidden_level = TRUE,
507 },
1c79356b
A
508};
509struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
510
511int
512db_ppc_reg_value(
513 struct db_variable *vp,
514 db_expr_t *valuep,
515 int flag,
516 db_var_aux_param_t ap)
517{
55e303ae
A
518 db_expr_t *dp = 0;
519 db_expr_t null_reg = 0;
520 uint32_t *dp32;
2d21ac55
A
521 thread_act_t thr_act = ap->thr_act;
522 unsigned int cpu;
1c79356b
A
523
524 if (db_option(ap->modif, 'u')) {
2d21ac55
A
525 if (thr_act == THR_ACT_NULL) {
526 if ((thr_act = current_thread()) == THR_ACT_NULL)
527 db_error("no user registers\n");
528 }
529 if (thr_act == current_thread()) {
55e303ae
A
530 if (IS_USER_TRAP((&ddb_regs))) dp = vp->valuep;
531 else if (INFIXEDSTACK(ddb_regs.save_r1))
532 db_error("cannot get/set user registers in nested interrupt\n");
2d21ac55 533 }
55e303ae
A
534 }
535 else {
91447636 536 if (thr_act == THR_ACT_NULL || thr_act == current_thread()) {
55e303ae
A
537 dp = vp->valuep;
538 }
539 else {
91447636 540 if (thr_act->kernel_stack) {
91447636 541 for (cpu = 0; cpu < real_ncpus; cpu++) {
55e303ae 542 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
2d21ac55
A
543 cpu_to_processor(cpu)->active_thread == thr_act &&
544 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
545
91447636 546 dp = (db_expr_t)(((uint32_t)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
2d21ac55
A
547 (((uint32_t) vp->valuep) -
548 (uint32_t) &ddb_regs));
55e303ae
A
549 break;
550 }
551 }
552
2d21ac55
A
553 if (dp == 0)
554 dp = &null_reg;
55e303ae 555 }
91447636 556 else {
55e303ae 557 /* only PC is valid */
2d21ac55
A
558 if (vp->valuep == &ddb_regs.save_srr0)
559 dp = (db_expr_t *)&thr_act->continuation;
560 else
55e303ae 561 dp = &null_reg;
55e303ae 562 }
2d21ac55 563 }
1c79356b
A
564 }
565 if (dp == 0) {
2d21ac55 566 if (!db_option(ap->modif, 'u')) {
91447636 567 for (cpu = 0; cpu < real_ncpus; cpu++) {
2d21ac55
A
568 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
569 cpu_to_processor(cpu)->active_thread == thr_act &&
570 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
571 dp = (int *) (((int)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
572 (((int) vp->valuep) - (int) &ddb_regs));
55e303ae
A
573 break;
574 }
575 }
2d21ac55
A
576 }
577 if (dp == 0) {
578 if (!thr_act || thr_act->machine.pcb == 0)
579 db_error("no pcb\n");
91447636 580 dp = (int *)((int)thr_act->machine.pcb + ((int)vp->valuep - (int)&ddb_regs));
2d21ac55 581 }
1c79356b 582 }
55e303ae 583
2d21ac55 584 if(vp->valuep == (db_expr_t *)&ddb_regs.save_cr) { /* Is this the CR we are doing? */
55e303ae 585 dp32 = (uint32_t *)dp; /* Make this easier */
2d21ac55
A
586 if (flag == DB_VAR_SET)
587 *dp32 = *valuep;
588 else
589 *valuep = *dp32;
55e303ae
A
590 }
591 else { /* Normal 64-bit registers */
2d21ac55
A
592 if (flag == DB_VAR_SET)
593 *dp = *valuep;
594 else
595 *valuep = *(unsigned long long *)dp;
55e303ae 596 }
2d21ac55
A
597
598 return 0;
1c79356b
A
599}
600
55e303ae 601
1c79356b
A
602void
603db_find_trace_symbols(void)
604{
605 db_expr_t value;
606 boolean_t found_some;
607
608 found_some = FALSE;
609 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
2d21ac55
A
610 db_user_trap_symbol_value = (db_addr_t) value;
611 found_some = TRUE;
1c79356b
A
612 }
613 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
2d21ac55
A
614 db_kernel_trap_symbol_value = (db_addr_t) value;
615 found_some = TRUE;
1c79356b
A
616 }
617 if (db_value_of_name(CC_SYM_PREFIX "ihandler", &value)) {
2d21ac55
A
618 db_interrupt_symbol_value = (db_addr_t) value;
619 found_some = TRUE;
1c79356b
A
620 }
621#if 0
622 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
2d21ac55
A
623 db_return_to_iret_symbol_value = (db_addr_t) value;
624 found_some = TRUE;
1c79356b
A
625 }
626#endif
627 if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
2d21ac55
A
628 db_syscall_symbol_value = (db_addr_t) value;
629 found_some = TRUE;
1c79356b
A
630 }
631 if (found_some)
2d21ac55 632 db_trace_symbols_found = TRUE;
1c79356b
A
633}
634
635int
636db_numargs(
637 struct db_ppc_frame *fp,
638 task_t task)
639{
2d21ac55 640 return DB_NUMARGS_MAX;
1c79356b
A
641}
642
643boolean_t
644db_find_arg(
645 struct db_ppc_frame *fp,
646 db_addr_t calleepc,
647 task_t task,
648 int narg,
649 db_addr_t *arg)
650{
651 db_addr_t argp;
652 db_addr_t calleep;
653 db_addr_t offset;
654 int i;
655 int inst;
656 char *name;
657
91447636 658#if 0
1c79356b
A
659 db_find_task_sym_and_offset(calleepc, &name, &offset, task);
660 calleep = calleepc-offset;
661
662 for (i = 0; calleep < calleepc; i++, calleep++) {
663 if (!DB_CHECK_ACCESS((int) calleep, 4, task)) {
664 continue;
665 }
666 inst = db_get_task_value(calleep, 4, FALSE, task);
667 if ((inst & 0xffff0000) == (0x907f0000 + (narg << 21)) ||
2d21ac55 668 (inst & 0xffff0000) == (0x90610000 + (narg << 21))) {
1c79356b
A
669 argp = (db_addr_t) &(fp->f_arg[narg]);
670 *arg = argp;
671 return TRUE;
672 }
673 }
674#endif
675 return FALSE;
676}
677
2d21ac55 678extern int TRAP_TYPES;
1c79356b
A
679/*
680 * Figure out the next frame up in the call stack.
681 * For trap(), we print the address of the faulting instruction and
682 * proceed with the calling frame. We return the ip that faulted.
683 * If the trap was caused by jumping through a bogus pointer, then
684 * the next line in the backtrace will list some random function as
685 * being called. It should get the argument list correct, though.
686 * It might be possible to dig out from the next frame up the name
687 * of the function that faulted, but that could get hairy.
688 */
689void
690db_nextframe(
691 struct db_ppc_frame **lfp, /* in/out */
692 struct db_ppc_frame **fp, /* in/out */
693 db_addr_t *ip, /* out */
694 int frame_type, /* in */
695 thread_act_t thr_act,
696 db_addr_t linkpc) /* in */
697{
9bccf70c 698 struct savearea *saved_regs;
1c79356b
A
699
700 task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL;
701
702 switch(frame_type) {
703 case TRAP:
2d21ac55
A
704 db_printf(">>>>> trap <<<<<\n");
705 goto miss_frame;
706 break;
1c79356b 707 case INTERRUPT:
2d21ac55
A
708 if (*lfp == 0) {
709 db_printf(">>>>> interrupt <<<<<\n");
710 goto miss_frame;
711 }
1c79356b
A
712 db_printf(">>>>> interrupt <<<<<\n");
713 goto miss_frame;
1c79356b 714 break;
2d21ac55
A
715 case SYSCALL:
716 if (thr_act != THR_ACT_NULL && thr_act->machine.pcb) {
717 *ip = (db_addr_t) thr_act->machine.pcb->save_srr0;
718 *fp = (struct db_ppc_frame *) (thr_act->machine.pcb->save_r1);
719 break;
720 }
721 /* falling down for unknown case */
1c79356b 722 default:
2d21ac55 723miss_frame:
55e303ae
A
724 if(!pmap_find_phys(kernel_pmap, (addr64_t)*fp)) { /* Check if this is valid */
725 db_printf("Frame not mapped %08X\n",*fp); /* Say not found */
726 *fp = 0; /* Show not found */
727 break; /* Out of here */
728 }
2d21ac55 729
1c79356b 730 if ((*fp)->f_frame)
2d21ac55
A
731 *ip = (db_addr_t)
732 db_get_task_value((int)&(*fp)->f_frame->f_retaddr,
733 4, FALSE, task);
1c79356b
A
734 else
735 *ip = (db_addr_t)
2d21ac55
A
736 db_get_task_value((int)&(*fp)->f_retaddr,
737 4, FALSE, task);
1c79356b 738
2d21ac55
A
739 *lfp = *fp;
740 *fp = (struct db_ppc_frame *)
741 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
742 break;
1c79356b
A
743 }
744}
745
746void
747db_stack_trace_cmd(
748 db_expr_t addr,
749 boolean_t have_addr,
750 db_expr_t count,
751 char *modif)
752{
753 struct db_ppc_frame *frame, *lastframe;
754 db_addr_t callpc, linkpc, lastcallpc;
755 int frame_type;
756 boolean_t kernel_only = TRUE;
757 boolean_t trace_thread = FALSE;
758 boolean_t trace_all_threads = FALSE;
759 int thcount = 0;
760 char *filename;
761 int linenum;
762 task_t task;
763 thread_act_t th, top_act;
764 int user_frame;
765 int frame_count;
766 jmp_buf_t *prev;
767 jmp_buf_t db_jmp_buf;
768 queue_entry_t act_list;
769
770 if (!db_trace_symbols_found)
2d21ac55 771 db_find_trace_symbols();
1c79356b 772 {
2d21ac55
A
773 char *cp = modif;
774 char c;
1c79356b
A
775
776 while ((c = *cp++) != 0) {
777 if (c == 't')
778 trace_thread = TRUE;
779 if (c == 'T') {
780 trace_all_threads = TRUE;
781 trace_thread = TRUE;
782 }
783 if (c == 'u')
784 kernel_only = FALSE;
785 }
786 }
787
788 if (trace_all_threads) {
2d21ac55 789 if (!have_addr && !trace_thread) {
1c79356b
A
790 have_addr = TRUE;
791 trace_thread = TRUE;
55e303ae 792 act_list = &(current_task()->threads);
1c79356b 793 addr = (db_expr_t) queue_first(act_list);
2d21ac55 794 }
1c79356b
A
795 else if (trace_thread) {
796 if (have_addr) {
797 if (!db_check_act_address_valid((thread_act_t)addr)) {
798 if (db_lookup_task((task_t)addr) == -1)
799 return;
55e303ae 800 act_list = &(((task_t)addr)->threads);
1c79356b
A
801 addr = (db_expr_t) queue_first(act_list);
802 }
803 else {
55e303ae 804 act_list = &(((thread_act_t)addr)->task->threads);
1c79356b 805 thcount = db_lookup_task_act(((thread_act_t)addr)->task,
2d21ac55 806 (thread_act_t)addr);
1c79356b
A
807 }
808 }
809 else {
810 th = db_default_act;
811 if (th == THR_ACT_NULL)
91447636 812 th = current_thread();
1c79356b
A
813 if (th == THR_ACT_NULL) {
814 db_printf("no active thr_act\n");
815 return;
816 }
817 have_addr = TRUE;
55e303ae 818 act_list = &th->task->threads;
1c79356b
A
819 addr = (db_expr_t) queue_first(act_list);
820 }
2d21ac55 821 }
1c79356b
A
822 }
823
824 if (count == -1)
2d21ac55 825 count = 65535;
1c79356b
A
826
827next_thread:
828 top_act = THR_ACT_NULL;
829
830 user_frame = 0;
831 frame_count = count;
832
833 if (!have_addr && !trace_thread) {
2d21ac55
A
834 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
835 callpc = (db_addr_t)ddb_regs.save_srr0;
836 linkpc = (db_addr_t)ddb_regs.save_lr;
837 th = current_thread();
838 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
1c79356b
A
839 }
840 else if (trace_thread) {
2d21ac55 841 if (have_addr) {
1c79356b
A
842 th = (thread_act_t) addr;
843 if (!db_check_act_address_valid(th))
2d21ac55
A
844 return;
845 }
1c79356b
A
846 else {
847 th = db_default_act;
848 if (th == THR_ACT_NULL)
2d21ac55 849 th = current_thread();
1c79356b 850 if (th == THR_ACT_NULL) {
2d21ac55
A
851 db_printf("no active thread\n");
852 return;
1c79356b 853 }
2d21ac55
A
854 }
855 if (trace_all_threads)
856 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
857 addr, thcount, th->task->thread_count);
1c79356b
A
858
859next_activation:
2d21ac55 860 user_frame = 0;
1c79356b 861
2d21ac55
A
862 task = th->task;
863 if (th == current_thread()) {
864 frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
865 callpc = (db_addr_t)ddb_regs.save_srr0;
9bccf70c 866 linkpc = (db_addr_t)ddb_regs.save_lr;
2d21ac55 867 }
1c79356b 868 else {
91447636 869 if (th->machine.pcb == 0) {
2d21ac55 870 db_printf("thread has no pcb\n");
1c79356b
A
871 goto thread_done;
872 }
91447636 873 if (th->kernel_stack == 0) {
2d21ac55
A
874 struct savearea *pss = th->machine.pcb;
875
1c79356b 876 db_printf("Continuation ");
91447636 877 db_task_printsym((db_expr_t)th->continuation,
2d21ac55 878 DB_STGY_PROC, task);
1c79356b 879 db_printf("\n");
9bccf70c
A
880 frame = (struct db_ppc_frame *) (pss->save_r1);
881 callpc = (db_addr_t) (pss->save_srr0);
882 linkpc = (db_addr_t) (pss->save_lr);
1c79356b
A
883 }
884 else {
885 int cpu;
2d21ac55 886
91447636 887 for (cpu = 0; cpu < real_ncpus; cpu++) {
9bccf70c 888 if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
2d21ac55
A
889 cpu_to_processor(cpu)->active_thread == th &&
890 PerProcTable[cpu].ppe_vaddr->db_saved_state) {
1c79356b
A
891 break;
892 }
893 }
894 if (top_act != THR_ACT_NULL) {
895 /*
896 * Trying to get the backtrace of an activation
897 * which is not the top_most one in the RPC chain:
898 * use the activation's pcb.
899 */
9bccf70c 900 struct savearea *pss;
2d21ac55 901
91447636 902 pss = th->machine.pcb;
9bccf70c
A
903 frame = (struct db_ppc_frame *) (pss->save_r1);
904 callpc = (db_addr_t) (pss->save_srr0);
905 linkpc = (db_addr_t) (pss->save_lr);
2d21ac55
A
906 } else {
907 if (cpu == real_ncpus) {
908 struct savearea *iks;
909 int r;
910
911 iks = th->machine.pcb;
912 prev = db_recover;
913 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
914 frame = (struct db_ppc_frame *) (iks->save_r1);
915 callpc = (db_addr_t) (iks->save_lr);
916 linkpc = 0;
1c79356b 917 } else {
2d21ac55
A
918 /*
919 * The kernel stack has probably been
920 * paged out (swapped out activation).
921 */
922 db_recover = prev;
923 if (r == 2) /* 'q' from db_more() */
924 db_error(0);
925 db_printf("<kernel stack (0x%x) error "
926 "(probably swapped out)>\n",
927 iks);
928 goto next_act;
1c79356b 929 }
2d21ac55
A
930 db_recover = prev;
931 } else {
932 db_printf(">>>>> active on cpu %d <<<<<\n",
933 cpu);
934 frame = (struct db_ppc_frame *)
935 (PerProcTable[cpu].ppe_vaddr->db_saved_state->save_r1);
936 callpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_srr0;
937 linkpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_lr;
1c79356b
A
938 }
939 }
2d21ac55
A
940 }
941 }
1c79356b 942 } else {
2d21ac55
A
943 frame = (struct db_ppc_frame *)addr;
944 th = (db_default_act)? db_default_act: current_thread();
945 task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
946 if (frame->f_frame) {
947 callpc = (db_addr_t)db_get_task_value
1c79356b 948 ((int)&frame->f_frame->f_retaddr,
2d21ac55
A
949 4, FALSE, (user_frame) ? task : 0);
950 callpc = callpc-sizeof(callpc);
951 } else
952 callpc =0;
953 linkpc = 0;
1c79356b
A
954 }
955
956 if (!INKERNELSTACK((unsigned)frame, th)) {
2d21ac55
A
957 db_printf(">>>>> user space <<<<<\n");
958 if (kernel_only)
959 goto thread_done;
960 user_frame++;
1c79356b 961 }
2d21ac55 962
1c79356b
A
963 lastframe = 0;
964 lastcallpc = (db_addr_t) 0;
965 while (frame_count-- && frame != 0) {
966 int narg = DB_NUMARGS_MAX;
967 int arg;
968 char * name;
969 db_expr_t offset;
970 db_addr_t call_func = 0;
971 int r;
972 db_addr_t off;
973
974 db_symbol_values(NULL,
2d21ac55
A
975 db_search_task_symbol_and_line(
976 callpc, DB_STGY_XTRN, &offset, &filename,
977 &linenum, (user_frame) ? task : 0, &narg),
978 &name, (db_expr_t *)&call_func);
1c79356b
A
979 if ( name == NULL) {
980 db_find_task_sym_and_offset(callpc,
2d21ac55 981 &name, &off, (user_frame) ? task : 0);
1c79356b
A
982 offset = (db_expr_t) off;
983 }
984
985 if (user_frame == 0) {
986 if (call_func &&
2d21ac55
A
987 (call_func == db_user_trap_symbol_value ||
988 call_func == db_kernel_trap_symbol_value)) {
989 frame_type = TRAP;
990 narg = 1;
1c79356b 991 } else if (call_func &&
2d21ac55 992 call_func == db_interrupt_symbol_value) {
1c79356b
A
993 frame_type = INTERRUPT;
994 goto next_frame;
995 } else if (call_func &&
2d21ac55 996 call_func == db_syscall_symbol_value) {
1c79356b
A
997 frame_type = SYSCALL;
998 goto next_frame;
999 } else {
1000 frame_type = 0;
1001 prev = db_recover;
1002 if ((r = _setjmp(db_recover = &db_jmp_buf))
2d21ac55
A
1003 == 0) {
1004 if (narg < 0)
1c79356b 1005 narg = db_numargs(frame,
2d21ac55 1006 (user_frame) ? task : 0);
1c79356b
A
1007 db_recover = prev;
1008 } else {
1009 db_recover = prev;
1010 goto next_act;
1011 }
1012 }
2d21ac55 1013 } else {
1c79356b
A
1014 frame_type = 0;
1015 prev = db_recover;
1016 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
1017 if (narg < 0)
1018 narg = db_numargs(frame,
2d21ac55 1019 (user_frame) ? task : 0);
1c79356b
A
1020 db_recover = prev;
1021 } else {
1022 db_recover = prev;
1023 goto next_act;
1024 }
1025 }
1026
2d21ac55 1027 if (name == 0 || offset > db_maxoff) {
91447636 1028 db_printf("[%08X]0x%08X(", frame, callpc);
2d21ac55
A
1029 } else {
1030 db_printf("[%08X]%s", frame, name);
91447636
A
1031 if (offset)
1032 db_printf("+%llx", offset);
2d21ac55
A
1033 db_printf("(");
1034 };
1c79356b 1035
2d21ac55 1036 narg = db_numargs(frame, (user_frame) ? task : 0);
1c79356b 1037
2d21ac55
A
1038 for (arg = 0; arg < narg; arg++) {
1039 db_addr_t argp;
1040 int value;
1041 boolean_t found;
1042
1043 prev = db_recover;
1044 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
1045 found = FALSE;
1046 if (lastframe)
1047 found = db_find_arg(frame, lastframe->f_retaddr,
1048 (user_frame) ? task : 0, arg, &argp);
1049 if (found)
1050 value = db_get_task_value(argp, 4, FALSE,
1051 (user_frame) ? task : 0);
1052 } else {
1053 db_recover = prev;
1054 if (r == 2) /* 'q' from db_more() */
1055 db_error(0);
1056 db_printf("... <stack error>)");
1057 db_printf("\n");
1058 goto next_act;
1059 }
1060 db_recover = prev;
1061 if (found)
1062 db_printf("%08X", value);
1063 else
1064 db_printf("??");
1065 argp = argp + sizeof(argp);
1066 if (arg < narg-1)
1067 db_printf(",");
1068 }
1069 if (arg != narg)
1070 db_printf("...");
1071 db_printf(")");
1072 db_printf("\n");
1c79356b 1073
2d21ac55
A
1074next_frame:
1075 lastcallpc = callpc;
1c79356b
A
1076 prev = db_recover;
1077 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
2d21ac55
A
1078 db_nextframe(&lastframe, &frame, &callpc, frame_type,
1079 (user_frame) ? th : THR_ACT_NULL, linkpc);
1080 callpc = callpc-sizeof(callpc);
1081 db_recover = prev;
1c79356b
A
1082 } else {
1083 db_recover = prev;
2d21ac55 1084 frame = 0;
1c79356b 1085 }
2d21ac55
A
1086 linkpc = 0;
1087
1088 if (frame == 0) {
1089next_act:
1090 /* end of chain */
1091 break;
1092 }
1093 if (!INKERNELSTACK(lastframe, th) ||
1094 !INKERNELSTACK((unsigned)frame, th))
1095 user_frame++;
1096 if (user_frame == 1) {
1097 db_printf(">>>>> user space <<<<<\n");
1098 if (kernel_only)
1099 break;
1100 }
1101
1c79356b 1102 if (frame <= lastframe) {
2d21ac55
A
1103 if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th)))
1104 continue;
1105 db_printf("Bad frame pointer: 0x%x\n", frame);
1106 break;
1107 }
1c79356b
A
1108 }
1109
2d21ac55 1110thread_done:
1c79356b 1111 if (trace_all_threads) {
2d21ac55
A
1112 if (top_act != THR_ACT_NULL)
1113 th = top_act;
1114 th = (thread_act_t) queue_next(&th->task_threads);
1115 if (! queue_end(act_list, (queue_entry_t) th)) {
1116 db_printf("\n");
1117 addr = (db_expr_t) th;
1118 thcount++;
1119 goto next_thread;
1120 }
1c79356b
A
1121 }
1122}