diff options
Diffstat (limited to 'tools/debugscripts')
-rw-r--r-- | tools/debugscripts/README | 21 | ||||
-rw-r--r-- | tools/debugscripts/dot.gdbinit | 117 | ||||
-rw-r--r-- | tools/debugscripts/gdbinit.i386 | 376 | ||||
-rw-r--r-- | tools/debugscripts/gdbinit.kernel | 370 | ||||
-rw-r--r-- | tools/debugscripts/kgdb | 67 | ||||
-rw-r--r-- | tools/debugscripts/kld_deb.py | 142 |
6 files changed, 1093 insertions, 0 deletions
diff --git a/tools/debugscripts/README b/tools/debugscripts/README new file mode 100644 index 0000000..2081531 --- /dev/null +++ b/tools/debugscripts/README @@ -0,0 +1,21 @@ +$FreeBSD$ + +This directory contains gdb macros for kernel debugging. When you +build a debug kernel, the target "gdbinit" in the kernel Makefile will +create the correct .gdbinit files in the kernel build directory. To +perform kernel debugging, you would do: + + # cd /usr/obj/usr/src/sys/GENERIC (or name of kernel config) + # make gdbinit + # gdb kernel.debug + This GDB was configured as "i386-undermydesk-freebsd"... + Ready to go. Enter 'tr' to connect to remote target + and 'getsyms' after connection to load kld symbols. + (kgdb) + + +This directory also contains a kgdb script that given a crash dump number +automatically extract the path to the kernel source, run gdb to extract +information about kernel modules loaded, and then rerun gdb loading the +necessary symbols for the modules. You need to make sure you build the +modules w/ debugging symbols separately to get things to work. diff --git a/tools/debugscripts/dot.gdbinit b/tools/debugscripts/dot.gdbinit new file mode 100644 index 0000000..1a340c0 --- /dev/null +++ b/tools/debugscripts/dot.gdbinit @@ -0,0 +1,117 @@ +# $FreeBSD$ +# .gdbinit file for remote serial debugging. +# +# XXX Do not use this file directly. It contains parameters which are +# XXX substituted by the kernel Makefile when you do a 'make gdbinit'. +# XXX This also removes lines starting with '# XXX'. +# XXX +# To debug kernels, do: +# +# cd /usr/obj/usr/src/sys/GENERIC (or kernel build directory) +# make gdbinit +# gdb kernel.debug +# +# Read gdb(4) for more details. + +# The following lines (down to "***** End" comment) may need to be changed + +# Bit rate for serial link. Due to problems in the interface, +# this may not work well above 9600 bps. +set remotebaud 9600 + +set output-radix 16 +set height 70 +set width 120 +set remotetimeout 1 +set complaints 1 +set print pretty +dir ../../.. + +# ***** End of things you're likely to need to change. + +# Connect to remote target via a serial port. +define tr +# Remote debugging port +target remote $arg0 +end + +document tr +Debug a remote system via serial or firewire interface. For example, specify 'tr /dev/cuau0' to use first serial port, or 'tr localhost:5556' for default firewire port. See also tr0, tr1 and trf commands. +end + +# Convenience functions. These call tr. +# debug via cuau0 +define tr0 +tr /dev/cuau0 +end +define tr1 +tr /dev/cuau1 +end +# Firewire +define trf +tr localhost:5556 +end + +document tr0 +Debug a remote system via serial interface /dev/cuau0. See also tr, tr1 and trf commands. +end +document tr1 +Debug a remote system via serial interface /dev/cuau1. See also tr, tr0 and trf commands. +end +document trf +Debug a remote system via firewire interface at default port 5556. See also tr, tr0 and tr1 commands. +end + +# Get symbols from klds. Unfortunately, there are a number of +# landmines involved here: +# +# When debugging the same machine (via /dev/mem), we can get the +# script to call kldstat and pass the info on to asf(8). This won't +# work for crashes or remote debugging, of course, because we'd get +# the information for the wrong system. Instead, we use the macro +# "kldstat", which extracts the information from the "dump". The +# trouble here is that it's a pain to use, since gdb doesn't have the +# capability to pass data to scripts, so we have to mark it and paste +# it into the script. This makes it silly to use this method for +# debugging the local system. Instead, we have two scripts: +# +# getsyms uses the information in the "dump", and you have to paste it. +# kldsyms uses the local kld information. +# +# Improvements in gdb should make this go away some day. +# +define kldsyms +# This will be replaced by the path of the real modules directory. +shell asf -f -k MODPATH +source .asf +end +document kldsyms +Read in the symbol tables for the debugging machine. This only makes sense when debugging /dev/mem; use the 'getsyms' macro for remote debugging. +end + +# Remote system +define getsyms +kldstat +echo Select the list above with the mouse, paste into the screen\n +echo and then press ^D. Yes, this is annoying.\n +# This will be replaced by the path of the real modules directory. +shell asf -f MODPATH +source .asf +end + +document getsyms +Display kldstat information for the target machine and invite user to paste it back in. This causes the symbols for the KLDs to be loaded. When doing memory debugging, use the command kldsyms instead. +end + +source gdbinit.kernel +source gdbinit.machine + +echo Ready to go. Enter 'tr' to connect to the remote target\n +echo with /dev/cuau0, 'tr /dev/cuau1' to connect to a different port\n +echo or 'trf portno' to connect to the remote target with the firewire\n +echo interface. portno defaults to 5556.\n +echo \n +echo Type 'getsyms' after connection to load kld symbols.\n +echo \n +echo If you're debugging a local system, you can use 'kldsyms' instead\n +echo to load the kld symbols. That's a less obnoxious interface.\n diff --git a/tools/debugscripts/gdbinit.i386 b/tools/debugscripts/gdbinit.i386 new file mode 100644 index 0000000..95dbf6e --- /dev/null +++ b/tools/debugscripts/gdbinit.i386 @@ -0,0 +1,376 @@ +# $FreeBSD$ +# Assembler-level macros for i386 +# Disassemble the next 10 instructions. +define xi +x/10i $eip +end + +# Top 12 words on stack +define xs +x/12x $esp +end + +# Top 12 words from frame pointer +define xb +x/12x $ebp +end + +# single step through calls and disassemble the next instruction +define z +ni +x/1i $eip +end + +# single step over calls and disassemble the next instruction +define zs +si +x/1i $eip +end + +# show current stack frame and first 4 parameters +define xp +printf " esp: " +output/x $esp +echo ( +output (((int)$ebp)-(int)$esp)/4-4 +printf " words on stack)\n ebp: " +output/x $ebp +printf "\n eip: " +x/1i $eip +printf "Saved ebp: " +output/x *(int*)$ebp +printf " (maximum of " +output ((*(int*)$ebp)-(int)$ebp)/4-4 +printf " parameters possible)\nSaved eip: " +x/1i *(int*)($ebp+4) +printf "\nParm 1 at " +output/x (int) ($ebp+8) +printf ": " +output (char*) *(int*)($ebp+8) +printf "\nParm 2 at " +output/x (int) ($ebp+12) +printf ": " +output (char*) *(int*)($ebp+12) +printf "\nParm 3 at " +output/x (int) ($ebp+16) +printf ": " +output (char*) *(int*)($ebp+16) +printf "\nParm 4 at " +output/x (int) ($ebp+20) +printf ": " +output (char*) *(int*)($ebp+20) +echo \n +end +document xp +Show the register contents and the first four parameter +words of the current frame. +end + +# show current stack frame and first 10 parameters +define xxp +printf " esp: " +output/x $esp +printf "\n ebp: " +output/x $ebp +printf "\n eip: " +x/1i $eip +printf "Saved ebp: " +output/x *(int*)$ebp +printf " (maximum of " +output ((*(int*)$ebp)-(int)$ebp)/4-4 +printf " parameters possible)\nSaved eip: " +x/1i *(int*)($ebp+4) +printf "\nParm 1 at " +output/x (int) ($ebp+8) +printf ": " +output (char*) *(int*)($ebp+8) +printf "\nParm 2 at " +output/x (int) ($ebp+12) +printf ": " +output (char*) *(int*)($ebp+12) +printf "\nParm 3 at " +output/x (int) ($ebp+16) +printf ": " +output (char*) *(int*)($ebp+16) +printf "\nParm 4 at " +output/x (int) ($ebp+20) +printf ": " +output (char*) *(int*)($ebp+20) +printf "\nParm 5 at " +output/x (int) ($ebp+24) +printf ": " +output (char*) *(int*)($ebp+24) +printf "\nParm 6 at " +output/x (int) ($ebp+28) +printf ": " +output (char*) *(int*)($ebp+28) +printf "\nParm 7 at " +output/x (int) ($ebp+32) +printf ": " +output (char*) *(int*)($ebp+32) +printf "\nParm 8 at " +output/x (int) ($ebp+36) +printf ": " +output (char*) *(int*)($ebp+36) +printf "\nParm 9 at " +output/x (int) ($ebp+40) +printf ": " +output (char*) *(int*)($ebp+40) +printf "\nParm 10 at " +output/x (int) ($ebp+44) +printf ": " +output (char*) *(int*)($ebp+44) +echo \n +end +document xxp +Show the register contents and the first ten parameter +words of the current frame. +end + +# Show first to fifth parameters of current frame as int, int * and char *. +define xp0 +x/12x *(int*)$esp +p *(int*)$esp +p (char*)*$esp +end +define xp1 +x/12x *(int*)($ebp+4) +p *(int*)($ebp+4) +p (char**)($ebp+4) +end +define xp2 +x/12x *(int*)($ebp+8) +p *(int*)($ebp+8) +p *(char**)($ebp+8) +end +define xp3 +x/12x *(int*)($ebp+12) +p *(int*)($ebp+12) +p (char**)($ebp+12) +end +define xp4 +x/12x *(int*)($ebp+16) +p *(int*)($ebp+16) +p (char**)($ebp+16) +end +document xp0 +Show the first parameter of current stack frame in various formats +end +document xp1 +Show the second parameter of current stack frame in various formats +end +document xp2 +Show the third parameter of current stack frame in various formats +end +document xp3 +Show the fourth parameter of current stack frame in various formats +end +document xp4 +Show the fifth parameter of current stack frame in various formats +end + +# Select frame 0 to 5 and show stack information. +define f0 +f 0 +xp +end +define f1 +f 1 +xp +end +define f2 +f 2 +xp +end +define f3 +f 3 +xp +end +define f4 +f 4 +xp +end +define f5 +f 5 +xp +end +document f0 +Select stack frame 0 and show assembler-level details +end +document f1 +Select stack frame 1 and show assembler-level details +end +document f2 +Select stack frame 2 and show assembler-level details +end +document f3 +Select stack frame 3 and show assembler-level details +end +document f4 +Select stack frame 4 and show assembler-level details +end +document f5 +Select stack frame 5 and show assembler-level details +end +document z +Single step 1 instruction (over calls) and show next instruction. +end +document zs +Single step 1 instruction (through calls) and show next instruction. +end +document xi +List the next 10 instructions from the current IP value +end +document xs +Show the last 12 words on stack in hex +end +document xb +Show 12 words starting at current BP value in hex +end + +# pcb <pid> +# show contents of pcb, currently only i386. +define pcb + set $nproc = nprocs + set $aproc = allproc.lh_first + set $proc = allproc.lh_first + while (--$nproc >= 0) + set $pptr = $proc.p_pptr + if ($proc->p_pid == $arg0) + set $pcba = $proc->p_threads.tqh_first->td_pcb + printf "ip: %08x sp: %08x bp: %08x bx: %08x\n", $pcba->pcb_eip, $pcba->pcb_esp, $pcba->pcb_ebp, $pcba->pcb_ebx + x/1i $pcba->pcb_eip + set $nproc = 0 + end + set $aproc = $proc.p_list.le_next + if ($aproc == 0 && $nproc > 0) + set $aproc = zombproc + end + set $proc = $aproc + end +end +document pcb +Show some pcb contents of process whose pid is specified. +end + +# btr <frame> +# primitive backtrace. frame is a memory address. +define btr +set $frame = $arg0 +set $fno = 0 +while (*(int *) $frame > 0xc0000000) + set $myebp = *(int *) $frame + set $myeip = *(int *) ($frame + 4) + printf " frame %d at %p: ebp %8x, eip ", $fno, $frame, $myebp + x/1i $myeip + set $frame = $myebp + set $fno = $fno + 1 +end +end +document btr +Show a backtrace from the ebp address specified. This can be used to get a backtrace from any stack resident in memory. It's the user's responsibility to ensure that the address is meaningful. +end + +# btp <pid> +# backtrace for process <pid>. Uses btr (machine dependent) to perform the backtrace. +# may produce nonsense. +define btp + set $nproc = nprocs + set $aproc = allproc.lh_first + set $proc = allproc.lh_first + while (--$nproc >= 0) + if ($proc->p_pid == $arg0) + btr $proc->p_threads.tqh_first->td_pcb->pcb_ebp + set $nproc = 0 + else + set $aproc = $proc.p_list.le_next + if ($aproc == 0 && $nproc > 0) + set $aproc = zombproc + end + set $proc = $aproc + end + end +end +document btp +Show a backtrace for the process whose pid is specified as a parameter. +end + +# Do backtraces for all processes in the system. +# Uses btr (machine dependent) to perform the backtrace. +define btpa + 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_stat) + printf "%5d %08x %4d %5d %5d %06x %d %-10s ", \ + $proc.p_pid, $aproc, \ + $proc.p_cred->p_ruid, $pptr->p_pid, \ + $proc.p_pgrp->pg_id, $proc.p_flag, $proc.p_stat, \ + &$proc.p_comm[0] + if ($proc.p_wchan) + if ($proc.p_wmesg) + printf "%s ", $proc.p_wmesg + end + printf "%x", $proc.p_wchan + end + printf "\n" + if ($proc->p_flag & 4) + btr $proc->p_threads.tqh_first->td_pcb->pcb_ebp + else + echo (not loaded)\n + end + end + set $aproc = $proc.p_list.le_next + if ($aproc == 0 && $nproc > 0) + set $aproc = zombproc + end + set $proc = $aproc + end +end +document btpa +Show backtraces for all processes in the system. +end + +# Show backtrace for process selected with "defproc" +define btpp +btr $myvectorproc->p_threads.tqh_first->td_pcb->pcb_ebp +end +document btpp +Show a backtrace for the process previously selected with 'defproc'. +end + +# Specific stack fram of process selected with "defproc". +define fr +set $fno = 0 +set $searching = 1 +set $frame = $myvectorproc->p_threads.tqh_first->td_pcb->pcb_ebp +while (($searching == 1) && (*(int *) $frame > 0xc0000000)) + set $myebp = *(int *) $frame + set $myeip = *(int *) ($frame + 4) + if ($fno == $arg0) + printf " frame %d at %p: ebp %8x, eip ", $fno, $frame, $myebp + x/1i $myeip + printf "Called from %8x, stack frame at %8x\n", *(int *) ($myebp+4), *(int *) $myebp + printf "last 20 local variables:\n" + x/20x ($myebp-80) + printf "call parameters:\n" + x/8x ($myebp+8) + set $searching = 0 + else + set $frame = $myebp + set $fno = $fno + 1 + end +end +if ($searching == 1) + echo frame not found\n +end +end +document fr +Show the frame of the stack of the process previously selected with 'defproc'. +end diff --git a/tools/debugscripts/gdbinit.kernel b/tools/debugscripts/gdbinit.kernel new file mode 100644 index 0000000..91d85c2 --- /dev/null +++ b/tools/debugscripts/gdbinit.kernel @@ -0,0 +1,370 @@ +# $FreeBSD$ +# General kernel macros + +# 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 diff --git a/tools/debugscripts/kgdb b/tools/debugscripts/kgdb new file mode 100644 index 0000000..ae580b3 --- /dev/null +++ b/tools/debugscripts/kgdb @@ -0,0 +1,67 @@ +#!/bin/sh - +# +# Copyright 2004 John-Mark Gurney +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +crashpath="/var/crash" +kld_debpy="kld_deb.py" + +if [ x"$1" = x"-?" -o x"$1" = x"-h" ]; then + echo "Usage: $0 <corenum> [ <gdbcmdfile> [ <modulepaths> ] ]" + echo "" + echo "Path for crash dumps: $crashpath" + exit 1 +fi + +if [ x"$1" = x"" ]; then + echo "Need core number." + exit 1 +fi +corenum="$1" +shift + +cmd_file="" +if [ x"$2" != x"" ]; then + cmd_file="-x $2" + shift +fi + +core="$crashpath/vmcore.$corenum" +info="$crashpath/info.$corenum" + +#Get the kernel source compile dir from the info file +kernsrc="`awk 'i == 1 { split($0, a, ":"); print a[2]; i = 0 } $1 == "Versionstring:" { i = 1 }' < "$info"`" + +tmpfile="/tmp/kgdb.asf.$$" +# -mapped (broken?) +# -x command_file +echo "Kernel Source: $kernsrc" +echo "Getting KLD information and locations..." +python $kld_debpy "$kernsrc" "$core" $@ > "$tmpfile" && +echo "Please run the following command to load module symbols:" +echo "source $tmpfile" +(cd "$kernsrc"; kgdb "$kernsrc/kernel.debug" "$core") +rm "$tmpfile" diff --git a/tools/debugscripts/kld_deb.py b/tools/debugscripts/kld_deb.py new file mode 100644 index 0000000..5cf0167 --- /dev/null +++ b/tools/debugscripts/kld_deb.py @@ -0,0 +1,142 @@ +#!/usr/local/bin/python +# +# Copyright 2004 John-Mark Gurney +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +import sys +import os +import popen2 +import re + +gdb_cmd = 'kgdb %(p)s/kernel.debug %(core)s | tee /tmp/gdb.log' +#GDB regex +filenamere = re.compile(r'filename\s+=\s+0x[0-9a-f]+\s("(?P<fn>[^"]+)"|(?P<error><[^>]*>))', re.M) +addressre = re.compile(r'address\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) +nextre = re.compile(r'tqe_next\s+=\s+(?P<ad>0x[0-9a-f]+)', re.M) +printre = re.compile(r'\$\d+\s+=\s+') + +#Paths to search for ko's/debugs +kld_debug_paths = [] + +if len(sys.argv[1:]) < 2: + print 'Usage: prog <kerncomp> <core> [<paths>]' + sys.exit(1) + +#Get the base modules path +pfs = sys.argv[1].split('/') +try: + i = 0 + while 1: + i = i + pfs[i:].index('sys') + 1 +except: + pass + +if i == -1: + sys.stderr.write("No sys dir in kernel source path: %s\n" % sys.argv[1]) + sys.exit(0) + +kld_debug_paths.append('/'.join(pfs[:i] + ['modules'])) +kld_debug_paths.append(sys.argv[1]) +#kld_debug_paths.append(sys.argv[3:]) +gdb_cmd = gdb_cmd % {'p': sys.argv[1], 'core': sys.argv[2] } + +#Start gdb +gdb = popen2.popen4(gdb_cmd) + +def searchfor(inp, re, j = 0, l = None): + """searchfor(inp, re, j, l): Searches for regex re in inp. It will +automatically add more lines. If j is set, the lines will be joined together. +l can provide a starting line to help search against. Return value is a +tuple of the last line, and the match if any.""" + ret = None + if not l: + l = inp.readline() + ret = re.search(l) + while l and not ret: + if j: + l += inp.readline() + else: + l = inp.readline() + ret = re.search(l) + + return (l, ret) + +def get_addresses(inp, out): + """get_addresses(inp, out): It will search for addresses from gdb. +inp and out, are the gdb input and output respectively. Return value is +a list of tuples. The tuples contain the filename and the address the +filename was loaded.""" + addr = [] + nxad = 1 + while nxad: + if nxad == 1: + out.write("print linker_files.tqh_first[0]\n") + else: + out.write("print *(struct linker_file *)%d\n" % nxad) + out.flush() + l = searchfor(inp, printre)[0] + l, fn = searchfor(inp, filenamere, 1, l) + if not fn.group('fn'): + sys.stderr.write("got error: %s\n" % fn.group('error')) + nxad = 0 + else: + l, ad = searchfor(inp, addressre, 1, l) + l, nx = searchfor(inp, nextre, 1, l) + addr.append((fn.group('fn'), long(ad.group('ad'), 16))) + nxad = long(nx.group('ad'), 16) + + return addr + +#Get the addresses +addr = get_addresses(gdb[0], gdb[1]) + +#Pass through the resulting addresses, skipping the kernel. +for i in addr[1:]: + for j in kld_debug_paths: + #Try .debug first. + p = popen2.popen4('find %s -type f -name "%s.debug"' % (j, i[0]))[0].read().strip() + if p: + break + #Try just .ko if .debug wasn't found. + p = popen2.popen4('find %s -type f -name "%s"' % (j, i[0]))[0].read().strip() + if p: + break + + if not p: + #Tell our user that we couldn't find it. + a = i[1] + sys.stderr.write("Can't find module: %s (addr: %d + header)\n" % (i[0], a)) + print '#add-symbol-file <file>', a, '#add header' + continue + + #j = popen2.popen4('objdump --section-headers /boot/kernel/%s | grep "\.text"' % i[0])[0].read().strip().split() + #Output the necessary information + j = popen2.popen4('objdump --section-headers "%s" | grep "\.text"' % p)[0].read().strip().split() + try: + a = int(j[5], 16) + print 'add-symbol-file', p, i[1] + a + except IndexError: + sys.stderr.write('Bad file: %s, address: %d\n' % (i[0], i[1])) |