Personal tools
Document Actions

Emacs Lisp デバッグ

著者 菅原泰樹

elisp のデバッグ方法について以下の3つの方法を説明します.
- printf デバッグ
- backtrace
- edebug

■■■ printf デバッグ
elisp で printf デバッグを行なうには message 関数を使います.message 関数の結果は *Messages* バッファに出力されます.
例えば以下の<リスト1>のように使います.

----------------
<リスト1> message 関数を使った printf デバッグ
(defun message-sample ()
(let (list)
(dotimes (i 10)
(push i list)
(message "%s" list))))
----------------

実行中に目視したい場合は sit-for と message の組み合わせか y-or-n-p を使うのが良いでしょう.
- sit-for はキーボード入力があるか,指定した時間まで処理を停止します.message と組合せる事で,一定時間 message の結果を minibuffer に表示できます.
- y-or-n-p は y か n を入力するまで操作を止めます.

<リスト1>の message 関数を使っている個所を<リスト2>のそれぞれで置き換えてみて下さい.

----------------
<リスト2> sit-for,y-or-n-p を使った printfデバッグ
;; sit-for と message の組み合わせの使い方
(message "%s" list)
(sit-for 3) ; 何かキー入力があるか,3秒経つと先に進む

;; y-or-n-pの使い方
(y-or-n-p (format "%s" list)) ; y か n を押すまで処理を止める
----------------

■■■ backtrace
backtrace は Java で言う stacktrace みたいなものです.backtrace を出力するには変数 debug-on-error を t にしておく必要があります.
<リスト3>の関数を定義してから実行すると,<リスト4>の backtrace が出力されます.
backtrace の先頭行にはエラーの概要が表示され,2行目以降には callstack が表示されます.

今回出力された backtrace を見てみましょう.
まず先頭行に (wrong-type-argument number-or-marker-p "20") とあるので,数値が要求された個所に文字列を渡している事がわかります.
2行目に +(-10 "20") とあるので,+ 関数に "20" を渡したためにこのエラーが発生した事がわかります.
3行目に (if (< n 0) (+ n m) (- n m)) とあるので,2行目は if 分の中で呼び出された + 関数だと言う事がわかります.つまり m が文字列な為エラーが発生した事が原因である事が分かりました.

■■ 注意点等
- backtrace モードを抜けるには backtrace バッファで q を押して下さい.
- bytecompile された関数の backtrace を取るときは eval-defun でその関数を再定義する必要があります.
- backtrace バッファ で e を押すとその時点での変数の値を評価できます.

----------------
<リスト3> 間違った関数
(defun backtrace-sample ()
(let ((n -10)
(m "20"))
(if (< n 0)
(+ n m)
(- n m))))
----------------

----------------
<リスト4> backtrace の出力例
Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p "20")
+(-10 "20")
(if (< n 0) (+ n m) (- n m))
(let ((n -10) (m "20")) (if (< n 0) (+ n m) (- n m)))
backtrace-sample()
eval((backtrace-sample))
eval-last-sexp-1(t)
eval-last-sexp(t)
eval-print-last-sexp()
call-interactively(eval-print-last-sexp)
----------------

■■■ edebug
elisp でステップ実行をするには edebug を使います.
edebug を使うにはブレークポイントを設定したい関数の上で C-u C-M-x (前置引数付きの eval-defun)をします.その後で,その関数が呼び出されると edebug モードに入ります.
<リスト5>を一度評価してから,edebug-sample の上で C-u C-M-x をして,M-x edebug-sample として下さい.let の上にカーソルが移動して,画面左側にインジケータが表示されるかと思います.

----------------
<リスト5> edebug のサンプル
(defun edebug-sample ()
(interactive)
(let ((i 5))
(message "sample1 %d" i)
(edebug-sample2 i)))

(defun edebug-sample2 (i)
(message "sample2 %d" (+ i 10)))
----------------

■■ ステップ実行
それではステップ実行してみましょう.ステップ実行をするには SPC を押します.
- 一度 SPC を押すと「(message "sample1 %d" i)」の行に移動します.
- もう一度 SPC を押すとカーソルが「i」の後ろに移動してミニバッファに「Result: 5 (#o5, #x5, ?\C-e)」と表示されます.
- もう一度 SPC を押すとカーソルが「(message "sample1 %d" i)」の後ろに移動してミニバッファに「Result: Result: "sample1 5"」と表示されます.
- 同じように繰り返し SPC を押すとカーソルが関数・変数単位で移動してその結果がミニバッファに表示されます.

<表1>に edebug のキーバインドを載せておきます。

----------------
<表1> edebug のキーバインド
SPC ステップ実行
g 次のブレークポイントまで実行
c ブレークポイントを表示しながら最後まで実行(C-g で止めるとその位置から再開できる)
h カーソル位置まで実行
i 直後の関数に入る
b ブレークポイントを張る
u ブレークポイントを削除
q edebug を抜ける
e 式を評価する(実行中の値が使える)
C-h v 変数の値を表示する(実行中の値が見れる)
----------------

Attachments

Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.