;;;; Guile Debugger ;;; Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. ;;; ;; This library is free software; you can redistribute it and/or ;; modify it under the terms of the GNU Lesser General Public ;; License as published by the Free Software Foundation; either ;; version 2.1 of the License, or (at your option) any later version. ;; ;; This library is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this library; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (define-module (ice-9 debugger) #:use-module (ice-9 debugger command-loop) #:use-module (ice-9 debugger state) #:use-module (ice-9 debugger utils) #:use-module (ice-9 format) #:use-module (emacs gds-client) #:export (debug-stack debug debug-last-error debugger-error debugger-quit debugger-input-port debugger-output-port debug-on-error) #:no-backtrace) ;;; The old (ice-9 debugger) has been factored into its constituent ;;; parts: ;;; ;;; (ice-9 debugger) - public interface to all of the following ;;; ;;; (... commands) - procedures implementing the guts of the commands ;;; provided by the interactive debugger ;;; ;;; (... command-loop) - binding these commands into the interactive ;;; debugger command loop ;;; ;;; (... state) - implementation of an object that tracks current ;;; debugger state ;;; ;;; (... utils) - utilities for printing out frame and stack ;;; information in various formats ;;; ;;; The division between (... commands) and (... command-loop) exists ;;; because I (NJ) have another generic command loop implementation ;;; under development, and I want to be able to switch easily between ;;; that and the command loop implementation here. Thus the ;;; procedures in this file delegate to a debugger command loop ;;; implementation via the `debugger-command-loop-*' interface. The ;;; (ice-9 debugger command-loop) implementation can be replaced by ;;; any other that implements the `debugger-command-loop-*' interface ;;; simply by changing the relevant #:use-module line above. ;;; ;;; The following new parts add breakpoint support: ;;; ;;; (... behaviour) - codification of the things that can happen when ;;; a breakpoint is hit, regardless of the type of ;;; the breakpoint ;;; ;;; (... breakpoints) - management of breakpoints in general ;;; ;;; (... breakpoints procedural) - breakpoints that trigger upon ;;; application of a specified ;;; procedure ;;; ;;; (... breakpoints source) - breakpoints that trigger upon ;;; evaluation of a specific source ;;; expression ;;; ;;; (... trap-hooks) - a (slightly) higher-level abstraction of ;;; Guile's evaluator traps interface ;;; ;;; (... trc) - generic tracing interface for debugging tricky code ;;; using the `printf' method :-) ;;; ;;; Note that (... breakpoints range) doesn't work yet. If loaded, it ;;; seems to cause some kind of explosion in the GOOPS method cache ;;; calculation code. ;;; ;;; - Neil Jerram 2002-10-26 (define *not-yet-introduced* #t) (define (debug-stack stack . flags) "Invoke the Guile debugger to explore the specified @var{stack}. @var{flags}, if present, are keywords indicating characteristics of the debugging session: the valid keywords are as follows. @table @code @item #:continuable Indicates that the debugger is being invoked from a context (such as an evaluator trap handler) where it is possible to return from the debugger and continue normal code execution. This enables the @dfn{continuing execution} commands, for example @code{continue} and @code{step}. @item #:with-introduction Indicates that the debugger should display an introductory message. @end table" (start-stack 'debugger (let ((state (apply make-state stack 0 flags))) (with-input-from-port (debugger-input-port) (lambda () (with-output-to-port (debugger-output-port) (lambda () (if (or *not-yet-introduced* (memq #:with-introduction flags)) (let ((ssize (stack-length stack))) (display "This is the Guile debugger -- for help, type `help'.\n") (set! *not-yet-introduced* #f) (if (= ssize 1) (display "There is 1 frame on the stack.\n\n") (format #t "There are ~A frames on the stack.\n\n" ssize)))) (write-state-short state) (if (gds-connected?) (gds-command-loop state) (debugger-command-loop state))))))))) (define (debug) "Invoke the Guile debugger to explore the context of the last error." (let ((stack (fluid-ref the-last-stack))) (if stack (debug-stack stack) (display "Nothing to debug.\n")))) (define debug-last-error debug) (define (debugger-error message) "Signal a debugger usage error with message @var{message}." (debugger-command-loop-error message)) (define (debugger-quit) "Exit the debugger." (debugger-command-loop-quit)) ;;; {Debugger Input and Output Ports} (define debugger-input-port (let ((input-port (current-input-port))) (make-procedure-with-setter (lambda () input-port) (lambda (port) (set! input-port port))))) (define debugger-output-port (let ((output-port (current-output-port))) (make-procedure-with-setter (lambda () output-port) (lambda (port) (set! output-port port))))) ;;; {Debug on Error} (define (debug-on-error syms) "Enable or disable debug on error." (set! lazy-handler-dispatch (if syms (lambda (key . args) (if (memq key syms) (begin (debug-stack (make-stack #t lazy-handler-dispatch) #:with-introduction #:continuable) (throw 'abort key))) (apply default-lazy-handler key args)) default-lazy-handler))) ;;; (ice-9 debugger) ends here.