次: , 前: Infinite Loops, 上: Debugger


17.1.3 関数呼び出し時のデバッガの起動

プログラムの途中で発生する問題点を調べるための1つの有用な技法は、 ある関数を呼び出すたびにデバッガに入ることです。 問題を生じる関数に対してこのようにしておき、 当該関数をステップ実行するか、あるいは、 問題が発生する直前に呼ばれる関数に対してこのようにしておき、 その関数の呼び出しを終えてから、呼び出し側をステップ実行します。

— コマンド: debug-on-entry function-name

この関数は、function-nameが呼び出されるたびに デバッガを起動するようにする。 当該関数の定義の最初のフォームとして フォーム(debug 'debug)を挿入することでこれを行う。

Lispコードで定義した任意の関数は、 解釈実行コードであろうとコンパイル済みのコードであろうと、 関数に入るときにブレークするようにできる。 関数がコマンドであると、Lispから呼ばれたときや 対話的に呼ばれたときに(引数を読み取ってから)デバッガに入る。 (Cで書いた)基本関数は、この方法ではデバッグできない。

debug-on-entryを対話的に呼び出すと、 ミニバッファでfunction-nameを問い合わせる。 その関数がすでに呼び出し時にデバッガを起動するようになっていると、 debug-on-entryはなにもしない。 debug-on-entryはつねにfunction-nameを返す。

注意: debug-on-entryを使ったあとに当該関数を再定義すると、 デバッガに入るためのコードがなくなる。 実質的には、関数を再定義すると呼び出し時にブレークする機能を 取り消すことになる。

          (defun fact (n)
            (if (zerop n) 1
                (* n (fact (1- n)))))
               => fact
          (debug-on-entry 'fact)
               => fact
          (fact 3)
          
          ------ Buffer: *Backtrace* ------
          Entering:
          * fact(3)
            eval-region(4870 4878 t)
            byte-code("...")
            eval-last-sexp(nil)
            (let ...)
            eval-insert-last-sexp(nil)
          * call-interactively(eval-insert-last-sexp)
          ------ Buffer: *Backtrace* ------
          
          (symbol-function 'fact)
               => (lambda (n)
                    (debug (quote debug))
                    (if (zerop n) 1 (* n (fact (1- n)))))
     
— コマンド: cancel-debug-on-entry function-name

この関数は、function-nameに対するdebug-on-entryの効果 (呼び出し時にブレークする)を取り消す。 対話的に呼び出すと、 ミニバッファでfunction-nameを問い合わせる。 function-namenilであったり空文字列であると、 すべての関数について、呼び出し時にブレークすることを取り消す。

呼び出し時にブレークする設定をしていない関数に対して cancel-debug-on-entryを呼び出してもなにもしない。 つねにfunction-nameを返す。