/* * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern jmp_buf_t *db_recover; struct x86_kernel_state32 ddb_null_kregs; extern kmod_info_t *kmod; /* * Stack trace. */ #define INKERNELSTACK(va, th) 1 #define DB_NUMARGS_MAX 5 struct i386_frame { struct i386_frame *f_frame; int f_retaddr; int f_arg0; }; #define TRAP 1 #define INTERRUPT 2 #define SYSCALL 3 db_addr_t db_user_trap_symbol_value = 0; db_addr_t db_kernel_trap_symbol_value = 0; db_addr_t db_interrupt_symbol_value = 0; db_addr_t db_return_to_iret_symbol_value = 0; db_addr_t db_syscall_symbol_value = 0; boolean_t db_trace_symbols_found = FALSE; struct i386_kregs { char *name; unsigned int offset; } i386_kregs[] = { { "ebx", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_ebx) }, { "esp", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_esp) }, { "ebp", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_ebp) }, { "edi", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_edi) }, { "esi", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_esi) }, { "eip", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_eip) }, { 0 } }; /* Forward */ extern unsigned int * db_lookup_i386_kreg( char *name, int *kregp); extern int db_i386_reg_value( struct db_variable * vp, db_expr_t * val, int flag, db_var_aux_param_t ap); extern void db_find_trace_symbols(void); extern int db_numargs( struct i386_frame *fp, task_t task); extern void db_nextframe( struct i386_frame **lfp, struct i386_frame **fp, db_addr_t *ip, int frame_type, thread_t thr_act); extern int _setjmp( jmp_buf_t * jb); /* * Machine register set. */ struct db_variable db_regs[] = { { "cs", (unsigned int *)&ddb_regs.cs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "ds", (unsigned int *)&ddb_regs.ds, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "es", (unsigned int *)&ddb_regs.es, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "fs", (unsigned int *)&ddb_regs.fs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "gs", (unsigned int *)&ddb_regs.gs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "ss", (unsigned int *)&ddb_regs.ss, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "eax",(unsigned int *)&ddb_regs.eax, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "ecx",(unsigned int *)&ddb_regs.ecx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "edx",(unsigned int *)&ddb_regs.edx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "ebx",(unsigned int *)&ddb_regs.ebx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "esp",(unsigned int *)&ddb_regs.uesp,db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "ebp",(unsigned int *)&ddb_regs.ebp, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "esi",(unsigned int *)&ddb_regs.esi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "edi",(unsigned int *)&ddb_regs.edi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "eip",(unsigned int *)&ddb_regs.eip, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }, { "efl",(unsigned int *)&ddb_regs.efl, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 } }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); unsigned int * db_lookup_i386_kreg( char *name, int *kregp) { register struct i386_kregs *kp; for (kp = i386_kregs; kp->name; kp++) { if (strcmp(name, kp->name) == 0) return((unsigned int *)((int)kregp + kp->offset)); } return(0); } int db_i386_reg_value( struct db_variable *vp, db_expr_t *valuep, int flag, db_var_aux_param_t ap) { extern char etext; unsigned int *dp = 0; db_expr_t null_reg = 0; register thread_t thr_act = ap->thr_act; if (db_option(ap->modif, 'u')) { if (thr_act == THREAD_NULL) { if ((thr_act = current_thread()) == THREAD_NULL) db_error("no user registers\n"); } if (thr_act == current_thread()) { if (IS_USER_TRAP(&ddb_regs, &etext)) dp = vp->valuep; } } else { if (thr_act == THREAD_NULL || thr_act == current_thread()) { dp = vp->valuep; } else { if (thr_act && (thr_act->continuation != THREAD_CONTINUE_NULL) && thr_act->kernel_stack) { int cpu; for (cpu = 0; cpu < real_ncpus; cpu++) { if (cpu_datap(cpu)->cpu_running == TRUE && cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) { dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) + (((unsigned int) vp->valuep) - (unsigned int) &ddb_regs)); break; } } if (dp == 0 && thr_act) dp = db_lookup_i386_kreg(vp->name, (unsigned int *)(STACK_IKS(thr_act->kernel_stack))); if (dp == 0) dp = &null_reg; } else if (thr_act && (thr_act->continuation != THREAD_CONTINUE_NULL)) { /* only EIP is valid */ if (vp->valuep == (unsigned int *) &ddb_regs.eip) { dp = (unsigned int *)(&thr_act->continuation); } else { dp = &null_reg; } } } } if (dp == 0) { int cpu; if (!db_option(ap->modif, 'u')) { for (cpu = 0; cpu < real_ncpus; cpu++) { if (cpu_datap(cpu)->cpu_running == TRUE && cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) { dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) + (((unsigned int) vp->valuep) - (unsigned int) &ddb_regs)); break; } } } if (dp == 0) { if (!thr_act || thr_act->machine.pcb == 0) db_error("no pcb\n"); dp = (unsigned int *)((unsigned int)(thr_act->machine.pcb->iss) + ((unsigned int)vp->valuep - (unsigned int)&ddb_regs)); } } if (flag == DB_VAR_SET) *dp = *valuep; else *valuep = *dp; return(0); } void db_find_trace_symbols(void) { db_expr_t value; boolean_t found_some; found_some = FALSE; if (db_value_of_name(CC_SYM_PREFIX "user_trap", &value)) { db_user_trap_symbol_value = (db_addr_t) value; found_some = TRUE; } if (db_value_of_name(CC_SYM_PREFIX "kernel_trap", &value)) { db_kernel_trap_symbol_value = (db_addr_t) value; found_some = TRUE; } if (db_value_of_name(CC_SYM_PREFIX "interrupt", &value)) { db_interrupt_symbol_value = (db_addr_t) value; found_some = TRUE; } if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) { db_return_to_iret_symbol_value = (db_addr_t) value; found_some = TRUE; } if (db_value_of_name(CC_SYM_PREFIX "syscall", &value)) { db_syscall_symbol_value = (db_addr_t) value; found_some = TRUE; } if (found_some) db_trace_symbols_found = TRUE; } /* * Figure out how many arguments were passed into the frame at "fp". */ int db_numargs_default = 5; int db_numargs( struct i386_frame *fp, task_t task) { int *argp; int inst; int args; extern char etext; argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task); if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext) args = db_numargs_default; else if (!DB_CHECK_ACCESS((int)argp, 4, task)) args = db_numargs_default; else { inst = db_get_task_value((int)argp, 4, FALSE, task); if ((inst & 0xff) == 0x59) /* popl %ecx */ args = 1; else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */ args = ((inst >> 16) & 0xff) / 4; else args = db_numargs_default; } return (args); } struct interrupt_frame { struct i386_frame *if_frame; /* point to next frame */ int if_retaddr; /* return address to _interrupt */ int if_unit; /* unit number */ int if_spl; /* saved spl */ int if_iretaddr; /* _return_to_{iret,iret_i} */ int if_edx; /* old sp(iret) or saved edx(iret_i) */ int if_ecx; /* saved ecx(iret_i) */ int if_eax; /* saved eax(iret_i) */ int if_eip; /* saved eip(iret_i) */ int if_cs; /* saved cs(iret_i) */ int if_efl; /* saved efl(iret_i) */ }; extern const char *trap_type[]; extern int TRAP_TYPES; /* * Figure out the next frame up in the call stack. * For trap(), we print the address of the faulting instruction and * proceed with the calling frame. We return the ip that faulted. * If the trap was caused by jumping through a bogus pointer, then * the next line in the backtrace will list some random function as * being called. It should get the argument list correct, though. * It might be possible to dig out from the next frame up the name * of the function that faulted, but that could get hairy. */ void db_nextframe( struct i386_frame **lfp, /* in/out */ struct i386_frame **fp, /* in/out */ db_addr_t *ip, /* out */ int frame_type, /* in */ thread_t thr_act) /* in */ { x86_saved_state32_t *iss32; struct interrupt_frame *ifp; task_t task = (thr_act != THREAD_NULL)? thr_act->task: TASK_NULL; switch(frame_type) { case TRAP: /* * We know that trap() has 1 argument and we know that * it is an (strcut x86_saved_state32_t *). */ iss32 = (x86_saved_state32_t *) db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task); if (iss32->trapno >= 0 && iss32->trapno < TRAP_TYPES) { db_printf(">>>>> %s trap at ", trap_type[iss32->trapno]); } else { db_printf(">>>>> trap (number %d) at ", iss32->trapno & 0xffff); } db_task_printsym(iss32->eip, DB_STGY_PROC, task); db_printf(" <<<<<\n"); *fp = (struct i386_frame *)iss32->ebp; *ip = (db_addr_t)iss32->eip; break; case INTERRUPT: if (*lfp == 0) { db_printf(">>>>> interrupt <<<<<\n"); goto miss_frame; } db_printf(">>>>> interrupt at "); ifp = (struct interrupt_frame *)(*lfp); *fp = ifp->if_frame; if (ifp->if_iretaddr == db_return_to_iret_symbol_value) { *ip = ((x86_saved_state32_t *)ifp->if_edx)->eip; } else *ip = (db_addr_t)ifp->if_eip; db_task_printsym(*ip, DB_STGY_PROC, task); db_printf(" <<<<<\n"); break; case SYSCALL: if (thr_act != THREAD_NULL && thr_act->machine.pcb) { iss32 = (x86_saved_state32_t *)thr_act->machine.pcb->iss; *ip = (db_addr_t)(iss32->eip); *fp = (struct i386_frame *)(iss32->ebp); } break; default: /* falling down for unknown case */ miss_frame: *ip = (db_addr_t) db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task); *lfp = *fp; *fp = (struct i386_frame *) db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task); break; } } void db_stack_trace_cmd( db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) { struct i386_frame *frame, *lastframe; x86_saved_state32_t *iss32; int *argp; db_addr_t callpc, lastcallpc; int frame_type; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; boolean_t trace_all_threads = FALSE; int thcount = 0; char *filename; int linenum; task_t task; thread_t th, top_act; int user_frame; int frame_count; jmp_buf_t *prev; jmp_buf_t db_jmp_buf; queue_entry_t act_list; if (!db_trace_symbols_found) db_find_trace_symbols(); { register char *cp = modif; register char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'T') { trace_all_threads = TRUE; trace_thread = TRUE; } if (c == 'u') kernel_only = FALSE; } } if (trace_all_threads) { if (!have_addr && !trace_thread) { have_addr = TRUE; trace_thread = TRUE; act_list = &(current_task()->threads); addr = (db_expr_t) queue_first(act_list); } else if (trace_thread) { if (have_addr) { if (!db_check_act_address_valid((thread_t)addr)) { if (db_lookup_task((task_t)addr) == -1) return; act_list = &(((task_t)addr)->threads); addr = (db_expr_t) queue_first(act_list); } else { act_list = &(((thread_t)addr)->task->threads); thcount = db_lookup_task_act(((thread_t)addr)->task, (thread_t)addr); } } else { th = db_default_act; if (th == THREAD_NULL) th = current_thread(); if (th == THREAD_NULL) { db_printf("no active thr_act\n"); return; } have_addr = TRUE; act_list = &th->task->threads; addr = (db_expr_t) queue_first(act_list); } } } if (count == -1) count = 65535; next_thread: top_act = THREAD_NULL; user_frame = 0; frame_count = count; if (!have_addr && !trace_thread) { frame = (struct i386_frame *)ddb_regs.ebp; callpc = (db_addr_t)ddb_regs.eip; th = current_thread(); task = (th != THREAD_NULL)? th->task: TASK_NULL; 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); } else if (trace_thread) { if (have_addr) { th = (thread_t) addr; if (!db_check_act_address_valid(th)) { return; } } else { th = db_default_act; if (th == THREAD_NULL) th = current_thread(); if (th == THREAD_NULL) { db_printf("no active thread\n"); return; } } if (trace_all_threads) db_printf("---------- Thread 0x%x (#%d of %d) ----------\n", addr, thcount, th->task->thread_count); next_activation: user_frame = 0; // 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); task = th->task; if (th == current_thread()) { frame = (struct i386_frame *)ddb_regs.ebp; callpc = (db_addr_t)ddb_regs.eip; } else { if (th->machine.pcb == 0) { db_printf("thread has no pcb\n"); return; } if (!th) { db_printf("thread has no shuttle\n"); goto thread_done; } else if ( (th->continuation != THREAD_CONTINUE_NULL) || th->kernel_stack == 0) { db_printf("Continuation "); db_task_printsym((db_expr_t)th->continuation, DB_STGY_PROC, task); db_printf("\n"); iss32 = (x86_saved_state32_t *)th->machine.pcb->iss; frame = (struct i386_frame *) (iss32->ebp); callpc = (db_addr_t) (iss32->eip); } else { int cpu; for (cpu = 0; cpu < real_ncpus; cpu++) { if (cpu_datap(cpu)->cpu_running == TRUE && cpu_datap(cpu)->cpu_active_thread == th && cpu_datap(cpu)->cpu_kdb_saved_state) { break; } } if (top_act != THREAD_NULL) { /* * Trying to get the backtrace of an activation * which is not the top_most one in the RPC chain: * use the activation's pcb. */ iss32 = (x86_saved_state32_t *)th->machine.pcb->iss; frame = (struct i386_frame *) (iss32->ebp); callpc = (db_addr_t) (iss32->eip); } else { if (cpu == real_ncpus) { register struct x86_kernel_state32 *iks; int r; iks = STACK_IKS(th->kernel_stack); prev = db_recover; if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { frame = (struct i386_frame *) (iks->k_ebp); callpc = (db_addr_t) (iks->k_eip); } else { /* * The kernel stack has probably been * paged out (swapped out activation). */ db_recover = prev; if (r == 2) /* 'q' from db_more() */ db_error(0); db_printf("\n", iks); goto thread_done; } db_recover = prev; } else { db_printf(">>>>> active on cpu %d <<<<<\n", cpu); iss32 = (x86_saved_state32_t *)cpu_datap(cpu)->cpu_kdb_saved_state; frame = (struct i386_frame *) (iss32->ebp); callpc = (db_addr_t) (iss32->eip); } } } } } else { frame = (struct i386_frame *)addr; th = (db_default_act)? db_default_act: current_thread(); task = (th != THREAD_NULL)? th->task: TASK_NULL; callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, 4, FALSE, (user_frame) ? task : 0); } if (!INKERNELSTACK((unsigned)frame, th)) { db_printf(">>>>> user space <<<<<\n"); if (kernel_only) goto thread_done; user_frame++; } lastframe = 0; lastcallpc = (db_addr_t) 0; while (frame_count-- && frame != 0) { int narg = DB_NUMARGS_MAX; char * name; db_expr_t offset; db_addr_t call_func = 0; int r; db_addr_t off; db_symbol_values(NULL, db_search_task_symbol_and_line( callpc, DB_STGY_XTRN, &offset, &filename, &linenum, (user_frame) ? task : 0, &narg), &name, (db_expr_t *)&call_func); if ( name == NULL) { db_find_task_sym_and_offset(callpc, &name, &off, (user_frame) ? task : 0); offset = (db_expr_t) off; } if (user_frame == 0) { if (call_func && call_func == db_user_trap_symbol_value || call_func == db_kernel_trap_symbol_value) { frame_type = TRAP; narg = 1; } else if (call_func && call_func == db_interrupt_symbol_value) { frame_type = INTERRUPT; goto next_frame; } else if (call_func && call_func == db_syscall_symbol_value) { frame_type = SYSCALL; goto next_frame; } else { frame_type = 0; prev = db_recover; if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { if (narg < 0) narg = db_numargs(frame, (user_frame) ? task : 0); db_recover = prev; } else { db_recover = prev; goto thread_done; } } } else { frame_type = 0; prev = db_recover; if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { if (narg < 0) narg = db_numargs(frame, (user_frame) ? task : 0); db_recover = prev; } else { db_recover = prev; goto thread_done; } } if (name == 0 || offset > db_maxoff) { db_printf("0x%x 0x%x(", frame, callpc); offset = 0; } else db_printf("0x%x %s(", frame, name); argp = &frame->f_arg0; while (narg > 0) { int value; prev = db_recover; if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) { value = db_get_task_value((int)argp, 4, FALSE, (user_frame) ? task : 0); } else { db_recover = prev; if (r == 2) /* 'q' from db_more() */ db_error(0); db_printf("... )"); if (offset) db_printf("+%x", offset); if (filename) { db_printf(" [%s", filename); if (linenum > 0) db_printf(":%d", linenum); db_printf("]"); } db_printf("\n"); goto thread_done; } db_recover = prev; db_printf("%x", value); argp++; if (--narg != 0) db_printf(","); } if (narg < 0) db_printf("..."); db_printf(")"); if (offset) { db_printf("+%x", offset); } if (filename) { db_printf(" [%s", filename); if (linenum > 0) db_printf(":%d", linenum); db_printf("]"); } db_printf("\n"); next_frame: lastcallpc = callpc; db_nextframe(&lastframe, &frame, &callpc, frame_type, (user_frame) ? th : THREAD_NULL); if (frame == 0) { if (th->task_threads.prev != THREAD_NULL) { if (top_act == THREAD_NULL) top_act = th; th = th->task_threads.prev; db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n", th, db_lookup_task(th->task), db_lookup_task_act(th->task, th)); goto next_activation; } /* end of chain */ break; } if (!INKERNELSTACK(lastframe, th) || !INKERNELSTACK((unsigned)frame, th)) user_frame++; if (user_frame == 1) { db_printf(">>>>> user space <<<<<\n"); if (kernel_only) break; } if (frame <= lastframe) { if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th))) continue; db_printf("Bad frame pointer: 0x%x\n", frame); break; } } thread_done: if (trace_all_threads) { if (top_act != THREAD_NULL) th = top_act; th = (thread_t) queue_next(&th->task_threads); if (! queue_end(act_list, (queue_entry_t) th)) { db_printf("\n"); addr = (db_expr_t) th; thcount++; goto next_thread; } } } extern int kdp_vm_read(caddr_t, caddr_t, unsigned int ); extern boolean_t kdp_trans_off; /* * Print out 256 bytes of real storage * * dr [entaddr] */ void db_display_real(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) { int i; unsigned int xbuf[8]; unsigned read_result = 0; /* Print 256 bytes */ for(i=0; i<8; i++) { /* * Do a physical read using kdp_vm_read(), rather than replicating the same * facility */ kdp_trans_off = 1; read_result = kdp_vm_read(addr, &xbuf[0], 32); kdp_trans_off = 0; if (read_result != 32) db_printf("Unable to read address\n"); else db_printf("%016llX %08X %08X %08X %08X %08X %08X %08X %08X\n", addr, /* Print a line */ xbuf[0], xbuf[1], xbuf[2], xbuf[3], xbuf[4], xbuf[5], xbuf[6], xbuf[7]); addr = addr + 0x00000020; /* Point to next address */ } db_next = addr; } /* * Displays all of the kmods in the system. * * dk */ void db_display_kmod(__unused db_expr_t addr, __unused boolean_t have_addr, __unused db_expr_t count, __unused char *modif) { kmod_info_t *kmd; unsigned int strt, end; kmd = kmod; /* Start at the start */ db_printf("info addr start - end name ver\n"); while (kmd) { /* Dump 'em all */ strt = (unsigned int) kmd->address + kmd->hdr_size; end = (unsigned int) kmd->address + kmd->size; db_printf("%08X %08X %08X - %08X: %s, %s\n", kmd, kmd->address, strt, end, kmd->name, kmd->version); kmd = kmd->next; } } void db_display_iokit(__unused db_expr_t addr, __unused boolean_t have_addr, __unused db_expr_t count, __unused char *modif) { }