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@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
61 #include <mach/boolean.h>
62 #include <vm/vm_map.h>
63 #include <kern/thread.h>
64 #include <kern/task.h>
66 #include <machine/asm.h>
67 #include <machine/db_machdep.h>
68 #include <machine/setjmp.h>
69 #include <mach/machine.h>
70 #include <mach/kmod.h>
74 #include <i386/cpuid.h>
75 #include <i386/proc_reg.h>
76 #include <i386/machine_routines.h>
78 #include <ddb/db_access.h>
79 #include <ddb/db_sym.h>
80 #include <ddb/db_variables.h>
81 #include <ddb/db_command.h>
82 #include <ddb/db_task_thread.h>
83 #include <ddb/db_output.h>
85 extern jmp_buf_t
*db_recover
;
86 struct x86_kernel_state32 ddb_null_kregs
;
87 extern kmod_info_t
*kmod
;
94 #define INKERNELSTACK(va, th) 1
96 #define DB_NUMARGS_MAX 5
99 struct i386_frame
*f_frame
;
108 db_addr_t db_user_trap_symbol_value
= 0;
109 db_addr_t db_kernel_trap_symbol_value
= 0;
110 db_addr_t db_interrupt_symbol_value
= 0;
111 db_addr_t db_return_to_iret_symbol_value
= 0;
112 db_addr_t db_syscall_symbol_value
= 0;
113 boolean_t db_trace_symbols_found
= FALSE
;
119 { "ebx", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_ebx
) },
120 { "esp", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_esp
) },
121 { "ebp", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_ebp
) },
122 { "edi", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_edi
) },
123 { "esi", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_esi
) },
124 { "eip", (unsigned int)(&((struct x86_kernel_state32
*)0)->k_eip
) },
130 extern unsigned int * db_lookup_i386_kreg(
133 extern int db_i386_reg_value(
134 struct db_variable
* vp
,
137 db_var_aux_param_t ap
);
138 extern void db_find_trace_symbols(void);
139 extern int db_numargs(
140 struct i386_frame
*fp
,
142 extern void db_nextframe(
143 struct i386_frame
**lfp
,
144 struct i386_frame
**fp
,
152 * Machine register set.
154 struct db_variable db_regs
[] = {
155 { "cs", (unsigned int *)&ddb_regs
.cs
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
156 { "ds", (unsigned int *)&ddb_regs
.ds
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
157 { "es", (unsigned int *)&ddb_regs
.es
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
158 { "fs", (unsigned int *)&ddb_regs
.fs
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
159 { "gs", (unsigned int *)&ddb_regs
.gs
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
160 { "ss", (unsigned int *)&ddb_regs
.ss
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
161 { "eax",(unsigned int *)&ddb_regs
.eax
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
162 { "ecx",(unsigned int *)&ddb_regs
.ecx
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
163 { "edx",(unsigned int *)&ddb_regs
.edx
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
164 { "ebx",(unsigned int *)&ddb_regs
.ebx
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
165 { "esp",(unsigned int *)&ddb_regs
.uesp
,db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
166 { "ebp",(unsigned int *)&ddb_regs
.ebp
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
167 { "esi",(unsigned int *)&ddb_regs
.esi
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
168 { "edi",(unsigned int *)&ddb_regs
.edi
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
169 { "eip",(unsigned int *)&ddb_regs
.eip
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 },
170 { "efl",(unsigned int *)&ddb_regs
.efl
, db_i386_reg_value
, 0, 0, 0, 0, TRUE
, 0, 0, (int *)0, 0 }
172 struct db_variable
*db_eregs
= db_regs
+ sizeof(db_regs
)/sizeof(db_regs
[0]);
179 register struct i386_kregs
*kp
;
181 for (kp
= i386_kregs
; kp
->name
; kp
++) {
182 if (strcmp(name
, kp
->name
) == 0)
183 return((unsigned int *)((int)kregp
+ kp
->offset
));
190 struct db_variable
*vp
,
193 db_var_aux_param_t ap
)
196 unsigned int *dp
= 0;
197 db_expr_t null_reg
= 0;
198 register thread_t thr_act
= ap
->thr_act
;
200 if (db_option(ap
->modif
, 'u')) {
201 if (thr_act
== THREAD_NULL
) {
202 if ((thr_act
= current_thread()) == THREAD_NULL
)
203 db_error("no user registers\n");
205 if (thr_act
== current_thread()) {
206 if (IS_USER_TRAP(&ddb_regs
, &etext
))
210 if (thr_act
== THREAD_NULL
|| thr_act
== current_thread()) {
214 (thr_act
->continuation
!= THREAD_CONTINUE_NULL
) &&
215 thr_act
->kernel_stack
) {
218 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
219 if (cpu_datap(cpu
)->cpu_running
== TRUE
&&
220 cpu_datap(cpu
)->cpu_active_thread
== thr_act
&& cpu_datap(cpu
)->cpu_kdb_saved_state
) {
221 dp
= (unsigned int *) (((unsigned int)cpu_datap(cpu
)->cpu_kdb_saved_state
) +
222 (((unsigned int) vp
->valuep
) -
223 (unsigned int) &ddb_regs
));
227 if (dp
== 0 && thr_act
)
228 dp
= db_lookup_i386_kreg(vp
->name
,
229 (unsigned int *)(STACK_IKS(thr_act
->kernel_stack
)));
232 } else if (thr_act
&&
233 (thr_act
->continuation
!= THREAD_CONTINUE_NULL
)) {
234 /* only EIP is valid */
235 if (vp
->valuep
== (unsigned int *) &ddb_regs
.eip
) {
236 dp
= (unsigned int *)(&thr_act
->continuation
);
246 if (!db_option(ap
->modif
, 'u')) {
247 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
248 if (cpu_datap(cpu
)->cpu_running
== TRUE
&&
249 cpu_datap(cpu
)->cpu_active_thread
== thr_act
&& cpu_datap(cpu
)->cpu_kdb_saved_state
) {
250 dp
= (unsigned int *) (((unsigned int)cpu_datap(cpu
)->cpu_kdb_saved_state
) +
251 (((unsigned int) vp
->valuep
) -
252 (unsigned int) &ddb_regs
));
258 if (!thr_act
|| thr_act
->machine
.pcb
== 0)
259 db_error("no pcb\n");
260 dp
= (unsigned int *)((unsigned int)(thr_act
->machine
.pcb
->iss
) +
261 ((unsigned int)vp
->valuep
- (unsigned int)&ddb_regs
));
264 if (flag
== DB_VAR_SET
)
272 db_find_trace_symbols(void)
275 boolean_t found_some
;
278 if (db_value_of_name(CC_SYM_PREFIX
"user_trap", &value
)) {
279 db_user_trap_symbol_value
= (db_addr_t
) value
;
282 if (db_value_of_name(CC_SYM_PREFIX
"kernel_trap", &value
)) {
283 db_kernel_trap_symbol_value
= (db_addr_t
) value
;
286 if (db_value_of_name(CC_SYM_PREFIX
"interrupt", &value
)) {
287 db_interrupt_symbol_value
= (db_addr_t
) value
;
290 if (db_value_of_name(CC_SYM_PREFIX
"return_to_iret", &value
)) {
291 db_return_to_iret_symbol_value
= (db_addr_t
) value
;
294 if (db_value_of_name(CC_SYM_PREFIX
"syscall", &value
)) {
295 db_syscall_symbol_value
= (db_addr_t
) value
;
299 db_trace_symbols_found
= TRUE
;
303 * Figure out how many arguments were passed into the frame at "fp".
305 int db_numargs_default
= 5;
309 struct i386_frame
*fp
,
317 argp
= (int *)db_get_task_value((int)&fp
->f_retaddr
, 4, FALSE
, task
);
318 if (argp
< (int *)VM_MIN_KERNEL_ADDRESS
|| (char *)argp
> &etext
)
319 args
= db_numargs_default
;
320 else if (!DB_CHECK_ACCESS((int)argp
, 4, task
))
321 args
= db_numargs_default
;
323 inst
= db_get_task_value((int)argp
, 4, FALSE
, task
);
324 if ((inst
& 0xff) == 0x59) /* popl %ecx */
326 else if ((inst
& 0xffff) == 0xc483) /* addl %n, %esp */
327 args
= ((inst
>> 16) & 0xff) / 4;
329 args
= db_numargs_default
;
334 struct interrupt_frame
{
335 struct i386_frame
*if_frame
; /* point to next frame */
336 int if_retaddr
; /* return address to _interrupt */
337 int if_unit
; /* unit number */
338 int if_spl
; /* saved spl */
339 int if_iretaddr
; /* _return_to_{iret,iret_i} */
340 int if_edx
; /* old sp(iret) or saved edx(iret_i) */
341 int if_ecx
; /* saved ecx(iret_i) */
342 int if_eax
; /* saved eax(iret_i) */
343 int if_eip
; /* saved eip(iret_i) */
344 int if_cs
; /* saved cs(iret_i) */
345 int if_efl
; /* saved efl(iret_i) */
348 extern const char *trap_type
[];
349 extern int TRAP_TYPES
;
352 * Figure out the next frame up in the call stack.
353 * For trap(), we print the address of the faulting instruction and
354 * proceed with the calling frame. We return the ip that faulted.
355 * If the trap was caused by jumping through a bogus pointer, then
356 * the next line in the backtrace will list some random function as
357 * being called. It should get the argument list correct, though.
358 * It might be possible to dig out from the next frame up the name
359 * of the function that faulted, but that could get hairy.
363 struct i386_frame
**lfp
, /* in/out */
364 struct i386_frame
**fp
, /* in/out */
365 db_addr_t
*ip
, /* out */
366 int frame_type
, /* in */
367 thread_t thr_act
) /* in */
369 x86_saved_state32_t
*iss32
;
370 struct interrupt_frame
*ifp
;
371 task_t task
= (thr_act
!= THREAD_NULL
)? thr_act
->task
: TASK_NULL
;
376 * We know that trap() has 1 argument and we know that
377 * it is an (strcut x86_saved_state32_t *).
379 iss32
= (x86_saved_state32_t
*)
380 db_get_task_value((int)&((*fp
)->f_arg0
),4,FALSE
,task
);
382 if (iss32
->trapno
>= 0 && iss32
->trapno
< TRAP_TYPES
) {
383 db_printf(">>>>> %s trap at ",
384 trap_type
[iss32
->trapno
]);
386 db_printf(">>>>> trap (number %d) at ",
387 iss32
->trapno
& 0xffff);
389 db_task_printsym(iss32
->eip
, DB_STGY_PROC
, task
);
390 db_printf(" <<<<<\n");
391 *fp
= (struct i386_frame
*)iss32
->ebp
;
392 *ip
= (db_addr_t
)iss32
->eip
;
397 db_printf(">>>>> interrupt <<<<<\n");
400 db_printf(">>>>> interrupt at ");
401 ifp
= (struct interrupt_frame
*)(*lfp
);
403 if (ifp
->if_iretaddr
== db_return_to_iret_symbol_value
) {
404 *ip
= ((x86_saved_state32_t
*)ifp
->if_edx
)->eip
;
406 *ip
= (db_addr_t
)ifp
->if_eip
;
407 db_task_printsym(*ip
, DB_STGY_PROC
, task
);
408 db_printf(" <<<<<\n");
412 if (thr_act
!= THREAD_NULL
&& thr_act
->machine
.pcb
) {
413 iss32
= (x86_saved_state32_t
*)thr_act
->machine
.pcb
->iss
;
415 *ip
= (db_addr_t
)(iss32
->eip
);
416 *fp
= (struct i386_frame
*)(iss32
->ebp
);
420 default: /* falling down for unknown case */
423 db_get_task_value((int)&(*fp
)->f_retaddr
, 4, FALSE
, task
);
425 *fp
= (struct i386_frame
*)
426 db_get_task_value((int)&(*fp
)->f_frame
, 4, FALSE
, task
);
438 struct i386_frame
*frame
, *lastframe
;
439 x86_saved_state32_t
*iss32
;
441 db_addr_t callpc
, lastcallpc
;
443 boolean_t kernel_only
= TRUE
;
444 boolean_t trace_thread
= FALSE
;
445 boolean_t trace_all_threads
= FALSE
;
450 thread_t th
, top_act
;
454 jmp_buf_t db_jmp_buf
;
455 queue_entry_t act_list
;
457 if (!db_trace_symbols_found
)
458 db_find_trace_symbols();
461 register char *cp
= modif
;
464 while ((c
= *cp
++) != 0) {
468 trace_all_threads
= TRUE
;
476 if (trace_all_threads
) {
477 if (!have_addr
&& !trace_thread
) {
480 act_list
= &(current_task()->threads
);
481 addr
= (db_expr_t
) queue_first(act_list
);
482 } else if (trace_thread
) {
484 if (!db_check_act_address_valid((thread_t
)addr
)) {
485 if (db_lookup_task((task_t
)addr
) == -1)
487 act_list
= &(((task_t
)addr
)->threads
);
488 addr
= (db_expr_t
) queue_first(act_list
);
490 act_list
= &(((thread_t
)addr
)->task
->threads
);
491 thcount
= db_lookup_task_act(((thread_t
)addr
)->task
,
496 if (th
== THREAD_NULL
)
497 th
= current_thread();
498 if (th
== THREAD_NULL
) {
499 db_printf("no active thr_act\n");
503 act_list
= &th
->task
->threads
;
504 addr
= (db_expr_t
) queue_first(act_list
);
513 top_act
= THREAD_NULL
;
518 if (!have_addr
&& !trace_thread
) {
519 frame
= (struct i386_frame
*)ddb_regs
.ebp
;
520 callpc
= (db_addr_t
)ddb_regs
.eip
;
521 th
= current_thread();
522 task
= (th
!= THREAD_NULL
)? th
->task
: TASK_NULL
;
523 db_printf("thread 0x%x, current_thread() is 0x%x, ebp is 0x%x, eip is 0x%x\n", th
, current_thread(), ddb_regs
.ebp
, ddb_regs
.eip
);
524 } else if (trace_thread
) {
526 th
= (thread_t
) addr
;
527 if (!db_check_act_address_valid(th
)) {
532 if (th
== THREAD_NULL
)
533 th
= current_thread();
534 if (th
== THREAD_NULL
) {
535 db_printf("no active thread\n");
539 if (trace_all_threads
)
540 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
541 addr
, thcount
, th
->task
->thread_count
);
545 // kprintf("th is %x, current_thread() is %x, ddb_regs.ebp is %x ddb_regs.eip is %x\n", th, current_thread(), ddb_regs.ebp, ddb_regs.eip);
547 if (th
== current_thread()) {
548 frame
= (struct i386_frame
*)ddb_regs
.ebp
;
549 callpc
= (db_addr_t
)ddb_regs
.eip
;
551 if (th
->machine
.pcb
== 0) {
552 db_printf("thread has no pcb\n");
556 db_printf("thread has no shuttle\n");
560 else if ( (th
->continuation
!= THREAD_CONTINUE_NULL
) ||
561 th
->kernel_stack
== 0) {
563 db_printf("Continuation ");
564 db_task_printsym((db_expr_t
)th
->continuation
,
568 iss32
= (x86_saved_state32_t
*)th
->machine
.pcb
->iss
;
570 frame
= (struct i386_frame
*) (iss32
->ebp
);
571 callpc
= (db_addr_t
) (iss32
->eip
);
576 for (cpu
= 0; cpu
< real_ncpus
; cpu
++) {
577 if (cpu_datap(cpu
)->cpu_running
== TRUE
&&
578 cpu_datap(cpu
)->cpu_active_thread
== th
&&
579 cpu_datap(cpu
)->cpu_kdb_saved_state
) {
583 if (top_act
!= THREAD_NULL
) {
585 * Trying to get the backtrace of an activation
586 * which is not the top_most one in the RPC chain:
587 * use the activation's pcb.
589 iss32
= (x86_saved_state32_t
*)th
->machine
.pcb
->iss
;
591 frame
= (struct i386_frame
*) (iss32
->ebp
);
592 callpc
= (db_addr_t
) (iss32
->eip
);
594 if (cpu
== real_ncpus
) {
595 register struct x86_kernel_state32
*iks
;
598 iks
= STACK_IKS(th
->kernel_stack
);
600 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
601 frame
= (struct i386_frame
*) (iks
->k_ebp
);
602 callpc
= (db_addr_t
) (iks
->k_eip
);
605 * The kernel stack has probably been
606 * paged out (swapped out activation).
609 if (r
== 2) /* 'q' from db_more() */
611 db_printf("<kernel stack (0x%x) error "
612 "(probably swapped out)>\n",
618 db_printf(">>>>> active on cpu %d <<<<<\n",
621 iss32
= (x86_saved_state32_t
*)cpu_datap(cpu
)->cpu_kdb_saved_state
;
623 frame
= (struct i386_frame
*) (iss32
->ebp
);
624 callpc
= (db_addr_t
) (iss32
->eip
);
630 frame
= (struct i386_frame
*)addr
;
631 th
= (db_default_act
)? db_default_act
: current_thread();
632 task
= (th
!= THREAD_NULL
)? th
->task
: TASK_NULL
;
633 callpc
= (db_addr_t
)db_get_task_value((int)&frame
->f_retaddr
,
636 (user_frame
) ? task
: 0);
639 if (!INKERNELSTACK((unsigned)frame
, th
)) {
640 db_printf(">>>>> user space <<<<<\n");
647 lastcallpc
= (db_addr_t
) 0;
648 while (frame_count
-- && frame
!= 0) {
649 int narg
= DB_NUMARGS_MAX
;
652 db_addr_t call_func
= 0;
656 db_symbol_values(NULL
,
657 db_search_task_symbol_and_line(
663 (user_frame
) ? task
: 0,
665 &name
, (db_expr_t
*)&call_func
);
667 db_find_task_sym_and_offset(callpc
,
668 &name
, &off
, (user_frame
) ? task
: 0);
669 offset
= (db_expr_t
) off
;
672 if (user_frame
== 0) {
673 if (call_func
&& call_func
== db_user_trap_symbol_value
||
674 call_func
== db_kernel_trap_symbol_value
) {
677 } else if (call_func
&&
678 call_func
== db_interrupt_symbol_value
) {
679 frame_type
= INTERRUPT
;
681 } else if (call_func
&& call_func
== db_syscall_symbol_value
) {
682 frame_type
= SYSCALL
;
687 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
689 narg
= db_numargs(frame
,
690 (user_frame
) ? task
: 0);
700 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
702 narg
= db_numargs(frame
,
703 (user_frame
) ? task
: 0);
711 if (name
== 0 || offset
> db_maxoff
) {
712 db_printf("0x%x 0x%x(", frame
, callpc
);
715 db_printf("0x%x %s(", frame
, name
);
717 argp
= &frame
->f_arg0
;
722 if ((r
= _setjmp(db_recover
= &db_jmp_buf
)) == 0) {
723 value
= db_get_task_value((int)argp
,
726 (user_frame
) ? task
: 0);
729 if (r
== 2) /* 'q' from db_more() */
731 db_printf("... <stack error>)");
733 db_printf("+%x", offset
);
735 db_printf(" [%s", filename
);
737 db_printf(":%d", linenum
);
744 db_printf("%x", value
);
753 db_printf("+%x", offset
);
756 db_printf(" [%s", filename
);
758 db_printf(":%d", linenum
);
765 db_nextframe(&lastframe
, &frame
, &callpc
, frame_type
,
766 (user_frame
) ? th
: THREAD_NULL
);
769 if (th
->task_threads
.prev
!= THREAD_NULL
) {
770 if (top_act
== THREAD_NULL
)
772 th
= th
->task_threads
.prev
;
773 db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
775 db_lookup_task(th
->task
),
776 db_lookup_task_act(th
->task
, th
));
777 goto next_activation
;
782 if (!INKERNELSTACK(lastframe
, th
) ||
783 !INKERNELSTACK((unsigned)frame
, th
))
785 if (user_frame
== 1) {
786 db_printf(">>>>> user space <<<<<\n");
790 if (frame
<= lastframe
) {
791 if ((INKERNELSTACK(lastframe
, th
) &&
792 !INKERNELSTACK(frame
, th
)))
794 db_printf("Bad frame pointer: 0x%x\n", frame
);
800 if (trace_all_threads
) {
801 if (top_act
!= THREAD_NULL
)
803 th
= (thread_t
) queue_next(&th
->task_threads
);
804 if (! queue_end(act_list
, (queue_entry_t
) th
)) {
806 addr
= (db_expr_t
) th
;
814 extern int kdp_vm_read(caddr_t
, caddr_t
, unsigned int );
815 extern boolean_t kdp_trans_off
;
817 * Print out 256 bytes of real storage
822 db_display_real(db_expr_t addr
, boolean_t have_addr
, db_expr_t count
,
826 unsigned int xbuf
[8];
827 unsigned read_result
= 0;
828 /* Print 256 bytes */
832 * Do a physical read using kdp_vm_read(), rather than replicating the same
836 read_result
= kdp_vm_read(addr
, &xbuf
[0], 32);
839 if (read_result
!= 32)
840 db_printf("Unable to read address\n");
842 db_printf("%016llX %08X %08X %08X %08X %08X %08X %08X %08X\n", addr
, /* Print a line */
843 xbuf
[0], xbuf
[1], xbuf
[2], xbuf
[3],
844 xbuf
[4], xbuf
[5], xbuf
[6], xbuf
[7]);
845 addr
= addr
+ 0x00000020; /* Point to next address */
851 * Displays all of the kmods in the system.
856 db_display_kmod(__unused db_expr_t addr
, __unused boolean_t have_addr
,
857 __unused db_expr_t count
, __unused
char *modif
)
861 unsigned int strt
, end
;
863 kmd
= kmod
; /* Start at the start */
865 db_printf("info addr start - end name ver\n");
867 while (kmd
) { /* Dump 'em all */
868 strt
= (unsigned int) kmd
->address
+ kmd
->hdr_size
;
869 end
= (unsigned int) kmd
->address
+ kmd
->size
;
870 db_printf("%08X %08X %08X - %08X: %s, %s\n",
871 kmd
, kmd
->address
, strt
, end
, kmd
->name
, kmd
->version
);
877 db_display_iokit(__unused db_expr_t addr
, __unused boolean_t have_addr
,
878 __unused db_expr_t count
, __unused
char *modif
)