2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 #include <mach/boolean.h>
35 #include <mach/machine.h>
37 #include <vm/vm_map.h>
39 #include <kern/thread.h>
40 #include <kern/processor.h>
41 #include <kern/task.h>
43 #include <ppc/cpu_internal.h>
44 #include <ppc/exception.h>
46 #include <machine/asm.h>
47 #include <machine/db_machdep.h>
48 #include <machine/setjmp.h>
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>
57 extern jmp_buf_t
*db_recover
;
59 struct savearea ddb_null_kregs
;
61 extern vm_offset_t vm_min_inks_addr
; /* set by db_clone_symtabXXX */
63 #define DB_NUMARGS_MAX 5
65 #define INFIXEDSTACK(va) 0 \
67 #define INKERNELSTACK(va, th) 1
70 struct db_ppc_frame
*f_frame
;
76 uint32_t f_arg
[DB_NUMARGS_MAX
];
83 db_addr_t db_user_trap_symbol_value
= 0;
84 db_addr_t db_kernel_trap_symbol_value
= 0;
85 db_addr_t db_interrupt_symbol_value
= 0;
86 db_addr_t db_return_to_iret_symbol_value
= 0;
87 db_addr_t db_syscall_symbol_value
= 0;
88 boolean_t db_trace_symbols_found
= FALSE
;
90 static int db_ppc_reg_value(
91 struct db_variable
* vp
,
94 db_var_aux_param_t ap
);
95 static void db_find_trace_symbols(void);
96 static int db_numargs(
97 struct db_ppc_frame
*fp
,
99 static boolean_t
db_find_arg(
100 struct db_ppc_frame
*frame
,
105 static void db_nextframe(
106 struct db_ppc_frame
**lfp
,
107 struct db_ppc_frame
**fp
,
110 thread_act_t thr_act
,
114 * Machine register set.
116 struct db_variable db_regs
[] = {
117 /* XXX "pc" is an alias to "srr0"... */
120 .valuep
= &ddb_regs
.save_srr0
,
121 .fcn
= db_ppc_reg_value
,
126 .hidden_level
= TRUE
,
130 .valuep
= &ddb_regs
.save_srr0
,
131 .fcn
= db_ppc_reg_value
,
136 .hidden_level
= TRUE
,
140 .valuep
= &ddb_regs
.save_srr1
,
141 .fcn
= db_ppc_reg_value
,
146 .hidden_level
= TRUE
,
150 .valuep
= &ddb_regs
.save_r0
,
151 .fcn
= db_ppc_reg_value
,
156 .hidden_level
= TRUE
,
160 .valuep
= &ddb_regs
.save_r1
,
161 .fcn
= db_ppc_reg_value
,
166 .hidden_level
= TRUE
,
170 .valuep
= &ddb_regs
.save_r2
,
171 .fcn
= db_ppc_reg_value
,
176 .hidden_level
= TRUE
,
180 .valuep
= &ddb_regs
.save_r3
,
181 .fcn
= db_ppc_reg_value
,
186 .hidden_level
= TRUE
,
190 .valuep
= &ddb_regs
.save_r4
,
191 .fcn
= db_ppc_reg_value
,
196 .hidden_level
= TRUE
,
200 .valuep
= &ddb_regs
.save_r5
,
201 .fcn
= db_ppc_reg_value
,
206 .hidden_level
= TRUE
,
210 .valuep
= &ddb_regs
.save_r6
,
211 .fcn
= db_ppc_reg_value
,
216 .hidden_level
= TRUE
,
220 .valuep
= &ddb_regs
.save_r7
,
221 .fcn
= db_ppc_reg_value
,
226 .hidden_level
= TRUE
,
230 .valuep
= &ddb_regs
.save_r8
,
231 .fcn
= db_ppc_reg_value
,
236 .hidden_level
= TRUE
,
240 .valuep
= &ddb_regs
.save_r9
,
241 .fcn
= db_ppc_reg_value
,
246 .hidden_level
= TRUE
,
250 .valuep
= &ddb_regs
.save_r10
,
251 .fcn
= db_ppc_reg_value
,
256 .hidden_level
= TRUE
,
260 .valuep
= &ddb_regs
.save_r11
,
261 .fcn
= db_ppc_reg_value
,
266 .hidden_level
= TRUE
,
270 .valuep
= &ddb_regs
.save_r12
,
271 .fcn
= db_ppc_reg_value
,
276 .hidden_level
= TRUE
,
280 .valuep
= &ddb_regs
.save_r13
,
281 .fcn
= db_ppc_reg_value
,
286 .hidden_level
= TRUE
,
290 .valuep
= &ddb_regs
.save_r14
,
291 .fcn
= db_ppc_reg_value
,
296 .hidden_level
= TRUE
,
300 .valuep
= &ddb_regs
.save_r15
,
301 .fcn
= db_ppc_reg_value
,
306 .hidden_level
= TRUE
,
310 .valuep
= &ddb_regs
.save_r16
,
311 .fcn
= db_ppc_reg_value
,
316 .hidden_level
= TRUE
,
320 .valuep
= &ddb_regs
.save_r17
,
321 .fcn
= db_ppc_reg_value
,
326 .hidden_level
= TRUE
,
330 .valuep
= &ddb_regs
.save_r18
,
331 .fcn
= db_ppc_reg_value
,
336 .hidden_level
= TRUE
,
340 .valuep
= &ddb_regs
.save_r19
,
341 .fcn
= db_ppc_reg_value
,
346 .hidden_level
= TRUE
,
350 .valuep
= &ddb_regs
.save_r20
,
351 .fcn
= db_ppc_reg_value
,
356 .hidden_level
= TRUE
,
360 .valuep
= &ddb_regs
.save_r21
,
361 .fcn
= db_ppc_reg_value
,
366 .hidden_level
= TRUE
,
370 .valuep
= &ddb_regs
.save_r22
,
371 .fcn
= db_ppc_reg_value
,
376 .hidden_level
= TRUE
,
380 .valuep
= &ddb_regs
.save_r23
,
381 .fcn
= db_ppc_reg_value
,
386 .hidden_level
= TRUE
,
390 .valuep
= &ddb_regs
.save_r24
,
391 .fcn
= db_ppc_reg_value
,
396 .hidden_level
= TRUE
,
400 .valuep
= &ddb_regs
.save_r25
,
401 .fcn
= db_ppc_reg_value
,
406 .hidden_level
= TRUE
,
410 .valuep
= &ddb_regs
.save_r26
,
411 .fcn
= db_ppc_reg_value
,
416 .hidden_level
= TRUE
,
420 .valuep
= &ddb_regs
.save_r27
,
421 .fcn
= db_ppc_reg_value
,
426 .hidden_level
= TRUE
,
430 .valuep
= &ddb_regs
.save_r28
,
431 .fcn
= db_ppc_reg_value
,
436 .hidden_level
= TRUE
,
440 .valuep
= &ddb_regs
.save_r29
,
441 .fcn
= db_ppc_reg_value
,
446 .hidden_level
= TRUE
,
450 .valuep
= &ddb_regs
.save_r30
,
451 .fcn
= db_ppc_reg_value
,
456 .hidden_level
= TRUE
,
460 .valuep
= &ddb_regs
.save_r31
,
461 .fcn
= db_ppc_reg_value
,
466 .hidden_level
= TRUE
,
470 .valuep
= (db_expr_t
*)&ddb_regs
.save_cr
,
471 .fcn
= db_ppc_reg_value
,
476 .hidden_level
= TRUE
,
480 .valuep
= &ddb_regs
.save_xer
,
481 .fcn
= db_ppc_reg_value
,
486 .hidden_level
= TRUE
,
490 .valuep
= &ddb_regs
.save_lr
,
491 .fcn
= db_ppc_reg_value
,
496 .hidden_level
= TRUE
,
500 .valuep
= &ddb_regs
.save_ctr
,
501 .fcn
= db_ppc_reg_value
,
506 .hidden_level
= TRUE
,
509 struct db_variable
*db_eregs
= db_regs
+ sizeof(db_regs
)/sizeof(db_regs
[0]);
513 struct db_variable
*vp
,
516 db_var_aux_param_t ap
)
519 db_expr_t null_reg
= 0;
521 thread_act_t thr_act
= ap
->thr_act
;
524 if (db_option(ap
->modif
, 'u')) {
525 if (thr_act
== THR_ACT_NULL
) {
526 if ((thr_act
= current_thread()) == THR_ACT_NULL
)
527 db_error("no user registers\n");
529 if (thr_act
== current_thread()) {
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");
536 if (thr_act
== THR_ACT_NULL
|| thr_act
== current_thread()) {
540 if (thr_act
->kernel_stack
) {
541 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
542 if (cpu_to_processor(cpu
)->state
== PROCESSOR_RUNNING
&&
543 cpu_to_processor(cpu
)->active_thread
== thr_act
&&
544 PerProcTable
[cpu
].ppe_vaddr
->db_saved_state
) {
546 dp
= (db_expr_t
)(((uint32_t)(PerProcTable
[cpu
].ppe_vaddr
->db_saved_state
)) +
547 (((uint32_t) vp
->valuep
) -
548 (uint32_t) &ddb_regs
));
557 /* only PC is valid */
558 if (vp
->valuep
== &ddb_regs
.save_srr0
)
559 dp
= (db_expr_t
*)&thr_act
->continuation
;
566 if (!db_option(ap
->modif
, 'u')) {
567 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
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
));
578 if (!thr_act
|| thr_act
->machine
.pcb
== 0)
579 db_error("no pcb\n");
580 dp
= (int *)((int)thr_act
->machine
.pcb
+ ((int)vp
->valuep
- (int)&ddb_regs
));
584 if(vp
->valuep
== (db_expr_t
*)&ddb_regs
.save_cr
) { /* Is this the CR we are doing? */
585 dp32
= (uint32_t *)dp
; /* Make this easier */
586 if (flag
== DB_VAR_SET
)
591 else { /* Normal 64-bit registers */
592 if (flag
== DB_VAR_SET
)
595 *valuep
= *(unsigned long long *)dp
;
603 db_find_trace_symbols(void)
606 boolean_t found_some
;
609 if (db_value_of_name(CC_SYM_PREFIX
"thandler", &value
)) {
610 db_user_trap_symbol_value
= (db_addr_t
) value
;
613 if (db_value_of_name(CC_SYM_PREFIX
"thandler", &value
)) {
614 db_kernel_trap_symbol_value
= (db_addr_t
) value
;
617 if (db_value_of_name(CC_SYM_PREFIX
"ihandler", &value
)) {
618 db_interrupt_symbol_value
= (db_addr_t
) value
;
622 if (db_value_of_name(CC_SYM_PREFIX
"return_to_iret", &value
)) {
623 db_return_to_iret_symbol_value
= (db_addr_t
) value
;
627 if (db_value_of_name(CC_SYM_PREFIX
"thandler", &value
)) {
628 db_syscall_symbol_value
= (db_addr_t
) value
;
632 db_trace_symbols_found
= TRUE
;
637 struct db_ppc_frame
*fp
,
640 return DB_NUMARGS_MAX
;
645 struct db_ppc_frame
*fp
,
659 db_find_task_sym_and_offset(calleepc
, &name
, &offset
, task
);
660 calleep
= calleepc
-offset
;
662 for (i
= 0; calleep
< calleepc
; i
++, calleep
++) {
663 if (!DB_CHECK_ACCESS((int) calleep
, 4, task
)) {
666 inst
= db_get_task_value(calleep
, 4, FALSE
, task
);
667 if ((inst
& 0xffff0000) == (0x907f0000 + (narg
<< 21)) ||
668 (inst
& 0xffff0000) == (0x90610000 + (narg
<< 21))) {
669 argp
= (db_addr_t
) &(fp
->f_arg
[narg
]);
678 extern int TRAP_TYPES
;
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.
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 */
698 struct savearea
*saved_regs
;
700 task_t task
= (thr_act
!= THR_ACT_NULL
)? thr_act
->task
: TASK_NULL
;
704 db_printf(">>>>> trap <<<<<\n");
709 db_printf(">>>>> interrupt <<<<<\n");
712 db_printf(">>>>> interrupt <<<<<\n");
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
);
721 /* falling down for unknown case */
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 */
732 db_get_task_value((int)&(*fp
)->f_frame
->f_retaddr
,
736 db_get_task_value((int)&(*fp
)->f_retaddr
,
740 *fp
= (struct db_ppc_frame
*)
741 db_get_task_value((int)&(*fp
)->f_frame
, 4, FALSE
, task
);
753 struct db_ppc_frame
*frame
, *lastframe
;
754 db_addr_t callpc
, linkpc
, lastcallpc
;
756 boolean_t kernel_only
= TRUE
;
757 boolean_t trace_thread
= FALSE
;
758 boolean_t trace_all_threads
= FALSE
;
763 thread_act_t th
, top_act
;
767 jmp_buf_t db_jmp_buf
;
768 queue_entry_t act_list
;
770 if (!db_trace_symbols_found
)
771 db_find_trace_symbols();
776 while ((c
= *cp
++) != 0) {
780 trace_all_threads
= TRUE
;
788 if (trace_all_threads
) {
789 if (!have_addr
&& !trace_thread
) {
792 act_list
= &(current_task()->threads
);
793 addr
= (db_expr_t
) queue_first(act_list
);
795 else if (trace_thread
) {
797 if (!db_check_act_address_valid((thread_act_t
)addr
)) {
798 if (db_lookup_task((task_t
)addr
) == -1)
800 act_list
= &(((task_t
)addr
)->threads
);
801 addr
= (db_expr_t
) queue_first(act_list
);
804 act_list
= &(((thread_act_t
)addr
)->task
->threads
);
805 thcount
= db_lookup_task_act(((thread_act_t
)addr
)->task
,
811 if (th
== THR_ACT_NULL
)
812 th
= current_thread();
813 if (th
== THR_ACT_NULL
) {
814 db_printf("no active thr_act\n");
818 act_list
= &th
->task
->threads
;
819 addr
= (db_expr_t
) queue_first(act_list
);
828 top_act
= THR_ACT_NULL
;
833 if (!have_addr
&& !trace_thread
) {
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
;
840 else if (trace_thread
) {
842 th
= (thread_act_t
) addr
;
843 if (!db_check_act_address_valid(th
))
848 if (th
== THR_ACT_NULL
)
849 th
= current_thread();
850 if (th
== THR_ACT_NULL
) {
851 db_printf("no active thread\n");
855 if (trace_all_threads
)
856 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
857 addr
, thcount
, th
->task
->thread_count
);
863 if (th
== current_thread()) {
864 frame
= (struct db_ppc_frame
*)(ddb_regs
.save_r1
);
865 callpc
= (db_addr_t
)ddb_regs
.save_srr0
;
866 linkpc
= (db_addr_t
)ddb_regs
.save_lr
;
869 if (th
->machine
.pcb
== 0) {
870 db_printf("thread has no pcb\n");
873 if (th
->kernel_stack
== 0) {
874 struct savearea
*pss
= th
->machine
.pcb
;
876 db_printf("Continuation ");
877 db_task_printsym((db_expr_t
)th
->continuation
,
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
);
887 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
888 if (cpu_to_processor(cpu
)->state
== PROCESSOR_RUNNING
&&
889 cpu_to_processor(cpu
)->active_thread
== th
&&
890 PerProcTable
[cpu
].ppe_vaddr
->db_saved_state
) {
894 if (top_act
!= THR_ACT_NULL
) {
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.
900 struct savearea
*pss
;
902 pss
= th
->machine
.pcb
;
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
);
907 if (cpu
== real_ncpus
) {
908 struct savearea
*iks
;
911 iks
= th
->machine
.pcb
;
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
);
919 * The kernel stack has probably been
920 * paged out (swapped out activation).
923 if (r
== 2) /* 'q' from db_more() */
925 db_printf("<kernel stack (0x%x) error "
926 "(probably swapped out)>\n",
932 db_printf(">>>>> active on cpu %d <<<<<\n",
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
;
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
948 ((int)&frame
->f_frame
->f_retaddr
,
949 4, FALSE
, (user_frame
) ? task
: 0);
950 callpc
= callpc
-sizeof(callpc
);
956 if (!INKERNELSTACK((unsigned)frame
, th
)) {
957 db_printf(">>>>> user space <<<<<\n");
964 lastcallpc
= (db_addr_t
) 0;
965 while (frame_count
-- && frame
!= 0) {
966 int narg
= DB_NUMARGS_MAX
;
970 db_addr_t call_func
= 0;
974 db_symbol_values(NULL
,
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
);
980 db_find_task_sym_and_offset(callpc
,
981 &name
, &off
, (user_frame
) ? task
: 0);
982 offset
= (db_expr_t
) off
;
985 if (user_frame
== 0) {
987 (call_func
== db_user_trap_symbol_value
||
988 call_func
== db_kernel_trap_symbol_value
)) {
991 } else if (call_func
&&
992 call_func
== db_interrupt_symbol_value
) {
993 frame_type
= INTERRUPT
;
995 } else if (call_func
&&
996 call_func
== db_syscall_symbol_value
) {
997 frame_type
= SYSCALL
;
1002 if ((r
= _setjmp(db_recover
= &db_jmp_buf
))
1005 narg
= db_numargs(frame
,
1006 (user_frame
) ? task
: 0);
1016 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
1018 narg
= db_numargs(frame
,
1019 (user_frame
) ? task
: 0);
1027 if (name
== 0 || offset
> db_maxoff
) {
1028 db_printf("[%08X]0x%08X(", frame
, callpc
);
1030 db_printf("[%08X]%s", frame
, name
);
1032 db_printf("+%llx", offset
);
1036 narg
= db_numargs(frame
, (user_frame
) ? task
: 0);
1038 for (arg
= 0; arg
< narg
; arg
++) {
1044 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
1047 found
= db_find_arg(frame
, lastframe
->f_retaddr
,
1048 (user_frame
) ? task
: 0, arg
, &argp
);
1050 value
= db_get_task_value(argp
, 4, FALSE
,
1051 (user_frame
) ? task
: 0);
1054 if (r
== 2) /* 'q' from db_more() */
1056 db_printf("... <stack error>)");
1062 db_printf("%08X", value
);
1065 argp
= argp
+ sizeof(argp
);
1075 lastcallpc
= callpc
;
1077 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
1078 db_nextframe(&lastframe
, &frame
, &callpc
, frame_type
,
1079 (user_frame
) ? th
: THR_ACT_NULL
, linkpc
);
1080 callpc
= callpc
-sizeof(callpc
);
1093 if (!INKERNELSTACK(lastframe
, th
) ||
1094 !INKERNELSTACK((unsigned)frame
, th
))
1096 if (user_frame
== 1) {
1097 db_printf(">>>>> user space <<<<<\n");
1102 if (frame
<= lastframe
) {
1103 if ((INKERNELSTACK(lastframe
, th
) && !INKERNELSTACK(frame
, th
)))
1105 db_printf("Bad frame pointer: 0x%x\n", frame
);
1111 if (trace_all_threads
) {
1112 if (top_act
!= THR_ACT_NULL
)
1114 th
= (thread_act_t
) queue_next(&th
->task_threads
);
1115 if (! queue_end(act_list
, (queue_entry_t
) th
)) {
1117 addr
= (db_expr_t
) th
;