blob: 1bb1f7af94018f0d33608def5c74180e96148559 [file] [log] [blame]
# $FreeBSD: src/tools/debugscripts/gdbinit.kernel,v 1.8 2004/11/20 02:32:42 das Exp $
# General kernel macros
# Macros
set $TDI_SUSPENDED=0x1
set $TDI_SLEEPING=0x2
set $TDI_SWAPPED=0x4
set $TDI_LOCK=0x8
set $TDI_IWAIT=0x10
set $TDF_SINTR=0x8
# TID_MAX is a wild guess
set $PID_MAX=99999
set $TID_MAX=999999
set $P_CONTROLT=0x2
set $P_PPWAIT=0x10
set $P_HADTHREADS=0x80
set $P_SYSTEM=0x200
set $P_TRACED=0x800
set $P_WEXIT=0x02000
set $P_STOPPED_SIG=0x20000
set $P_STOPPED_TRACE=0x40000
set $P_STOPPED_SINGLE=0x80000
set $P_STOPPED=($P_STOPPED_SIG|$P_STOPPED_TRACE|$P_STOPPED_SINGLE)
set $PS_INMEM=0x1
set $MTX_UNOWNED=4
set $VV_ROOT=0x0001
set $VV_TEXT=0x0020
set $VV_SYSTEM=0x0080
set $VI_DOOMED=0x0080
set $VI_FREE=0x0100
set $CTLTYPE=0xf
set $CTLTYPE_NODE=1
set $LK_WAITDRAIN=0x00080000
# Number of chars output by %p
set $PTRWIDTH=(sizeof(void *)*2+2)
# Print the command name of the current process
define pname
p (char *)curproc->p_comm
end
document pname
Print the command name of the current process.
end
# Show contents of bp supplied as first parameter:
#
# (gdb) bpp bp
define bpp
set $bp = (struct buf *) $arg0
if $bp->b_io.bio_dev
printf " Buffer at 0x%x: dev 0x%x data 0x%x bcount 0x%x blkno 0x%x resid 0x%x\n", \
$bp, \
$bp->b_io.bio_dev->si_udev, \
$bp->b_io.bio_data, \
$bp->b_io.bio_bcount, \
$bp->b_io.bio_blkno, \
$bp->b_io.bio_resid
else
printf " Buffer at 0x%x: dev (none) data 0x%x bcount 0x%x blkno 0x%x resid 0x%x\n", \
$bp, \
$bp->b_io.bio_data, \
$bp->b_io.bio_bcount, \
$bp->b_io.bio_blkno, \
$bp->b_io.bio_resid
end
printf " flags 0x%x: ", $bp->b_flags
if $bp->b_flags & 0x10
printf "busy "
end
if $bp->b_flags & 0x40
printf "call "
end
if $bp->b_flags & 0x200
printf "done "
end
if $bp->b_flags & 0x800
printf "error "
end
if $bp->b_flags & 0x40000
printf "phys "
end
if $bp->b_flags & 0x100000
printf "read "
end
printf "\n"
end
document bpp
Show summary information about the buffer header (struct bp) pointed at by the parameter.
end
# Show more detailed contents of bp supplied as first parameter:
#
# (gdb) bpl bp
define bpl
set $bp = (struct buf *) $arg0
printf "b_proc: "
output $bp->b_proc
printf "\nb_flags: "
output $bp->b_flags
printf "\nb_qindex: "
output $bp->b_qindex
printf "\nb_usecount: "
output $bp->b_usecount
printf "\nb_error: "
output $bp->b_error
printf "\nb_bufsize: "
output $bp->b_bufsize
printf "\nb_io.bio_bcount: "
output $bp->b_io.bio_bcount
printf "\nb_io.bio_resid: "
output $bp->b_io.bio_resid
printf "\nb_io.bio_dev: "
output $bp->b_io.bio_dev
printf "\nb_io.bio_data: "
output $bp->b_io.bio_data
printf "\nb_kvasize: "
output $bp->b_kvasize
printf "\nb_lblkno: "
output $bp->b_lblkno
printf "\nb_io.bio_blkno: "
output $bp->b_io.bio_blkno
printf "\nb_iodone: "
output $bp->b_iodone
printf "\nb_vp: "
output $bp->b_vp
printf "\nb_dirtyoff: "
output $bp->b_dirtyoff
printf "\nb_dirtyend: "
output $bp->b_dirtyend
printf "\nb_generation: "
output $bp->b_generation
printf "\nb_rcred: "
output $bp->b_rcred
printf "\nb_wcred: "
output $bp->b_wcred
printf "\nb_validoff: "
output $bp->b_validoff
printf "\nb_validend: "
output $bp->b_validend
printf "\nb_pblkno: "
output $bp->b_pblkno
printf "\nb_saveaddr: "
output $bp->b_saveaddr
printf "\nb_savekva: "
output $bp->b_savekva
printf "\nb_driver1: "
output $bp->b_driver1
printf "\nb_driver2: "
output $bp->b_driver2
printf "\nb_spc: "
output $bp->b_spc
printf "\nb_npages: "
output $bp->b_npages
printf "\n"
end
document bpl
Show detailed information about the buffer header (struct bp) pointed at by the parameter.
end
# Show contents of buffer header in local variable bp.
define bp
bpp bp
end
document bp
Show information about the buffer header pointed to by the variable bp in the current frame.
end
# Show data of buffer header in local variable bp as string.
define bpd
printf "Buffer data:\n%s", (char *) bp->b_io.bio_data
end
document bpd
Show the contents (char*) of bp->data in the current frame.
end
document bpl
Show detailed information about the buffer header (struct bp) pointed at by the local variable bp.
end
define bx
printf "\n b_vnbufs "
output/x bp->b_vnbufs
printf "\n b_freelist "
output/x bp->b_freelist
printf "\n b_act "
output/x bp->b_act
printf "\n b_flags "
output/x bp->b_flags
printf "\n b_qindex "
output/x bp->b_qindex
printf "\n b_usecount "
output/x bp->b_usecount
printf "\n b_error "
output/x bp->b_error
printf "\n b_bufsize "
output/x bp->b_bufsize
printf "\n b_io.bio_bcount "
output/x bp->b_io.bio_bcount
printf "\n b_io.bio_resid "
output/x bp->b_io.bio_resid
printf "\n b_io.bio_dev "
output/x bp->b_io.bio_dev
printf "\n b_io.bio_data "
output/x bp->b_io.bio_data
printf "\n b_kvasize "
output/x bp->b_kvasize
printf "\n b_io.bio_blkno "
output/x bp->b_io.bio_blkno
printf "\n b_iodone_chain "
output/x bp->b_iodone_chain
printf "\n b_vp "
output/x bp->b_vp
printf "\n b_dirtyoff "
output/x bp->b_dirtyoff
printf "\n b_validoff "
output/x bp->b_validoff
echo \n
end
document bx
Print a number of fields from the buffer header pointed at in by the pointer bp in the current environment.
end
# Switch back to ddb
define ddb
set boothowto=0x80000000
s
end
document ddb
Switch back to ddb.
end
# ps: equivalent of the userland command
define ps
set $nproc = nprocs
set $aproc = allproc.lh_first
set $proc = allproc.lh_first
printf " pid proc uid ppid pgrp flag stat comm wchan\n"
while (--$nproc >= 0)
set $pptr = $proc.p_pptr
if ($pptr == 0)
set $pptr = $proc
end
if ($proc.p_state)
set $thread = $proc->p_threads.tqh_first
while ($thread)
printf "%5d %08x %4d %5d %5d %06x %d %-10s ", \
$proc.p_pid, $aproc, \
$proc.p_ucred->cr_ruid, $pptr->p_pid, \
$proc.p_pgrp->pg_id, $proc.p_flag, $proc.p_state, \
&$proc.p_comm[0]
if ($thread.td_wchan)
if ($thread.td_wmesg)
printf "%s ", $thread.td_wmesg
end
printf "%x", $thread.td_wchan
end
printf "\n"
set $thread = $thread->td_plist.tqe_next
end
end
set $aproc = $proc.p_list.le_next
if ($aproc == 0 && $nproc > 0)
set $aproc = zombproc
end
set $proc = $aproc
end
end
document ps
Show process status without options.
end
# Specify a process for other commands to refer to.
# Most are machine-dependent.
define defproc
set $nproc = nprocs
set $aproc = allproc.lh_first
set $proc = allproc.lh_first
while (--$nproc >= 0)
if ($proc->p_pid == $arg0)
set $pptr = $proc.p_pptr
if ($pptr == 0)
set $pptr = $proc
end
set $myvectorproc = $proc
if ($proc.p_state)
set $thread = $proc->p_threads.tqh_first
while ($thread)
printf "%5d %08x %08x %4d %5d %5d %06x %d %-10s ", \
$proc.p_pid, $aproc, \
$proc.p_uarea, $proc.p_ucred->cr_ruid, $pptr->p_pid, \
$proc.p_pgrp->pg_id, $proc.p_flag, $proc.p_state, \
&$proc.p_comm[0]
if ($thread.td_wchan)
if ($thread.td_wmesg)
printf "%s ", $thread.td_wmesg
end
printf "%x", $thread.td_wchan
end
printf "\n"
set $thread = $thread->td_plist.tqe_next
end
end
btpp
set $nproc = 0
else
set $proc = $proc.p_list.le_next
end
end
end
document defproc
Specify a process for btpp and fr commands.
end
define vdev
if (vp->v_type == VBLK)
p *vp->v_un.vu_spec.vu_specinfo
printf "numoutput: %d\n", vp->v_numoutput
else
echo "Not a block device"
end
end
document vdev
Show some information of the vnode pointed to by the local variable vp.
end
# Kludge. When changing macros, it's convenient to copy and paste
# definitions from the editor into the debugger window.
# Unfortunately, gdb insists on asking for confirmation after the
# "define" line. y enables you to insert the confirmation in the
# definition without affecting the way the macro runs (much).
define y
echo Check your .gdbinit: it contains a y command\n
end
document y
Kludge for writing macros This is a no-op except for printing a message See gdb(4) for more details.
end
# dmesg: print msgbuf. Can take forever.
define dmesg
printf "%s", msgbufp->msg_ptr
end
document dmesg
Print the system message buffer (dmesg) This can take a long time due to the time it takes to transmit the data across a serial line and even on a firewire connection the processing time slows it down
end
# checkmem: check unallocated memory for modifications
# this assumes that DIAGNOSTIC is set, which causes
# free memory to be set to 0xdeadc0de
#
# Use: checkmem offset length
define checkmem
set $offset = $arg0
# XXX sizeof int. Needs changing for 64 bit machines.
# subtract 1 because the last word is always different.
set $length = $arg1 / 4 - 1
set $word = 0
while ($word < $length)
if ((int *) $offset) [$word] != 0xdeadc0de
printf "invalid word 0x%x at 0x%x\n", ((int *) $offset) [$word], &((int *) $offset) [$word]
end
set $word = $word + 1
end
end
document checkmem
Check unallocated memory for modifications This assumes that DIAGNOSTIC is set which causes free memory to be set to 0xdeadc0de.
end
define kernel
exec-file kernel.$arg0
symbol-file symbols.$arg0
core-file vmcore.$arg0
end
define kldstat
set $kld = linker_files.tqh_first
printf "Id Refs Address Size Name\n"
while ($kld != 0)
printf "%2d %4d 0x%08x %-8x %s\n", \
$kld->id, $kld->refs, $kld->address, $kld->size, $kld->filename
set $kld = $kld->link.tqe_next
end
end
document kldstat
Lists the modules that were loaded when the kernel crashed.
end
define kldstat-v
set $kld = linker_files.tqh_first
printf "Id Refs Address Size Name\n"
while ($kld != 0)
printf "%2d %4d 0x%08x %-8x %s\n", \
$kld->id, $kld->refs, $kld->address, $kld->size, $kld->filename
printf " Contains modules:\n"
printf " Id Name\n"
set $module = $kld->modules.tqh_first
while ($module != 0)
printf " %2d %s\n", $module->id, $module->name
set $module = $module->link.tqe_next
end
set $kld = $kld->link.tqe_next
end
end
# Lookup a process specified via $arg0. We first check to see if it
# is a valid PID, if not, we assume it is a pointer to a struct proc.
# If it looks like a PID, we walk the process lists to find it. The
# proc pointer is returned in $arg1.
define lookup_proc
set $_pid = (int)$arg0
set $arg1 = (struct proc *)$arg0
if ($_pid <= $PID_MAX)
set $_zomb = 0
set $_p = allproc.lh_first
while ($_p)
if ($_p->p_pid == $_pid)
set $arg1 = $_p
set $_p = 0
else
set $_p = $_p->p_list.le_next
if ($_p == 0 && $_zomb == 0)
set $_p = zombproc.lh_first
set $_zomb = 1
end
end
end
end
end
# Lookup a thread specified via $arg0. We walk all the processes and threads
# looking to see if $arg0 specifies a valid TID. In addition, if $arg2 is
# non-zero, then we will check to see if it's a valid PID as well, and if so
# we return the first thread in the process with that PID. If it is not a
# valid tid, then we assume $arg0 is a thread pointer and leave it alone.
# The thread pointer is returned in $arg1.
define lookup_thread
set $_id = (int)$arg0
set $arg1 = (struct thread *)$arg0
if ($_id <= $TID_MAX)
set $_zomb = 0
set $_p = allproc.lh_first
while ($_p)
if ($arg2 && $_p->p_pid == $_id)
set $arg1 = $_p->p_threads.tqh_first
set $_p = 0
else
set $_td = $_p->p_threads.tqh_first
while ($_td)
if ($_td->td_tid == $_id)
set $arg1 = $_td
set $_td = 0
set $_p = 0
else
set $_td = $_td->td_plist.tqe_next
end
end
if ($_p)
set $_p = $_p->p_list.le_next
if ($_p == 0 && $_zomb == 0)
set $_p = zombproc.lh_first
set $_zomb = 1
end
end
end
end
end
end
# formatting helper
# spaces <count>
define spaces
set $_count = $arg0
while (--$_count >= 0)
printf " "
end
end
# dumpthread <td> <all>
# ps helper to display info about a thread
define dumpthread
if ($arg1)
set $x = 0
printf " %9d ", $arg0->td_tid
if ($arg0->td_state == TDS_RUNNING)
printf " Run "
set $x = 1
end
if ($arg0->td_state == TDS_RUNQ)
printf " RunQ "
set $x = 1
end
if ($arg0->td_state == TDS_CAN_RUN)
printf " CanRun "
set $x = 1
end
if ($arg0->td_state == TDS_INACTIVE)
printf " Inactv "
set $x = 1
end
if ($arg0->td_state == TDS_INHIBITED)
printf " "
set $i = 6
if ($arg0->td_inhibitors & $TDI_LOCK)
printf "L"
set $i = $i - 1
end
if ($arg0->td_inhibitors & $TDI_SLEEPING)
if ($arg0->td_flags & $TDF_SINTR)
printf "S"
set $i = $i - 1
else
printf "D"
set $i = $i - 1
end
end
if ($arg0->td_inhibitors & $TDI_SWAPPED)
printf "W"
set $i = $i - 1
end
if ($arg0->td_inhibitors & $TDI_IWAIT)
printf "I"
set $i = $i - 1
end
if ($arg0->td_inhibitors & $TDI_SUSPENDED)
printf "s"
set $i = $i - 1
end
while ($i != 0)
printf " "
set $i = $i - 1
end
printf " "
set $x = 1
end
if ($x == 0)
printf " ??? "
end
end
if ($arg0->td_inhibitors & $TDI_LOCK)
printf "*%-8.8s %p ", $arg0->td_lockname, $arg0->td_blocked
else
if ($arg0->td_wchan != 0)
printf " %-8.8s %p ", $arg0->td_wmesg, $arg0->td_wchan
else
if ($arg0->td_state == TDS_RUNNING)
printf " CPU %2d ", $arg0->td_oncpu
else
printf " "
end
spaces $PTRWIDTH
printf " "
end
end
if ($arg0->td_proc->p_flag & $P_SYSTEM)
printf "["
end
printf "%s", $arg0->td_proc->p_comm
if ($arg0->td_proc->p_flag & $P_SYSTEM)
printf "]"
end
printf "\n"
end
document dumpthread
Show one-line summary of a thread's state.
end
# procstate <p>
# Helper function for 'ps' to dump process state string
define procstate
# First determine the primary process state
if ($arg0->p_state == PRS_NORMAL)
if ($arg0->p_flag & $P_STOPPED)
printf "T"
else
set $rflag = 0
set $sflag = 0
set $dflag = 0
set $lflag = 0
set $wflag = 0
set $td = $arg0->p_threads.tqh_first
while ($td != 0)
if ($td->td_state == TDS_RUNNING || \
$td->td_state == TDS_RUNQ || $td->td_state == TDS_CAN_RUN)
set $rflag = $rflag + 1
end
if ($td->td_inhibitors & $TDI_LOCK)
set $lflag = $lflag + 1
end
if ($td->td_inhibitors & $TDI_SLEEPING)
if ($td->td_flags & $TDF_SINTR)
set $sflag = $sflag + 1
else
set $dflag = $dflag + 1
end
end
if ($td->td_inhibitors & $TDI_IWAIT)
set $wflag = $wflag + 1
end
set $td = $td->td_plist.tqe_next
end
if ($rflag)
printf "R"
else
if ($lflag)
printf "L"
else
if ($dflag)
printf "D"
else
if ($sflag)
printf "S"
else
if ($wflag)
printf "W"
else
printf "?"
end
end
end
end
end
end
else
if ($arg0->p_state == PRS_NEW)
printf "N"
else
if ($arg0->p_state == PRS_ZOMBIE)
printf "Z"
else
printf "U"
end
end
end
# Extra states
set $i = 5
if (!($arg0->p_sflag & $PS_INMEM))
printf "W"
set $i = $i - 1
end
if ($arg0->p_flag & $P_TRACED)
printf "X"
set $i = $i - 1
end
if ($arg0->p_flag & $P_WEXIT && $arg0->p_state != PRS_ZOMBIE)
printf "E"
set $i = $i - 1
end
if ($arg0->p_flag & $P_PPWAIT)
printf "V"
set $i = $i - 1
end
if ($arg0->p_flag & $P_SYSTEM || $p->p_lock > 0)
printf "L"
set $i = $i - 1
end
if ($arg0->p_pgrp != 0 && $arg0->p_pgrp->pg_session != 0 && \
$arg0->p_pgrp->pg_session->s_leader == $arg0 && $i > 0)
printf "s"
set $i = $i - 1
end
if ($arg0->p_flag & $P_CONTROLT && $i > 0)
printf "+"
set $i = $i - 1
end
if ($arg0->p_ucred != 0 && $arg0->p_ucred->cr_prison != 0 && $i > 0)
printf "J"
set $i = $i - 1
end
while ($i != 0)
printf " "
set $i = $i - 1
end
end
# dumpproc <proc>
# ps helper to dump info about a given process
define dumpproc
set $pp = $arg0.p_pptr
if ($pp == 0)
set $pp = $arg0
end
if ($arg0.p_ucred == 0)
set $uid = 0
else
set $uid = $arg0.p_ucred->cr_ruid
end
if ($arg0.p_pgrp == 0)
set $pgid = 0
else
set $pgid = $arg0.p_pgrp->pg_id
end
printf "%5d %5d %5d %5d ", $arg0.p_pid, $pp->p_pid, $pgid, $uid
printf " "
procstate $arg0
printf " "
set $x = $arg0.p_flag & $P_HADTHREADS
if ($x)
printf " (threaded) %s\n", $arg0.p_comm
end
set $td = $arg0.p_threads.tqh_first
while ($td != 0)
dumpthread $td $x
set $td = $td->td_plist.tqe_next
end
end
# qps: "quick" ps skips any single threaded procs that are asleep
define qps
set $nproc = nprocs
set $p = allproc.lh_first
printf " pid ppid pgrp uid state wmesg "
set $foo = ($PTRWIDTH - 5) / 2
spaces $foo
printf "wchan"
set $foo = $PTRWIDTH - 5 - $foo
spaces $foo
printf " cmd\n"
while (--$nproc >= 0)
set $td = $p->p_threads.tqh_first
if ($p.p_flag & $P_HADTHREADS || $td->td_state != TDS_INHIBITED || $td->td_inhibitors & $TDI_LOCK)
dumpproc $p
end
set $p = $p.p_list.le_next
if ($p == 0 && $nproc > 0)
set $p = zombproc.lh_first
end
end
end
document qps
Show process status of non-idle processes without options.
end
define mtx_owner
if (((struct mtx *)$arg0)->mtx_lock == $MTX_UNOWNED)
printf "unowned\n"
else
set $td = (struct thread *)(((struct mtx *)$arg0)->mtx_lock & ~0x3)
printf "td: %p\n", $td
printf "pid: %d, p_comm: %s\n", $td->td_proc->p_pid, \
$td->td_proc->p_comm
end
end
document mtx_owner
Displays the owner of a given mutex
end
define lockchain
set $count = 20
lookup_thread $arg0 $td 1
while ($td != 0)
printf " thread %d (pid %d, %s) ", $td->td_tid, $td->td_proc->p_pid, \
$td->td_proc->p_comm
if ($td->td_state == TDS_INHIBITED)
if ($td->td_inhibitors & $TDI_LOCK)
set $ts = $td->td_blocked
set $lock = $ts->ts_lockobj
printf "blocked on lock %p \"%s\"\n", $lock, $lock->lo_name
set $td = $ts->ts_owner
if ($td == $arg0 || --$count == 0)
printf " DEADLOCK\n"
set $td = 0
end
else
printf "inhibited\n"
set $td = 0
end
else
if ($td->td_state == TDS_INACTIVE)
printf "is inactive\n"
else
if ($td->td_state == TDS_CAN_RUN)
printf "can run\n"
else
if ($td->td_state == TDS_RUNQ)
printf "is on a run queue\n"
else
if ($td->td_state == TDS_RUNNING)
printf "running on CPU %d\n", $td->td_oncpu
else
printf "unknown state!\n"
end
end
end
end
set $td = 0
end
end
end
document lockchain
Displays the chain of contested locks a thread is blocked on
end
define allchains
set $p = allproc.lh_first
set $i = 1
while ($p != 0)
set $td2 = $p->p_threads.tqh_first
while ($td2 != 0)
if ($td2->td_inhibitors & $TDI_LOCK && \
$td2->td_contested.lh_first == 0)
printf "chain %d:\n", $i
lockchain $td2
set $i = $i + 1
end
set $td2 = $td2->td_plist.tqe_next
end
set $p = $p->p_list.le_next
end
end
document allchains
Displays all the contested lock thread chains in the system
end
# printpcpu <struct pcpu *>
# helper function for pcpu and allpcpu
define printpcpu
printf "cpuid = %d\n", $arg0->pc_cpuid
printf "curthread = "
if ($arg0->pc_curthread != 0)
printf "%p: pid %d \"%s\"\n", $arg0->pc_curthread, \
$arg0->pc_curthread->td_proc->p_pid, \
$arg0->pc_curthread->td_proc->p_comm
else
printf "none\n"
end
printf "curpcb = %p\n", $arg0->pc_curpcb
printf "fpcurthread = "
if ($arg0->pc_fpcurthread != 0)
printf "%p: pid %d \"%s\"\n", $arg0->pc_fpcurthread, \
$arg0->pc_fpcurthread->td_proc->p_pid, \
$arg0->pc_fpcurthread->td_proc->p_comm
else
printf "none\n"
end
printf "idlethread = "
if ($arg0->pc_idlethread != 0)
printf "%p: pid %d \"%s\"\n", $arg0->pc_idlethread, \
$arg0->pc_idlethread->td_proc->p_pid, \
$arg0->pc_idlethread->td_proc->p_comm
else
printf "none\n"
end
end
define pcpu
set $p = cpuhead.slh_first
while ($p != 0)
if ($p->pc_cpuid == $arg0)
printpcpu $p
set $p = 0
else
set $p = $p->pc_allcpu.sle_next
end
end
end
document pcpu
Display per-CPU information for a specified CPU.
end
define allpcpu
set $p = cpuhead.slh_first
while ($p != 0)
printpcpu $p
printf "\n"
set $p = $p->pc_allcpu.sle_next
end
end
document allpcpu
Display per-CPU information for all CPUs.
end
define lockmgr_owner
if (((struct lock *)$arg0)->lk_exclusivecount != 0)
set $td = ((struct lock *)$arg0)->lk_lockholder
printf "td: %p\n", $td
printf "pid: %d, p_comm: %s\n", $td->td_proc->p_pid, \
$td->td_proc->p_comm
end
if (((struct lock *)$arg0)->lk_sharecount != 0)
printf "share count: %d\n", ((struct lock *)$arg0)->lk_sharecount
end
end
document lockmgr_owner
Displays the owner of a given lockmgr lock
end
# vtypename <type>
# helper function for vprint
define vtypename
if ($arg0 == VNON)
printf "VNON"
else
if ($arg0 == VREG)
printf "VREG"
else
if ($arg0 == VDIR)
printf "VDIR"
else
if ($arg0 == VBLK)
printf "VBLK"
else
if ($arg0 == VCHR)
printf "VCHR"
else
if ($arg0 == VLNK)
printf "VLNK"
else
if ($arg0 == VSOCK)
printf "VSOCK"
else
if ($arg0 == VFIFO)
printf "VFIFO"
else
if ($arg0 == VBAD)
printf "VBAD"
else
if ($arg0 == VMARKER)
printf "VMARKER"
else
printf "V??:%d", $arg0
end
end
end
end
end
end
end
end
end
end
end
# vprint <vp>
# helper function to dump info about a vnode
define vprint
set $vp = (struct vnode *)$arg0
printf "%p: ", $vp
printf "tag %s, type ", $vp->v_tag
vtypename $vp->v_type
printf "\n"
printf " usecount %d, writecount %d, refcount %d mountedhere %p\n", \
$vp->v_usecount, $vp->v_writecount, $vp->v_holdcnt, $vp->v_un.vu_mount
printf " flags ("
set $_pipe = 0
if ($vp->v_vflag & $VV_ROOT)
printf "VV_ROOT"
set $_pipe = 1
end
if ($vp->v_vflag & $VV_TEXT)
if ($_pipe)
printf "|"
end
printf "VV_TEXT"
set $_pipe = 1
end
if ($vp->v_vflag & $VV_SYSTEM)
if ($_pipe)
printf "|"
end
printf "VV_SYSTEM"
set $_pipe = 1
end
if ($vp->v_iflag & $VI_DOOMED)
if ($_pipe)
printf "|"
end
printf "VI_DOOMED"
set $_pipe = 1
end
if ($vp->v_iflag & $VI_FREE)
if ($_pipe)
printf "|"
end
printf "VI_FREE"
set $_pipe = 1
end
printf ")"
if ($vp->v_interlock.mtx_lock != $MTX_UNOWNED)
printf " VI_LOCKed"
end
printf "\n"
set $_vobj = $vp->v_bufobj.bo_object
if ($_vobj != 0)
printf " v_object %p ref %d pages %d\n", $_vobj, $_vobj->ref_count, \
$_vobj->resident_page_count
end
printf " "
# lockmgr_printinfo()
set $_lkp = $vp->v_vnlock
if ($_lkp->lk_sharecount)
printf "lock type %s: SHARED (count %d)", $_lkp->lk_wmesg, \
$_lkp->lk_sharecount
else
if ($_lkp->lk_exclusivecount)
printf "lock type %s: EXCL (count %d) by thread %p (pid %d)", \
$_lkp->lk_wmesg, $_lkp->lk_exclusivecount, \
$_lkp->lk_lockholder, $_lkp->lk_lockholder->td_proc->p_pid
else
printf "lock type %s: UNLOCKED", $_lkp->lk_wmesg
end
end
if ($_lkp->lk_waitcount > 0)
printf " with %d pending", $_lkp->lk_waitcount
end
printf "\n"
# XXX: no VOP_PRINT
end
define lockedvnodes
printf "Locked vnodes\n"
set $mp = mountlist.tqh_first
while ($mp != 0)
set $lvp = $mp->mnt_nvnodelist.tqh_first
while ($lvp != 0)
if ($lvp->v_type != VMARKER && \
($lvp->v_vnlock->lk_exclusivecount != 0 || \
$lvp->v_vnlock->lk_sharecount != 0))
vprint $lvp
end
set $lvp = $lvp->v_nmntvnodes.tqe_next
end
set $mp = $mp->mnt_list.tqe_next
end
end
document lockedvnodes
List all of the locked vnodes in the system
end
# helper functions for sleepchain, return success or failure in $arg1 and
# if ok, owner in $arg2, $arg0 is thread
define lk_chain
set $lkp = (struct lock *)$arg0->td_wchan
# imperfect test to see if the wchan is a lockmgr lock maybe
if ($lkp->lk_wmesg != $arg0->td_wmesg)
# it might be sleeping on &lkp->lk_flags during a drain
set $lkp = (struct lock *)((char *)$lkp - (int)(&((struct lock *)0)->lk_flags))
if ($lkp->lk_wmesg != $arg0->td_wmesg || !($lkp->lk_flags & $LK_WAITDRAIN))
set $lkp = 0
end
end
if ($lkp)
set $arg1 = 1
printf "blocked on lk \"%s\" ", $lkp->lk_wmesg
if ($lkp->lk_sharecount)
printf "SHARED (count %d)", $lkp->lk_sharecount
set $arg2 = 0
else
printf "EXCL (count %d)", $lkp->lk_exclusivecount
set $arg2 = $lkp->lk_lockholder
end
else
set $arg1 = 0
end
end
define sx_chain
set $cv = (struct cv *)$arg0->td_wchan
if ($cv->cv_description == $arg0->td_wmesg)
set $sx = (struct sx *)((char *)$cv - (int)(&((struct sx *)0)->sx_excl_cv))
if ($sx->sx_object.lo_class != &lock_class_sx || $sx->sx_excl_wcnt == 0)
set $sx = (struct sx *)((char *)$cv - (int)(&((struct sx *)0)->sx_shrd_cv))
if ($sx->sx_object.lo_class != &lock_class_sx || $sx->sx_shrd_wcnt == 0)
set $sx = 0
end
end
if ($sx)
set $arg1 = 1
printf "blocked on sx \"%s\" ", $arg0->td_wmesg
if ($sx->sx_cnt >= 0)
printf "SLOCK (count %d)", $sx->sx_cnt
set $arg2 = 0
else
printf "XLOCK"
set $arg2 = $sx->sx_xholder
end
else
set $arg1 = 0
end
else
set $arg1 = 0
end
end
define sleepchain
set $count = 20
lookup_thread $arg0 $td 1
while ($td != 0)
printf " thread %d (pid %d, %s) ", $td->td_tid, $td->td_proc->p_pid, \
$td->td_proc->p_comm
if ($td->td_wchan != 0)
lk_chain $td $ok $owner
if ($ok == 0)
sx_chain $td $ok $owner
end
if ($ok != 0)
set $td = $owner
if ($td == $arg0 || --$count == 0)
printf "\n DEADLOCK"
set $td = 0
end
else
printf "non-lock sleep"
set $td = 0
end
else
set $td = 0
end
printf "\n"
end
end
document sleepchain
Like lockchain but for sleep locks
end
# sysctl_oid name namelen
define sysctl_oid
set $oid = sysctl__children.slh_first
set $index = 0
while ($oid != 0 && $index < $arg1)
if ($oid->oid_number == $arg0[$index])
set $index = $index + 1
printf "%6d: %s\n", $oid->oid_number, $oid->oid_name
if (($oid->oid_kind & $CTLTYPE) == $CTLTYPE_NODE)
if ($oid->oid_handler != 0)
set $oid = 0
else
set $oid = ((struct sysctl_oid_list *)$oid->oid_arg1)->slh_first
end
else
set $oid = 0
end
else
set $oid = $oid->oid_link.sle_next
end
end
end
document sysctl_oid
Try to lookup the name of a sysctl OID.
end
define memstat
printf "%8d K Active (%2d%%)\n", cnt.v_active_count * cnt.v_page_size / 1024, cnt.v_active_count * 100 / cnt.v_page_count
printf "%8d K Inact (%2d%%)\n", cnt.v_inactive_count * cnt.v_page_size / 1024, cnt.v_inactive_count * 100 / cnt.v_page_count
printf "%8d K Wired (%2d%%)\n", cnt.v_wire_count * cnt.v_page_size / 1024, cnt.v_wire_count * 100 / cnt.v_page_count
printf "%8d K Cache (%2d%%)\n", cnt.v_cache_count * cnt.v_page_size / 1024, cnt.v_cache_count * 100 / cnt.v_page_count
printf "%8d K Buf\n", bufspace / $div
printf "%8d K Free (%2d%%)\n", cnt.v_free_count * cnt.v_page_size / 1024, cnt.v_free_count * 100 / cnt.v_page_count
end
document memstat
Show top-like memory usage summary
end
define swapinfo
printf "Device 1K-blocks Used Avail Capacity\n"
set $swp = swtailq.tqh_first
while ($swp != 0)
if ($swp->sw_dev == 0)
printf "%-15s", "<NFSfile>"
else
printf "/dev/%-10s", $swp->sw_vp->v_un.vu_cdev->si_name
end
printf " %9u", $swp->sw_nblks * (4096 / 1024)
printf " %8u", $swp->sw_used * (4096 / 1024)
printf " %8u", ($swp->sw_nblks - $swp->sw_used) * (4096 / 1024)
printf " %5.0f%c\n", ($swp->sw_used * 100.0 ) / $swp->sw_nblks, '%'
set $swp = $swp->sw_list.tqe_next
end
end
document swapinfo
Output similar to swapinfo(8)
end
define devstate
if ($arg0->state == DS_NOTPRESENT)
printf "NOT PRESENT"
else
if ($arg0->state == DS_ALIVE)
printf "ALIVE "
else
if ($arg0->state == DS_ATTACHED)
printf "ATTACHED "
else
if ($arg0->state == DS_BUSY)
printf "BUSY: %-5d", $arg0->busy
else
printf "???: %-6d", $arg0->state
end
end
end
end
end
# List device info as <name:20> <state:11> <softc> <ivars>
define lsdev
printf " name state "
set $foo = ($PTRWIDTH - 5) / 2
set $bar = $PTRWIDTH - 5 - $foo
spaces $foo
printf "softc"
spaces $bar
printf " "
spaces $foo
printf "ivars\n"
set $foo = $PTRWIDTH - 4
set $dev = bus_data_devices->tqh_first
while ($dev != 0)
if ($dev->nameunit)
printf "%-20s ", $dev->nameunit
else
printf "(null) "
end
devstate $dev
if ($dev->softc)
printf " %p", $dev->softc
else
printf " NULL"
spaces $foo
end
if ($dev->ivars)
printf " %p", $dev->ivars
else
printf " NULL"
spaces $foo
end
printf "\n"
set $dev = $dev->devlink.tqe_next
end
end
document lsdev
Show new-bus devices.
end
# Show the new-bus device tree
define devinfo
set $indent = 0
set $dev = root_bus
set $ignore = 0
while ($dev != 0)
if ($dev->nameunit != 0 && $ignore == 0)
spaces $indent
printf "%s\n", $dev->nameunit
end
if ($dev->children.tqh_first != 0 && $ignore == 0)
set $dev = $dev->children.tqh_first
set $indent = $indent + 1
set $ignore = 0
else
if ($dev->link.tqe_next != 0)
set $dev = $dev->link.tqe_next
set $ignore = 0
else
set $indent = $indent - 1
set $dev = $dev->parent
set $ignore = 1
end
end
end
end
document devinfo
Show new-bus heirarchy similar to devinfo(8).
end
#
# Show threads of a process
#
#
define showthread
set $_p=allproc.lh_first
while ( $_p != 0 )
if ($_p->p_pid == $arg0)
printf "process %d is %s\n", $_p->p_pid, $_p->p_comm
set $_thread=$_p->p_threads.tqh_first
while ($_thread != 0)
print $_thread
set $_thread=$_thread->td_plist.tqe_next
set $_p=0
end
end
if ($_p != 0)
set $_p=$_p->p_list.le_next
end
end
end
document showthread
Using process [pid] show the threads of the process
end
#
# Show all associations that have locks held
#
#
define sctp_allasocs_wlock
set $_inp=sctppcbinfo.listhead.lh_first
while ( $_inp != 0 )
set $_asoc=$_inp->sctp_asoc_list.lh_first
while ( $_asoc != 0)
if ($_asoc->tcb_mtx->mtx_lock != $MTX_UNOWNED)
print $_asoc
set $_sctp_mtx=&$_asoc->tcb_mtx
mtx_owner $_sctp_mtx
end
set $_asoc=$_asoc->sctp_tcblist.le_next
end
set $_inp=$_inp->sctp_list.le_next
end
end
document sctp_allasocs_wlock
Show all SCTP associations that are locked and their owners
end
#
# Show all vmstat info on malloc'd data you
# must pass the number of CPU's as an argument
#
define vmstat_malloc
set $meml=(struct malloc_type *)kmemstatistics
set $totalmem=0
while ( $meml != 0 )
set $mtip=(struct malloc_type_internal *)$meml->ks_handle
set $cpunum=0
set $used=0
set $usedmem=0
while ( $cpunum < $arg0 )
set $used=($used + $mtip->mti_stats[$cpunum].mts_numallocs-$mtip->mti_stats[$cpunum].mts_numfrees)
set $usedmem=($usedmem + $mtip->mti_stats[$cpunum].mts_memalloced-$mtip->mti_stats[$cpunum].mts_memfreed)
set $cpunum=$cpunum+1
end
printf "location %p cnt:%8d inusemem:%8d\n", \
$meml, $used, $usedmem
set $totalmem=$totalmem + $usedmem
set $meml=$meml->ks_next
end
printf "Total memory used in malloc is %d\n", $totalmem
end
document vmstat_malloc
Show memory zone statistics argument is the number of cpu's on the machine.
end
#
# Show all vmstat zone printing helper
#
define vmstat_print_zones
set $kz=$arg0
set $z=$kz->uk_zones->lh_first
set $total_items=0
while ( $z != 0 )
set $num_frees=$z->uz_frees
set $num_allocs=$z->uz_allocs
set $cache_free=0
set $cpu_index=0
while ( $cpu_index < mp_ncpus)
set $num_frees=$num_frees+$z->uz_cpu[$cpu_index].uc_frees
set $num_allocs=$num_allocs+$z->uz_cpu[$cpu_index].uc_allocs
if ( $z->uz_cpu[$cpu_index].uc_freebucket != 0 )
set $cache_free=$cache_free+$z->uz_cpu[$cpu_index].uc_freebucket.ub_cnt
end
if ( $z->uz_cpu[$cpu_index].uc_allocbucket != 0 )
set $cache_free=$cache_free+$z->uz_cpu[$cpu_index].uc_allocbucket.ub_cnt
end
set $cpu_index=$cpu_index + 1
end
if ( $num_allocs >= $num_frees )
set $in_use=$num_allocs - $num_frees
else
set $in_use=-1
end
set $freebucket=$z->uz_full_bucket->lh_first
while ($freebucket != 0 )
set $cache_free=$cache_free+$freebucket->ub_cnt
set $freebucket=$freebucket->ub_link.le_next
end
printf "zone:%p pages:%6d keg_free:%5d size:%5d in-use:%10d cachefree:%10d fail:%6d\n", \
$z, \
$kz->uk_pages, \
$kz->uk_free, \
$kz->uk_rsize, \
$in_use, \
$cache_free, \
$z->uz_fails
set $total_items=$total_items + $cache_free + $in_use
set $z=$z->uz_link->le_next
end
set $total_items=$total_items+$kz->uk_free
if ($kz->uk_rsize < 4096)
set $itm_per_page=$kz->uk_ipers
set $one_minus=$itm_per_page-1
set $total_items=$total_items+$one_minus
set $page_amount=$total_items/$itm_per_page
else
set $page_amount=$total_items*$kz->uk_ppera
end
if ( $page_amount != $kz->uk_pages )
printf "This zone has %d pages allocated, but only shows %d in use/cache - debug please\n", $kz->uk_pages, $page_amount
print $kz
end
end
document vmstat_print_zones
vmstat_zones helper
end
#
# Show all vmstat zone information like
# vmstat -z
#
define vmstat_zone
set $_kz=uma_kegs->lh_first
set $mem_used=0
set $pag_used=0
set $_cpucnt=mp_ncpus
while ( $_kz != 0 )
vmstat_print_zones $_kz
set $mem_used=$mem_used + ($_kz->uk_pages * 4096)
set $pag_used=$pag_used + $_kz->uk_pages
set $_kz=$_kz->uk_link.le_next
end
printf "Total page bytes in use %d\n", $mem_used
printf "Total pages in use %d\n", $pag_used
end
document vmstat_zone
prints vm-zone prints out vm_zone information
end