#!/bin/sh
#
# kgdb 1.6 1995/06/07 06:05:46 (David Hinds)
#
# A script for starting up gdb for kernel debugging
#
# This will load the kdebug.o module if necessary, create a device
# file for the kdebug pseudo-device, and fire up gdb, loading the
# kernel symbol table and module symbols.  
#

mpath=/lib/modules/`uname -r`
vmlinux=/usr/src/linux/vmlinux

while getopts "m:v:t:p:" ch ; do
  case $ch in
    m)  mpath=$OPTARG ;;
    v)  vmlinux=$OPTARG ;;
    t)  trapfile=$OPTARG ;;
    p)  pid=$OPTARG ;;
    \?)
      echo "usage: $0 [-m modpath] [-v vmlinux] [-t trapfile] [-p pid]" >&2
      exit 1
      ;;
  esac
done

if [ ! -f $mpath/misc/kdebug.o ] ; then
  echo "$mpath/misc/kdebug.o does not exist!"
  exit 1
fi

if [ ! -f $vmlinux ] ; then
  echo "kernel image \"$vmlinux\" does not exist!"
  exit 1
fi

strings $vmlinux | grep -q "`uname -v`"
if [ $? -ne 0 ] ; then
  echo "Warning: $vmlinux version does not match current kernel!"
fi

insmod $mpath/misc/kdebug.o

rm -f /dev/kdebug
major=`grep kdebug /proc/devices | cut -d' ' -f1`
mknod /dev/kdebug c $major 0

cat << EOF > /tmp/kgdb.$$
echo Reading symbols from $vmlinux...\n
file $vmlinux
target remote /dev/kdebug
set output-radix 16
define set-task
  set \$task=*(struct task_struct **)get_task(\$pid)
  set \$tss=\$task->tss
  set \$eax=\$tss.eax, \$ebx=\$tss.ebx, \$ecx=\$tss.ecx
  set \$edx=\$tss.edx, \$esi=\$tss.esi, \$edi=\$tss.edi
  set \$eip=\$tss.eip, \$ebp=\$tss.ebp, \$esp=\$tss.esp
  set \$ps=\$tss.eflags
end
EOF

search=`/bin/ls -d $mpath/*`
search=". $search"

expand() {
  while read a b c ; do
    for d in $search ; do
      if [ -r $d/$b ] ; then
	echo "echo loading $d/$b...\n"
        echo $a $d/$b $c
        break
      fi
    done
  done
}

ksyms -m | sed -n -e 's/\(.*\)000 .*\[\(.*\)\]/\1004 \2/p' | \
	awk '{ printf("add-symbol-file %s.o\t0x%s\n", $2, $1) }' \
	| expand >> /tmp/kgdb.$$

if [ -n "$trapfile" ] ; then
  if [ -r $trapfile ] ; then
    echo "echo loading trap info...\n" >> /tmp/kgdb.$$
  else
    echo "trap file \"$trapfile\" does not exist!"
    exit 1
  fi
  # Magic number to signal we want to set up a separate stack
  echo "set $eip=0xe5e5e5e5" >> /tmp/kgdb.$$
  cat $trapfile | awk '
    /EIP:/ { match($0, "EIP:"); print substr($0, RSTART) }
    /EFLAGS:/,/Code:/ { print substr($0, RSTART) } ' \
  | awk '
    /EIP: / \
      { print "set $eip=0x" substr($2,6) }
    /EFLAGS: / \
      { print "set $ps=0x" $2 }
    /eax: / \
      { print "set $eax=0x" $2 ", $ebx=0x" $4 ", $ecx=0x" $6 ", $edx=0x" $8 }
    /esi: / \
      { print "set $esi=0x" $2 ", $edi=0x" $4 ", $ebp=0x" $6 ", $esp=0x" $8 }
    /Stack: / \
      { for (i=2;i<=NF;i++) print "set ((long *)$esp)[" sp++ "]=0x" $i }
    /^      / \
      { for (i=1;i<=NF;i++) print "set ((long *)$esp)[" sp++ "]=0x" $i }
    /Call Trace: / \
      { exit }
  ' >> /tmp/kgdb.$$
fi

if [ x$pid != x ] ; then
  echo 'set $pid='$pid >> /tmp/kgdb.$$
  echo 'set-task' >> /tmp/kgdb.$$
fi

echo "where" >> /tmp/kgdb.$$

#cat /tmp/kgdb.$$
gdb -x /tmp/kgdb.$$

rm -f /tmp/kgdb.* /dev/kdebug
rmmod kdebug
