#!/bin/csh
#
# gdbmodules -- gdb wrapper adding symbol information from loaded modules
# Darrell Anderson 1/99 with help from Drew (:
#
# usage:
#   if no arguments are given, run on the active kernel.
#   if one argument, use /var/crash/kernel.ARG, vmcore.ARG.
#   if two arguments, use them as kernel and core.
#
#   also, a "--" argument terminates the script flags, anything following
#   is passed to the gdb command line flags.

set VERBOSE = 0
set TMPFILE = /var/run/gdbmodstmp.$USER
if (-e $TMPFILE) /bin/rm $TMPFILE
touch $TMPFILE

echo "please be patient while loaded modules are resolved"

if ($#argv >= 2 && $1 != "--" && $2 != "--") then
	set KERNEL = $1
	set CORE = $2
	shift
	shift
else if ($#argv >= 1 && $1 != "--") then
	set KERNEL = /var/crash/kernel.$1
	set CORE = /var/crash/vmcore.$1
	shift
else if ($#argv == 0 || ($#argv > 0 && $1 == "--")) then
	set KERNEL = `sysctl kern.bootfile | awk '{print $2}'`
	set CORE = /dev/mem
else
	echo "huh?"
	exit 1
endif

echo "gdbmods using kernel: $KERNEL"
echo "gdbmods using core:   $CORE"

if ($#argv > 0) then
	if ($1 != "--") then
		echo "something in the initial parsing is broken"
		exit 1
	endif
	shift
endif
if ($VERBOSE) echo "gdb extra arguments: $argv"

if (! -e $KERNEL) then
	echo "can't find file $KERNEL"
	exit 1
endif
if (! -r $KERNEL) then
	echo "no read permission for $KERNEL"
	exit 1
endif
if (! -e $CORE) then
	echo "can't find file $CORE"
	exit 1
endif
if (! -r $CORE) then
	echo "no read permission for $CORE"
	exit 1
endif

if (`uname -m` == alpha) then
	echo "target kcore $CORE" >> $TMPFILE
	set GDB_BINARY = "gdb"
	set GDB = "$GDB_BINARY -n -quiet -x $TMPFILE $KERNEL"
else
	set GDB_BINARY = "gdb"
	set GDB = "$GDB_BINARY -k -n -quiet -x $TMPFILE $KERNEL $CORE"
endif

#
# assume modules came from same build pool as kernel (bad assumption..)
# perhaps consult an environment variable instead/as well?
#
if (!($?MODPATH)) then
    set MODPATH = `strings $KERNEL | grep 'sys/compile' | sed -e 's/.*://' | sed -e 's/compile.*/modules/'`
    set MODPATH = `echo "$MODPATH" | sed -e 's#\.amd_mnt#a#'`
endif

if ($MODPATH == "") then
    if ($VERBOSE) echo "must be using buildkernel.."
    set MODPATH = `strings $KERNEL | grep 'usr/obj/usr/src/sys' |  sed -e 's/.*://'`
endif

if (! -d $MODPATH) then
	echo "bad module path $MODPATH"
	exit 1
endif
if ($VERBOSE) echo "MODPATH $MODPATH"

#
# locate first module, skipping the "kernel" entry
#
set MODULE = `echo "print linker_files->tqh_first->link.tqe_next" | $GDB |& grep "linker_file" | awk '{print $7}'`
if ($VERBOSE) echo "MODULE $MODULE"

#
# iterate over all modules
#
while ($MODULE != 0x0 && $MODULE != '')

    #
    # get the module name
    #
    set MODNAME = `echo "print ((struct linker_file *)$MODULE)->filename" | $GDB |& grep "gdb" | awk '{print $5}' | sed -e 's/\"//g'`
    ##HUH
    set MODNAME = `echo $MODNAME | sed -e "s@$TMPFILE@@g"`
    if ($VERBOSE) echo "MODNAME $MODNAME"

    #
    # get the module load address
    #
    set MODADDR = `echo "print ((struct linker_file *)$MODULE)->address" | $GDB |& grep "gdb" | awk '{print $4}'`
    ##HUH
    set MODADDR = `echo $MODADDR | sed -e 's/\-x//g'`
    if ($VERBOSE) echo "MODADDR $MODADDR"

    #
    # find the module file
    # can get default module path from `sysctl kern.module_path` XXX
    # prefer modules with the archtype in the path.
    #
    set ARCH = `uname -m`
    set MODFILE = `find $MODPATH -name "$MODNAME" -print | grep $ARCH`
    if ($MODFILE == "") then
	set MODFILE = `find $MODPATH -name "$MODNAME" -print`
	if ($MODFILE == "") then
		set MODFILE = `find /modules -name "$MODNAME" -print`
	endif
    endif
    if ($MODFILE == "") then
	echo "can't find module $MODNAME"
    else
    if ($VERBOSE) echo "MODFILE $MODFILE"

    #
    # find the text segment offset
    #
    set MODOFFS = `objdump --headers $MODFILE | grep ".text" | grep -v ".rel.text" | awk '{print $6}'`
    set MODOFFS = `echo 0x${MODOFFS}`
    if ($VERBOSE) echo "MODOFFS $MODOFFS"

    #
    # add the load command to the command file
    #
    echo "add-symbol-file $MODFILE $MODADDR + $MODOFFS" >> $TMPFILE

    #
    # report status
    #
    echo "added symbols for module $MODNAME"
    endif
    #
    # locate next module
    #
    set MODULE = \
    `echo "print ((struct linker_file *)$MODULE)->link.tqe_next" | $GDB |& grep "linker_file" | awk '{print $7}'`
    if ($VERBOSE) echo "MODULE $MODULE"

end

#
# for some reason adding symbols confuses the frame information.  kludge.
#
echo "select-frame 0" >> $TMPFILE

#
# invoke the real gdb with the command file
#
if (`uname -m` == alpha) then
	if ($VERBOSE) echo "command line: $GDB_BINARY -x $TMPFILE $argv $KERNEL"
	$GDB_BINARY -x $TMPFILE $argv $KERNEL
else
	if ($VERBOSE) echo "command line: $GDB_BINARY -k -x $TMPFILE $argv $KERNEL $CORE"
	$GDB_BINARY -k -x $TMPFILE $argv $KERNEL $CORE
endif

/bin/rm $TMPFILE

#EOF#

