プログラミングユーティリティ

カーネルをトレースするためのシェルスクリプト


例 1-3 ktrace スクリプト

#!/bin/sh
#
# ktrace
# カーネルのトレースをリセットし有効にする
# 指定されている場合はコマンドをバックグラウンドで実行する
# 指定されている場合は休眠 (スリープ) する
# コマンドの実行完了、タイムアウト、キーボードの割り込みを待機
# (注 : キーボード割り込みによってコマンドは終了する)
# カーネルのトレースを無効にする
# カーネルトレースバッファーを抽出する
# 指定されている場合はカーネルのトレースをリセットする
#
 
TMPDIR=${TMPDIR:-/tmp}
 
output_file=$TMPDIR/ktrace.tnf
buffer_size=512k
duration=
events=
command=
do_reset=y
child=
alarm=
 
# 使用法のメッセージ
usage() {
 echo ""
 echo $1
 echo "
Usage: ktrace [-o <output_file>] # デフォルトでは /tmp/ktrace.tnf
              [-s <buffer_size>] # デフォルトでは 512k
              -e <events>        # 有効にするカーネルプローブ (キー)
              [-r]                  # カーネルのトレースをリセットしない
                                    # デフォルトでは、コマンド実行後にリセットする
              <cmd> | -t <seconds>
 
Eg,
 # ktrace -e `thread vm io' -t 10
 # ktrace -e `thread' -s 256k myapp ...
"
 exit 1
}
# 失敗時のメッセージ
fail() {
 while [ $# -gt 0 ]
 do
  echo $1
  shift
 done
 echo "ktrace failed"
 exit 2
}
 
# カーネルのトレースをリセットする
ktrace_reset() {
 if [ $1 = "y" ]; then
  echo "Resetting kernel tracing"
  prex -k >/dev/null 2>&1 <<-EOF
   ktrace off
   untrace /.*/
   disable /.*/
   buffer dealloc
   EOF
  test $? -ne 0 && fail "Could not reset kernel tracing" ¥
   "`su root' and retry"
 fi
}
 
# カーネルのトレースを有効にする
ktrace_on() {
 echo "Enabling kernel tracing"
 prex -k >/dev/null 2>&1 <<-EOF
  buffer alloc $buffer_size
  trace $events
  enable $events
  ktrace on
  EOF
 test $? -ne 0 && fail "Could not enable kernel tracing" ¥
  "Check syntax of `-e' argument" ¥
  "Check buffer size is not too high"
}
 
# カーネルのトレースを無効にする
ktrace_off() {
 prex -k >/dev/null 2>&1 <<-EOF
  ktrace off
  EOF
 test $? -ne 0 && fail "Could not disable kernel tracing"
 echo "Kernel tracing disabled"
}
 
# カーネルトレースバッファーを抽出する
ktrace_xtract() {
 echo "Extracting kernel trace buffer"
 tnfxtract $output_file || fail "Could not extract kernel trace
 buffer"
 ls -l $output_file
}
 
# コマンドを実行、休眠、またはコマンド実行完了を待機する
run_command() {
 trap `interrupt' 0 1 2 3 15
 if [ "$command" ]; then
  $command &
  child=$!
  echo "`$command' pid is $child"
 fi
 
 if [ "$duration" ]; then
  sleep $duration &
  alarm=$!
  wait $alarm
  # XXX test -z "$child" || kill -15 $child
 else
  wait $child
 fi
 trap 0 1 2 3 15
}
 
# キーボード割り込み
interrupt() {
 test -z "$alarm" || kill -15 $alarm
 test -z "$child" || kill -15 $child
}
 
# オプションを読み取る
while getopts o:s:t:e:r opt
do
 case $opt in
  o) output_file="$OPTARG";;
  s) buffer_size="$OPTARG";;
  t) duration="$OPTARG";;
  e) events="$OPTARG";;
  r) do_reset="n";;
  ¥?) usage;;
 esac
done
 
shift `expr $OPTIND - 1`
 
# 実行するコマンドを取得する
test $# -gt 0 && command="$*"
 
# オプションを検査
test -z "$events" && usage "No kernel events specified"
test -z "$command" && test -z "$duration" && ¥
usage "No command or time duration specified"
 
# 検査を実行する
ktrace_reset y           # カーネルのトレースをリセット
ktrace_on                # カーネルのトレースを有効に
run_command              # コマンド実行、待機、または休眠
ktrace_off               # カーネルのトレースを無効に
ktrace_xtract            # バッファを抽出
ktrace_reset $do_reset   # カーネルのトレースを再度リセット
exit 0