+
+
+define resetstacks
+ _kgm_flush_loop
+ set kdp_pmap = 0
+ _kgm_flush_loop
+ resetctx
+ _kgm_flush_loop
+ _kgm_update_loop
+ resetctx
+ _kgm_update_loop
+end
+
+document resetstacks
+| Syntax: resetstacks
+| Internal kgmacro routine used by the "showuserstack" macro
+| to reset the target pmap to the kernel pmap.
+end
+
+#Barely effective hacks to work around bugs in the "flush" and "update"
+#gdb commands in Tiger (up to 219); these aren't necessary with Panther
+#gdb, but do no harm.
+define _kgm_flush_loop
+ set $kgm_flush_loop_ctr = 0
+ while ($kgm_flush_loop_ctr < 30)
+ flushregs
+ flushstack
+ set $kgm_flush_loop_ctr = $kgm_flush_loop_ctr + 1
+ end
+end
+
+define _kgm_update_loop
+ set $kgm_update_loop_ctr = 0
+ while ($kgm_update_loop_ctr < 30)
+ update
+ set $kgm_update_loop_ctr = $kgm_update_loop_ctr + 1
+ end
+end
+
+#This is necessary since gdb often doesn't do backtraces on x86 correctly
+#in the absence of symbols.The code below in showuserstack and
+#showx86backtrace also contains several workarouds for the gdb bug where
+#gdb stops macro evaluation because of spurious "Cannot read memory"
+#errors on x86. These errors appear on ppc as well, but they don't
+#always stop macro evaluation.
+
+set $kgm_cur_ebp = 0
+set $kgm_cur_eip = 0
+
+define showx86backtrace
+ if ($kgm_cur_ebp == 0)
+ set $kgm_cur_ebp = $ebp
+ end
+ if ($kgm_cur_eip == 0)
+ set $kgm_cur_eip = $eip
+ end
+ printf "0: EBP: 0x%08x EIP: 0x%08x\n", $kgm_cur_ebp, $kgm_cur_eip
+ x/i $kgm_cur_eip
+ set $kgm_prev_ebp = *((uint32_t *) $kgm_cur_ebp)
+ set $kgm_prev_eip = *((uint32_t *) ($kgm_cur_ebp + 4))
+ set $kgm_frameno = 1
+ while $kgm_prev_ebp != 0
+ printf "%d: saved EBP: 0x%08x saved EIP: 0x%08x\n", $kgm_frameno, $kgm_prev_ebp, $kgm_prev_eip
+ x/i $kgm_prev_eip
+ set $kgm_cur_ebp = $kgm_prev_ebp
+ set $kgm_prev_ebp = *((uint32_t *) $kgm_cur_ebp)
+ set $kgm_prev_eip = *((uint32_t *) ($kgm_cur_ebp + 4))
+ set $kgm_frameno = $kgm_frameno + 1
+ end
+ set $kgm_cur_ebp = 0
+ set $kgm_cur_eip = 0
+ set kdp_pmap = 0
+end
+
+define showuserstack
+ if ($kgm_mtype == 18)
+ if ($kdp_act_counter == 0)
+ set $kdpstate = (struct savearea *) kdp.saved_state
+ end
+ set $kdp_act_counter = $kdp_act_counter + 1
+ set $newact = (struct thread *) $arg0
+ _kgm_flush_loop
+ set $checkpc = $newact->machine->upcb.save_srr0
+ if ($checkpc == 0)
+ echo This activation does not appear to have
+ echo \20 a valid user context.\n
+ else
+ set (struct savearea *) kdp.saved_state=$newact->machine->upcb
+ set $pc = $checkpc
+#flush and update seem to be executed lazily by gdb on Tiger, hence the
+#repeated invocations - see 3743135
+ _kgm_flush_loop
+# This works because the new pmap is used only for reads
+ set kdp_pmap = $newact->task->map->pmap
+ _kgm_flush_loop
+ _kgm_update_loop
+ bt
+ resetstacks
+ _kgm_flush_loop
+ _kgm_update_loop
+ resetstacks
+ _kgm_flush_loop
+ _kgm_update_loop
+ end
+ else
+ set $newact = (struct thread *) $arg0
+ set $newiss = (x86_saved_state32_t *) ($newact->machine.pcb->iss)
+ set $checkpc = $newiss.eip
+ if ($checkpc == 0)
+ echo This activation does not appear to have
+ echo \20 a valid user context.\n
+ else
+ set $kgm_cur_ebp = $newiss.ebp
+ set $kgm_cur_eip = $checkpc
+ printf "You may now issue the showx86backtrace command to see the user space backtrace for this thread (0x%08x); you can also examine memory locations in this address space (pmap 0x%08x) before issuing the backtrace. This two-step process is necessary to work around various bugs in x86 gdb, which cause it to stop memory evaluation on spurious memory read errors. Additionally, you may need to issue a set kdp_pmap = 0 command after the showx86backtrace completes, to resume reading from the kernel address space.\n", $arg0, $newact->task->map->pmap
+ set kdp_pmap = $newact->task->map->pmap
+ _kgm_flush_loop
+ _kgm_update_loop
+ end
+ end
+end
+document showuserstack
+Syntax: showuserstack <address of thread activation>
+|This command displays a numeric backtrace for the user space stack of
+|the given thread activation. It may, of course, fail to display a
+|complete backtrace if portions of the user stack are not mapped in.
+|Symbolic backtraces can be obtained either by running gdb on the
+|user space binary, or a tool such as "symbolicate".
+|Note that while this command works on Panther's gdb, an issue
+|with Tiger gdb (3743135) appears to hamper the evaluation of this
+|macro in some cases.
+end
+
+#Stopgap until gdb can generate the HOSTREBOOT packet
+define kdp-reboot
+ set flag_kdp_trigger_reboot = 1
+ continue
+end
+
+document kdp-reboot
+Syntax: kdp-reboot
+|Reboot the remote target machine; not guaranteed to succeed. Requires symbols
+|until gdb support for the HOSTREBOOT packet is implemented.
+end
+
+define sendcore
+ set kdp_trigger_core_dump = 1
+ set kdp_flag |= 0x40
+ set panicd_ip_str = "$arg0"
+ set panicd_specified = 1
+ set disableDebugOuput = 0
+ set disableConsoleOutput = 0
+ set logPanicDataToScreen = 1
+ set reattach_wait = 1
+ resume_off
+end
+
+document sendcore
+Syntax: sendcore <IP address>
+|Configure the kernel to transmit a kernel coredump to a server (kdumpd)
+|at the specified IP address. This is useful when the remote target has
+|not been previously configured to transmit coredumps, and you wish to
+|preserve kernel state for later examination. NOTE: You must issue a "continue"
+|command after using this macro to trigger the kernel coredump. The kernel
+|will resume waiting in the debugger after completion of the coredump. You
+|may disable coredumps by executing the "disablecore" macro.
+end
+
+define disablecore
+ set kdp_trigger_core_dump = 0
+ set kdp_flag |= 0x40
+ set kdp_flag &= ~0x10
+ set panicd_specified = 0
+end
+
+document disablecore
+Syntax: disablecore
+|Reconfigures the kernel so that it no longer transmits kernel coredumps. This
+|complements the "sendcore" macro, but it may be used if the kernel has been
+|configured to transmit coredumps through boot-args as well.
+end
+
+#Use of this macro requires the gdb submission from 3401283
+define switchtocorethread
+ if ($kgm_mtype == 18)
+ if ($kdp_act_counter == 0)
+ set $kdpstate = (struct savearea *) kdp.saved_state
+ end
+ set $kdp_act_counter = $kdp_act_counter + 1
+ set $newact = (struct thread *) $arg0
+ if ($newact->kernel_stack == 0)
+ echo This thread does not have a stack.\n
+ echo continuation:
+ output/a (unsigned) $newact.continuation
+ echo \n
+ else
+ loadcontext $newact->machine->pcb
+# flushstack will be introduced in a gdb version > gdb-357
+ flushstack
+ set $pc = $newact->machine->pcb.save_srr0
+ end
+ else
+ echo switchtocorethread not implemented for this architecture.\n
+ end
+end
+
+document switchtocorethread
+Syntax: switchtocorethread <address of activation>
+| The corefile equivalent of "switchtoact". When debugging a kernel coredump
+| file, this command can be used to examine the execution context and stack
+| trace for a given thread activation. For example, to view the backtrace
+| for a thread issue "switchtocorethread <address>", followed by "bt".
+| Before resuming execution, issue a "resetcorectx" command, to
+| return to the original execution context. Note that this command
+| requires gdb support, as documented in Radar 3401283.
+end
+
+define loadcontext
+ set $pc = $arg0.save_srr0
+ set $r1 = $arg0.save_r1
+ set $lr = $arg0.save_lr
+
+ set $r2 = $arg0.save_r2
+ set $r3 = $arg0.save_r3
+ set $r4 = $arg0.save_r4
+ set $r5 = $arg0.save_r5
+ set $r6 = $arg0.save_r6
+ set $r7 = $arg0.save_r7
+ set $r8 = $arg0.save_r8
+ set $r9 = $arg0.save_r9
+ set $r10 = $arg0.save_r10
+ set $r11 = $arg0.save_r11
+ set $r12 = $arg0.save_r12
+ set $r13 = $arg0.save_r13
+ set $r14 = $arg0.save_r14
+ set $r15 = $arg0.save_r15
+ set $r16 = $arg0.save_r16
+ set $r17 = $arg0.save_r17
+ set $r18 = $arg0.save_r18
+ set $r19 = $arg0.save_r19
+ set $r20 = $arg0.save_r20
+ set $r21 = $arg0.save_r21
+ set $r22 = $arg0.save_r22
+ set $r23 = $arg0.save_r23
+ set $r24 = $arg0.save_r24
+ set $r25 = $arg0.save_r25
+ set $r26 = $arg0.save_r26
+ set $r27 = $arg0.save_r27
+ set $r28 = $arg0.save_r28
+ set $r29 = $arg0.save_r29
+ set $r30 = $arg0.save_r30
+ set $r31 = $arg0.save_r31
+
+ set $cr = $arg0.save_cr
+ set $ctr = $arg0.save_ctr
+end
+
+define resetcorectx
+ set $kgm_corecontext = (struct savearea *) kdp.saved_state
+ loadcontext $kgm_corecontext
+# Maintaining this act counter wouldn't be necessary if we just initialized
+# $kdpstate at the beginning of the macro..
+ set $kdp_act_counter = 0
+end
+
+document resetcorectx
+Syntax: resetcorectx
+| The corefile equivalent of "resetctx". Returns to the original
+| execution context (that of the active thread at the time of the NMI or
+| panic). This command should be issued if you wish to resume
+| execution after using the "switchtocorethread" command.
+end
+
+#Helper function for "showallgdbstacks"
+
+define showgdbthread
+ printf " 0x%08x ", $arg0
+ set $kgm_thread = *(struct thread *)$arg0
+ printf "0x%08x ", $arg0
+ printf "%3d ", $kgm_thread.sched_pri
+ set $kgm_state = $kgm_thread.state
+ if $kgm_state & 0x80
+ printf "I"
+ end
+ if $kgm_state & 0x40
+ printf "P"
+ end
+ if $kgm_state & 0x20
+ printf "A"
+ end
+ if $kgm_state & 0x10
+ printf "H"
+ end
+ if $kgm_state & 0x08
+ printf "U"
+ end
+ if $kgm_state & 0x04
+ printf "R"
+ end
+ if $kgm_state & 0x02
+ printf "S"
+ end
+ if $kgm_state & 0x01
+ printf "W\t"
+ printf "0x%08x ", $kgm_thread.wait_queue
+ output /a (unsigned) $kgm_thread.wait_event
+ end
+ if $arg1 != 0
+ if ($kgm_thread.kernel_stack != 0)
+ if ($kgm_thread.reserved_stack != 0)
+ printf "\n\t\treserved_stack=0x%08x", $kgm_thread.reserved_stack
+ end
+ printf "\n\t\tkernel_stack=0x%08x", $kgm_thread.kernel_stack
+ if ($kgm_mtype == 18)
+ set $mysp = $kgm_thread.machine.pcb->save_r1
+ else
+ set $kgm_statep = (struct x86_kernel_state32 *) \
+ ($kgm_thread->kernel_stack + 0x4000 \
+ - sizeof(struct x86_kernel_state32))
+ set $mysp = $kgm_statep->k_ebp
+ end
+ set $prevsp = 0
+ printf "\n\t\tstacktop=0x%08x", $mysp
+ switchtoact $arg0
+ bt
+ else
+ printf "\n\t\t\tcontinuation="
+ output /a (unsigned) $kgm_thread.continuation
+ end
+ printf "\n"
+ else
+ printf "\n"
+ end
+end
+
+#Use of this macro is currently (8/04) blocked by the fact that gdb
+#stops evaluating macros when encountering an error, such as a failure
+#to read memory from a certain location. Until this issue (described in
+#3758949) is addressed, evaluation of this macro may stop upon
+#encountering such an error.
+
+define showallgdbstacks
+ set $kgm_head_taskp = &default_pset.tasks
+ set $kgm_taskp = (struct task *)($kgm_head_taskp->next)
+ while $kgm_taskp != $kgm_head_taskp
+ showtaskheader
+ showtaskint $kgm_taskp
+ set $kgm_head_actp = &($kgm_taskp->threads)
+ set $kgm_actp = (struct thread *)($kgm_taskp->threads.next)
+ while $kgm_actp != $kgm_head_actp
+ showactheader
+ showgdbthread $kgm_actp 1
+ set $kgm_actp = (struct thread *)($kgm_actp->task_threads.next)
+ end
+ printf "\n"
+ set $kgm_taskp = (struct task *)($kgm_taskp->pset_tasks.next)
+ end
+ resetctx
+end
+
+document showallgdbstacks
+Syntax: showallgdbstacks
+| An alternative to "showallstacks". Iterates through the task list and
+| displays a gdb generated backtrace for each kernel thread. It is
+| advantageous in that it is much faster than "showallstacks", and
+| decodes function call arguments and displays source level traces, but
+| it has the drawback that it doesn't determine if frames belong to
+| functions from kernel extensions, as with "showallstacks".
+| This command may terminate prematurely because of a gdb bug
+| (Radar 3758949), which stops macro evaluation on memory read
+| errors.
+end
+
+define switchtouserthread
+ if ($kgm_mtype == 18)
+ if ($kdp_act_counter == 0)
+ set $kdpstate = (struct savearea *) kdp.saved_state
+ end
+ set $kdp_act_counter = $kdp_act_counter + 1
+ set $newact = (struct thread *) $arg0
+ _kgm_flush_loop
+ set $checkpc = $newact->machine->upcb.save_srr0
+ if ($checkpc == 0)
+ echo This activation does not appear to have
+ echo \20 a valid user context.\n
+ else
+ set (struct savearea *) kdp.saved_state=$newact->machine->upcb
+ set $pc = $checkpc
+#flush and update seem to be executed lazily by gdb on Tiger, hence the
+#repeated invocations - see 3743135
+ _kgm_flush_loop
+# This works because the new pmap is used only for reads
+ set kdp_pmap = $newact->task->map->pmap
+ _kgm_flush_loop
+ _kgm_update_loop
+ end
+ else
+ echo switchtouserthread not implemented for this architecture.\n
+ end
+end
+
+document switchtouserthread
+Syntax: switchtouserthread <address of thread>
+| Analogous to switchtoact, but switches to the user context of a
+| specified thread address. Similar to the "showuserstack"
+| command, but this command does not return gdb to the kernel context
+| immediately. This is to assist with the following (rather risky)
+| manoeuvre - upon switching to the user context and virtual address
+| space, the user may choose to call remove-symbol-file on the
+| mach_kernel symbol file, and then add-symbol-file on the user space
+| binary's symfile. gdb can then generate symbolic backtraces
+| for the user space thread. To return to the
+| kernel context and virtual address space, the process must be
+| reversed, i.e. call remove-symbol-file on the user space symbols, and
+| then add-symbol-file on the appropriate mach_kernel, and issue the
+| "resetstacks" command. Note that gdb may not react kindly to all these
+| symbol file switches. The same restrictions that apply to "showuserstack"
+| apply here - pages that have been paged out cannot be read while in the
+| debugger context, so backtraces may terminate early.
+| If the virtual addresses in the stack trace do not conflict with those
+| of symbols in the kernel's address space, it may be sufficient to
+| just do an add-symbol-file on the user space binary's symbol file.
+| Note that while this command works on Panther's gdb, an issue
+| with Tiger gdb (3743135) appears to hamper the evaluation of this
+| macro in some cases.
+end
+
+define showmetaclass
+ set $kgm_metaclassp = (OSMetaClass *)$arg0
+ printf "%-5d", $kgm_metaclassp->instanceCount
+ printf "x %5d bytes", $kgm_metaclassp->classSize
+ printf " %s\n", $kgm_metaclassp->className->string
+end
+
+define showstring
+ printf "\"%s\"", ((OSString *)$arg0)->string
+end
+
+define shownumber
+ printf "%lld", ((OSNumber *)$arg0)->value
+end
+
+define showboolean
+ if ($arg0 == gOSBooleanFalse)
+ printf "No"
+ else
+ printf "Yes"
+ end
+end
+
+define showdata
+ set $kgm_data = (OSData *)$arg0
+
+ printf "<"
+ set $kgm_datap = (const unsigned char *) $kgm_data->data
+
+ set $kgm_printstr = 0
+ if (0 == (3 & (unsigned int)$kgm_datap) && ($kgm_data->length >= 3))
+ set $kgm_bytes = *(unsigned int *) $kgm_datap
+ if (0xffff0000 & $kgm_bytes)
+ set $kgm_idx = 0
+ set $kgm_printstr = 1
+ while ($kgm_idx++ < 4)
+ set $kgm_bytes = $kgm_bytes >> 8
+ set $kgm_char = 0xff & $kgm_bytes
+ if ($kgm_char && (($kgm_char < 0x20) || ($kgm_char > 0x7e)))
+ set $kgm_printstr = 0
+ end
+ end
+ end
+ end
+
+ set $kgm_idx = 0
+ if ($kgm_printstr)
+ set $kgm_quoted = 0
+ while ($kgm_idx < $kgm_data->length)
+ set $kgm_char = $kgm_datap[$kgm_idx++]
+ if ($kgm_char)
+ if (0 == $kgm_quoted)
+ set $kgm_quoted = 1
+ if ($kgm_idx > 1)
+ printf ",\""
+ else
+ printf "\""
+ end
+ end
+ printf "%c", $kgm_char
+ else
+ if ($kgm_quoted)
+ set $kgm_quoted = 0
+ printf "\""
+ end
+ end
+ end
+ if ($kgm_quoted)
+ printf "\""
+ end
+ else
+ if (0 == (3 & (unsigned int)$kgm_datap))
+ while (($kgm_idx + 3) <= $kgm_data->length)
+ printf "%08x", *(unsigned int *) &$kgm_datap[$kgm_idx]
+ set $kgm_idx = $kgm_idx + 4
+ end
+ end
+ while ($kgm_idx < $kgm_data->length)
+ printf "%02x", $kgm_datap[$kgm_idx++]
+ end
+ end
+ printf ">"
+end
+
+define showdictionaryint
+ set $kgm$arg0_dict = (OSDictionary *)$arg1
+
+ printf "{"
+ set $kgm$arg0_idx = 0
+ while ($kgm$arg0_idx < $kgm$arg0_dict->count)
+ set $kgm_obj = $kgm$arg0_dict->dictionary[$kgm$arg0_idx].key
+ showobjectint _$arg0 $kgm_obj
+ printf "="
+ set $kgm_obj = $kgm$arg0_dict->dictionary[$kgm$arg0_idx++].value
+ showobjectint _$arg0 $kgm_obj
+ if ($kgm$arg0_idx < $kgm$arg0_dict->count)
+ printf ","
+ end
+ end
+ printf "}"
+end
+
+define indent
+ set $kgm_idx = 0
+ while ($kgm_idx < $arg0)
+ if ($arg1 & (1 << $kgm_idx++))
+ printf "| "
+ else
+ printf " "
+ end
+ end
+end
+
+define showregdictionary
+ indent $kgm_reg_depth+2 $arg1
+ printf "{\n"
+
+ set $kgm_reg_idx = 0
+ while ($kgm_reg_idx < $arg0->count)
+ indent $kgm_reg_depth+2 $arg1
+ printf " "
+ set $kgm_obj = $arg0->dictionary[$kgm_reg_idx].key
+ showobjectint _ $kgm_obj
+ printf " = "
+
+ set $kgm_obj = $arg0->dictionary[$kgm_reg_idx++].value
+ showobjectint _ $kgm_obj
+ printf "\n"
+ end
+ indent $kgm_reg_depth+2 $arg1
+ printf "}\n"
+end
+
+
+define showarraysetint
+ set $kgm$arg0_array = (OSArray *)$arg1
+
+ set $kgm$arg0_idx = 0
+ while ($kgm$arg0_idx < $kgm$arg0_array->count)
+ set $kgm_obj = $kgm$arg0_array->array[$kgm$arg0_idx++]
+ showobjectint _$arg0 $kgm_obj
+ if ($kgm$arg0_idx < $kgm$arg0_array->count)
+ printf ","
+ end
+ end
+end
+
+define showarrayint
+ printf "("
+ showarraysetint $arg0 $arg1
+ printf ")"
+end
+
+define showsetint
+ set $kgm_array = ((OSSet *)$arg1)->members
+ printf "["
+ showarraysetint $arg0 $kgm_array
+ printf "]"
+end
+
+
+define showobjectint
+ set $kgm_obj = (OSObject *) $arg1
+ set $kgm_vt = *((void **) $arg1)
+
+ if ($kgm_show_object_addrs)
+ printf "`object %p, vt ", $arg1
+ output /a (unsigned) $kgm_vt
+ if ($kgm_show_object_retain)
+ printf ", retain count %d, container retain %d", (0xffff & $kgm_obj->retainCount), $kgm_obj->retainCount >> 16
+ end
+ printf "` "
+ end
+
+ if ($kgm_vt == _ZTV8OSString)
+ showstring $arg1
+ else
+ if ($kgm_vt == _ZTV8OSSymbol)
+ showstring $arg1
+ else
+ if ($kgm_vt == _ZTV8OSNumber)
+ shownumber $arg1
+ else
+ if ($kgm_vt == _ZTV6OSData)
+ showdata $arg1
+ else
+ if ($kgm_vt == _ZTV9OSBoolean)
+ showboolean $arg1
+ else
+ if ($kgm_vt == _ZTV12OSDictionary)
+ showdictionaryint _$arg0 $arg1
+ else
+ if ($kgm_vt == _ZTV7OSArray)
+ showarrayint _$arg0 $arg1
+ else
+ if ($kgm_vt == _ZTV5OSSet)
+ showsetint _$arg0 $arg1
+ else
+ if ($kgm_show_object_addrs == 0)
+ printf "`object %p, vt ", $arg1
+ output /a (unsigned) $kgm_vt
+ printf "`"
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+define showobject
+ set $kgm_save = $kgm_show_object_addrs
+ set $kgm_show_object_addrs = 1
+ set $kgm_show_object_retain = 1
+ showobjectint _ $arg0
+ set $kgm_show_object_addrs = $kgm_save
+ set $kgm_show_object_retain = 0
+ printf "\n"
+end
+document showobject
+| Show info about an OSObject - its vtable ptr and retain count.
+| If the object is a simple container class, more info will be shown.
+| The following is the syntax:
+| (gdb) showobject <object address>
+end
+
+define dictget
+ set $kgm_dictp = (OSDictionary *)$arg0
+ set $kgm_keyp = (const OSSymbol *)$arg1
+ set $kgm_idx = 0
+ set $kgm_result = 0
+ while (($kgm_idx < $kgm_dictp->count) && ($kgm_result == 0))
+ if ($kgm_keyp == $kgm_dictp->dictionary[$kgm_idx].key)
+ set $kgm_result = $kgm_dictp->dictionary[$kgm_idx].value
+ end
+ set $kgm_idx = $kgm_idx + 1
+ end
+end
+
+
+define showregistryentryrecurse
+ set $kgm_re = (IOService *)$arg1
+ set $kgm$arg0_stack = (unsigned long long) $arg2
+
+ if ($arg3)
+ set $kgm$arg0_stack = $kgm$arg0_stack | (1ULL << $kgm_reg_depth)
+ else
+ set $kgm$arg0_stack = $kgm$arg0_stack & ~(1ULL << $kgm_reg_depth)
+ end
+
+ dictget $kgm_re->fRegistryTable $kgm_childkey
+ set $kgm$arg0_child_array = (OSArray *) $kgm_result
+
+ if ($kgm$arg0_child_array)
+ set $kgm$arg0_child_count = $kgm$arg0_child_array->count
+ else
+ set $kgm$arg0_child_count = 0
+ end
+
+ if ($kgm$arg0_child_count)
+ set $kgm$arg0_stack = $kgm$arg0_stack | (2ULL << $kgm_reg_depth)
+ else
+ set $kgm$arg0_stack = $kgm$arg0_stack & ~(2ULL << $kgm_reg_depth)
+ end
+
+ indent $kgm_reg_depth $kgm$arg0_stack
+ printf "+-o "
+
+ dictget $kgm_re->fRegistryTable $kgm_namekey
+ if ($kgm_result == 0)
+ dictget $kgm_re->fRegistryTable gIONameKey
+ end
+ if ($kgm_result == 0)
+ dictget $kgm_re->fPropertyTable gIOClassKey
+ end
+
+ if ($kgm_result != 0)
+ printf "%s", ((OSString *)$kgm_result)->string
+ else
+ if (((IOService*)$kgm_re)->pm_vars && ((IOService*)$kgm_re)->pm_vars->ourName)
+ printf "%s", ((IOService*)$kgm_re)->pm_vars->ourName
+ else
+# printf ", guessclass "
+# guessclass $kgm_re
+ printf "??"
+ end
+ end
+
+
+ printf " <object %p, ", $kgm_re
+ printf "vtable "
+ set $kgm_vt = (unsigned) *(void**) $kgm_re
+ output /a $kgm_vt
+
+ if ($kgm_vt != _ZTV15IORegistryEntry)
+ printf ", "
+ set $kgm_state = $kgm_re->__state[0]
+ # kIOServiceRegisteredState
+ if (0 == ($kgm_state & 2))
+ printf "!"
+ end
+ printf "registered, "
+ # kIOServiceMatchedState
+ if (0 == ($kgm_state & 4))
+ printf "!"
+ end
+ printf "matched, "
+ # kIOServiceInactiveState
+ if ($kgm_state & 1)
+ printf "in"
+ end
+ printf "active, busy %d, retain count %d", (0xff & $kgm_re->__state[1]), (0xffff & $kgm_re->retainCount)
+ end
+ printf ">\n"
+
+ if ($kgm_show_props)
+ set $kgm_props = $kgm_re->fPropertyTable
+ showregdictionary $kgm_props $kgm$arg0_stack
+ end
+
+ # recurse
+ if ($kgm$arg0_child_count != 0)
+
+ set $kgm_reg_depth = $kgm_reg_depth + 1
+ set $kgm$arg0_child_idx = 0
+
+ while ($kgm$arg0_child_idx < $kgm$arg0_child_count)
+ set $kgm_re = $kgm$arg0_child_array->array[$kgm$arg0_child_idx++]
+ set $kgm_more_sib = ($kgm$arg0_child_idx < $kgm$arg0_child_count)
+ showregistryentryrecurse _$arg0 $kgm_re $kgm$arg0_stack $kgm_more_sib
+ end
+
+ set $kgm_reg_depth = $kgm_reg_depth - 1
+ end
+end
+
+define showregistryentryint
+ set $kgm_namekey = (OSSymbol *) $kgm_reg_plane[2]
+ set $kgm_childkey = (OSSymbol *) $kgm_reg_plane[4]
+
+ showregistryentryrecurse _ $arg0 0 0
+end
+
+define showregistry
+ set $kgm_reg_depth = 0
+ set $kgm_show_props = 0
+ showregistryentryint gRegistryRoot
+end
+document showregistry
+| Show info about all registry entries in the current plane.
+| The following is the syntax:
+| (gdb) showregistry
+end
+
+define showregistryprops
+ set $kgm_reg_depth = 0
+ set $kgm_show_props = 1
+ showregistryentryint gRegistryRoot
+end
+document showregistryprops
+| Show info about all registry entries in the current plane, and their properties.
+| set $kgm_show_object_addrs = 1 and/or set $kgm_show_object_retain = 1 will display
+| more verbose information
+| The following is the syntax:
+| (gdb) showregistryprops
+end
+
+define showregistryentry
+ set $kgm_reg_depth = 0
+ set $kgm_show_props = 1
+ showregistryentryint $arg0
+end
+document showregistryentry
+| Show info about a registry entry; its properties and descendants in the current plane.
+| The following is the syntax:
+| (gdb) showregistryentry <object address>
+end
+
+define setregistryplane
+ if ($arg0)
+ set $kgm_reg_plane = (void **) $arg0
+ else
+ showobjectint _ gIORegistryPlanes
+ printf "\n"
+ end
+end
+document setregistryplane
+| Set the plane to be used for the iokit registry macros. An argument of zero will
+| display known planes.
+| The following is the syntax:
+| (gdb) setregistryplane <plane object address>
+end
+
+define guessclass
+ set $kgm_classidx = 0
+ set $kgm_lookvt = *((void **) $arg0)
+ set $kgm_bestvt = (void *) 0
+ set $kgm_bestidx = 0
+
+ while $kgm_classidx < sAllClassesDict->count
+ set $kgm_meta = (OSMetaClass *) sAllClassesDict->dictionary[$kgm_classidx].value
+
+ set $kgm_vt = *((void **) $kgm_meta)
+
+ if (($kgm_vt > $kgm_bestvt) && ($kgm_vt < $kgm_lookvt))
+ set $kgm_bestvt = $kgm_vt
+ set $kgm_bestidx = $kgm_classidx
+ end
+ set $kgm_classidx = $kgm_classidx + 1
+ end
+ printf "%s", sAllClassesDict->dictionary[$kgm_bestidx].key->string
+end
+
+define showallclasses
+ set $kgm_classidx = 0
+ while $kgm_classidx < sAllClassesDict->count
+ set $kgm_meta = (OSMetaClass *) sAllClassesDict->dictionary[$kgm_classidx++].value
+ showmetaclass $kgm_meta
+ end
+end
+
+document showallclasses
+| Show the instance counts and ivar size of all OSObject subclasses. See ioclasscount man page for details.
+| The following is the syntax:
+| (gdb) showallclasses
+end
+
+define showioalloc
+ printf " Instance allocation = 0x%08lx = %4ld K\n", (int) debug_ivars_size, ((int) debug_ivars_size) / 1024
+ printf "Container allocation = 0x%08lx = %4ld K\n", (int) debug_container_malloc_size, ((int) debug_container_malloc_size) / 1024
+ printf " IOMalloc allocation = 0x%08lx = %4ld K\n", (int) debug_iomalloc_size, ((int) debug_iomalloc_size) / 1024
+ printf " Pageable allocation = 0x%08lx = %4ld K\n", (vm_size_t) debug_iomallocpageable_size, ((vm_size_t) debug_iomallocpageable_size) / 1024
+end
+
+document showioalloc
+| Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
+| The following is the syntax:
+| (gdb) showioalloc
+end
+
+define readphys
+ set kdp_trans_off = 1
+ x/x $arg0
+ set kdp_trans_off = 0
+end
+
+define readphys64
+ if ($kgm_mtype == 18)
+ set kdp_src_high32 = ((uint32_t) ($arg0)) >> 32
+ x/x (uint32_t) (($arg0) & 0x00000000ffffffffUL)
+ set kdp_src_high32 = 0
+ else
+ echo readphys64 not available on this architecture.\n
+ end
+end
+
+document readphys
+| The argument is interpreted as a physical address, and the word addressed is
+| displayed. While this fails if no physical page exists at the given address,
+| it must be used with caution.
+end
+
+document readphys64
+| The argument is interpreted as a 64-bit physical address, and the word
+| addressed is displayed. While this fails if no physical page exists at the
+| given address, it must be used with caution.
+end