;;;-*-Mode: LISP; Package: CCL -*- ;;; ;;; Copyright (C) 2009 Clozure Associates ;;; Copyright (C) 1994-2001 Digitool, Inc ;;; This file is part of Clozure CL. ;;; ;;; Clozure CL is licensed under the terms of the Lisp Lesser GNU Public ;;; License , known as the LLGPL and distributed with Clozure CL as the ;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL, ;;; which is distributed with Clozure CL as the file "LGPL". Where these ;;; conflict, the preamble takes precedence. ;;; ;;; Clozure CL is referenced in the preamble as the "LIBRARY." ;;; ;;; The LLGPL is also available online at ;;; http://opensource.franz.com/preamble.html ; l1-readloop-lds.lisp (in-package "CCL") (defvar *read-loop-function* 'read-loop) (defun run-read-loop (&rest args) (declare (dynamic-extent args)) (apply *read-loop-function* args)) (defun toplevel-loop () (loop (if (eq (catch :toplevel (run-read-loop :break-level 0 )) $xstkover) (format t "~&;[Stacks reset due to overflow.]") (when (eq *current-process* *initial-process*) (toplevel))))) (defvar *defined-toplevel-commands* ()) (defvar *active-toplevel-commands* ()) (defun %define-toplevel-command (group-name key name fn doc args) (let* ((group (or (assoc group-name *defined-toplevel-commands*) (car (push (list group-name) *defined-toplevel-commands*)))) (pair (assoc key (cdr group) :test #'eq))) (if pair (rplacd pair (list* fn doc args)) (push (cons key (list* fn doc args)) (cdr group)))) name) (define-toplevel-command :global y (&optional p) "Yield control of terminal-input to process whose name or ID matches

, or to any process if

is null" (%%yield-terminal-to (if p (find-process p)))) ;may be nil (define-toplevel-command :global kill (p) "Kill process whose name or ID matches

" (let* ((proc (find-process p))) (if proc (process-kill proc)))) (define-toplevel-command :global proc (&optional p) "Show information about specified process

/all processes" (flet ((show-process-info (proc) (format t "~&~d : ~a ~a ~25t[~a] " (process-serial-number proc) (if (eq proc *current-process*) "->" " ") (process-name proc) (process-whostate proc)) (let* ((suspend-count (process-suspend-count proc))) (if (and suspend-count (not (eql 0 suspend-count))) (format t " (Suspended)"))) (let* ((terminal-input-shared-resource (if (typep *terminal-io* 'two-way-stream) (input-stream-shared-resource (two-way-stream-input-stream *terminal-io*))))) (if (and terminal-input-shared-resource (%shared-resource-requestor-p terminal-input-shared-resource proc)) (format t " (Requesting terminal input)"))) (fresh-line))) (if p (let* ((proc (find-process p))) (if (null proc) (format t "~&;; not found - ~s" p) (show-process-info proc))) (dolist (proc (all-processes) (values)) (show-process-info proc))))) (define-toplevel-command :global cd (dir) "Change to directory DIR (e.g., #p\"ccl:\" or \"/some/dir\")" (setf (current-directory) dir) (toplevel-print (list (current-directory)))) (define-toplevel-command :global pwd () "Print the pathame of the current directory" (toplevel-print (list (current-directory)))) (defun list-restarts () (format *debug-io* "~&> Type (:C ) to invoke one of the following restarts:") (display-restarts)) (define-toplevel-command :break pop () "exit current break loop" (abort-break)) (define-toplevel-command :break a () "exit current break loop" (abort-break)) (define-toplevel-command :break go () "continue" (continue)) (define-toplevel-command :break q () "return to toplevel" (toplevel)) (define-toplevel-command :break r () "list restarts" (list-restarts)) (define-toplevel-command :break nframes () "print the number of stack frames accessible from this break loop" (do* ((p *break-frame* (parent-frame p nil)) (i 0 ) (last (last-frame-ptr))) ((eql p last) (toplevel-print (list i))) (declare (fixnum i)) (when (function-frame-p p nil) (incf i)))) (define-toplevel-command :global ? () "help" (format t "~&The following toplevel commands are available:") (when *default-integer-command* (format t "~& ~8Tthe same as (~s )" (car *default-integer-command*))) (dolist (g *active-toplevel-commands*) (dolist (c (cdr g)) (let* ((command (car c)) (doc (caddr c)) (args (cdddr c))) (if args (format t "~& (~S~{ ~A~}) ~8T~A" command args doc) (format t "~& ~S ~8T~A" command doc))))) (format t "~&Any other form is evaluated and its results are printed out.")) (define-toplevel-command :break b (&key start count show-frame-contents) "backtrace" (when *break-frame* (print-call-history :detailed-p show-frame-contents :origin *break-frame* :count count :start-frame-number (or start 0)))) (define-toplevel-command :break c (&optional n) "Choose restart . If no , continue" (if n (select-restart n) (continue))) (define-toplevel-command :break f (n) "Show backtrace frame " (print-call-history :origin *break-frame* :start-frame-number n :count 1 :detailed-p t)) (define-toplevel-command :break return-from-frame (i &rest values) "Return VALUES from the I'th stack frame" (let* ((frame-sp (nth-function-frame i *break-frame* nil))) (if frame-sp (apply #'return-from-frame frame-sp values)))) (define-toplevel-command :break apply-in-frame (i function &rest args) "Applies FUNCTION to ARGS in the execution context of the Ith stack frame" (let* ((frame-sp (nth-function-frame i *break-frame* nil))) (if frame-sp (apply-in-frame frame-sp function args)))) (define-toplevel-command :break raw (n) "Show raw contents of backtrace frame " (print-call-history :origin *break-frame* :start-frame-number n :count 1 :detailed-p :raw)) (define-toplevel-command :break v (n frame-number) "Return value in frame " (let* ((frame-sp (nth-function-frame frame-number *break-frame* nil))) (if frame-sp (toplevel-print (list (nth-value-in-frame frame-sp n nil)))))) (define-toplevel-command :break arg (name frame-number) "Return value of argument named in frame " (let* ((frame-sp (nth-function-frame frame-number *break-frame* nil))) (when frame-sp (multiple-value-bind (lfun pc) (cfp-lfun frame-sp) (when (and lfun pc) (let* ((unavailable (cons nil nil))) (declare (dynamic-extent unavailable)) (let* ((value (arg-value nil frame-sp lfun pc unavailable name))) (if (eq value unavailable) (format *debug-io* "~&;; Can't determine value of ~s in frame ~s." name frame-number) (toplevel-print (list value)))))))))) (define-toplevel-command :break set-arg (name frame-number new) "Set value of argument named in frame to value ." (let* ((frame-sp (nth-function-frame frame-number *break-frame* nil))) (when frame-sp (multiple-value-bind (lfun pc) (cfp-lfun frame-sp) (when (and lfun pc) (or (set-arg-value nil frame-sp lfun pc name new) (format *debug-io* "~&;; Can't change value of ~s in frame ~s." name frame-number))))))) (define-toplevel-command :break local (name frame-number) "Return value of local denoted by in frame can either be a symbol - in which case the most recent binding of that symbol is used - or an integer index into the frame's set of local bindings." (let* ((frame-sp (nth-function-frame frame-number *break-frame* nil))) (when frame-sp (multiple-value-bind (lfun pc) (cfp-lfun frame-sp) (when (and lfun pc) (let* ((unavailable (cons nil nil))) (declare (dynamic-extent unavailable)) (let* ((value (local-value nil frame-sp lfun pc unavailable name))) (if (eq value unavailable) (format *debug-io* "~&;; Can't determine value of ~s in frame ~s." name frame-number) (toplevel-print (list value)))))))))) (define-toplevel-command :break set-local (name frame-number new) "Set value of argument denoted (see :LOCAL) in frame to value ." (let* ((frame-sp (nth-function-frame frame-number *break-frame* nil))) (when frame-sp (multiple-value-bind (lfun pc) (cfp-lfun frame-sp) (when (and lfun pc) (or (set-local-value nil frame-sp lfun pc name new) (format *debug-io* "~&;; Can't change value of ~s in frame ~s." name frame-number))))))) (define-toplevel-command :break form (frame-number) "Return a form which looks like the call which established the stack frame identified by . This is only well-defined in certain cases: when the function is globally named and not a lexical closure and when it was compiled with *SAVE-LOCAL-SYMBOLS* in effect." (let* ((form (dbg-form frame-number))) (when form (let* ((*print-level* *backtrace-print-level*) (*print-length* *backtrace-print-length*)) (toplevel-print (list form)))))) ;;; Ordinarily, form follows function. (define-toplevel-command :break function (frame-number) "Returns the function invoked in backtrace frame . This may be useful for, e.g., disassembly" (let* ((cfp (nth-function-frame frame-number *break-frame* nil))) (when (and cfp (not (catch-csp-p cfp nil))) (let* ((function (cfp-lfun cfp))) (when function (toplevel-print (list function))))))) (defun %use-toplevel-commands (group-name) ;; Push the whole group (pushnew (assoc group-name *defined-toplevel-commands*) *active-toplevel-commands* :key #'(lambda (x) (car x)))) ; #'car not defined yet ... (%use-toplevel-commands :global) (defparameter *toplevel-commands-dwim* t "If true, tries to interpret otherwise-erroneous toplevel expressions as commands. In addition, will suppress standard error handling for expressions that look like commands but aren't") (defvar *default-integer-command* nil "If non-nil, should be (keyword min max)), causing integers between min and max to be interpreted as (keyword integer)") (defun check-toplevel-command (form) (when (and *default-integer-command* (integerp form) (<= (cadr *default-integer-command*) form (caddr *default-integer-command*))) (setq form `(,(car *default-integer-command*) ,form))) (let* ((cmd (if (consp form) (car form) form)) (args (if (consp form) (cdr form)))) (when (or (keywordp cmd) (and *toplevel-commands-dwim* (non-nil-symbol-p cmd) (not (if (consp form) (fboundp cmd) (or (boundp cmd) (nth-value 1 (gethash cmd *symbol-macros*))))) ;; Use find-symbol so don't make unneeded keywords. (setq cmd (find-symbol (symbol-name cmd) :keyword)))) (when (eq cmd :help) (setq cmd :?)) (flet ((run (cmd form) (or (dolist (g *active-toplevel-commands*) (let* ((pair (assoc cmd (cdr g)))) (when pair (apply (cadr pair) args) (return t)))) ;; Try to detect user mistyping a command (when (and *toplevel-commands-dwim* (if (consp form) (and (keywordp (%car form)) (not (fboundp (%car form)))) (keywordp form))) (error "Unknown command ~s" cmd))))) (declare (dynamic-extent #'run)) (if *toplevel-commands-dwim* (block nil (handler-bind ((error (lambda (c) (format t "~&~a" c) (return t)))) (run cmd form))) (run cmd form)))))) (defparameter *quit-on-eof* nil) (defparameter *consecutive-eof-limit* 2 "max number of consecutive EOFs at a given break level, before we give up and abruptly exit.") (defmethod stream-eof-transient-p (stream) (let ((fd (stream-device stream :input))) (and fd (eof-transient-p fd)))) (defvar *save-interactive-source-locations* t) ;;; This is the part common to toplevel loop and inner break loops. (defun read-loop (&key (input-stream *standard-input*) (output-stream *standard-output*) (break-level *break-level*) (prompt-function #'(lambda (stream) (when (and *show-available-restarts* *break-condition*) (list-restarts) (setf *show-available-restarts* nil)) (print-listener-prompt stream t)))) (let* ((*break-level* break-level) (*last-break-level* break-level) (*loading-file-source-file* nil) (*loading-toplevel-location* nil) *in-read-loop* *** ** * +++ ++ + /// // / - (eof-value (cons nil nil)) (eof-count 0) (*show-available-restarts* (and *show-restarts-on-break* *break-condition*)) (map (make-hash-table :test #'eq :shared nil))) (declare (dynamic-extent eof-value)) (loop (restart-case (catch :abort ;last resort... (loop (catch-cancel (loop (setq *in-read-loop* nil *break-level* break-level) (multiple-value-bind (form env print-result) (toplevel-read :input-stream input-stream :output-stream output-stream :prompt-function prompt-function :eof-value eof-value :map (when *save-interactive-source-locations* (clrhash map) map)) (if (eq form eof-value) (progn (when (> (incf eof-count) *consecutive-eof-limit*) (#_ _exit 0)) (if (and (not *batch-flag*) (not *quit-on-eof*) (stream-eof-transient-p input-stream)) (progn (stream-clear-input input-stream) (abort-break)) (exit-interactive-process *current-process*))) (let ((*nx-source-note-map* (and *save-interactive-source-locations* map))) (setq eof-count 0) (or (check-toplevel-command form) (let* ((values (toplevel-eval form env))) (if print-result (toplevel-print values))))))))) (format *terminal-io* "~&Cancelled"))) (abort () :report (lambda (stream) (if (eq break-level 0) (format stream "Return to toplevel.") (format stream "Return to break level ~D." break-level))) #| ; Handled by interactive-abort ; go up one more if abort occurred while awaiting/reading input (when (and *in-read-loop* (neq break-level 0)) (abort)) |# ) (abort-break () (unless (eq break-level 0) (abort)))) (clear-input input-stream) (format output-stream "~%")))) ;;; The first non-whitespace character available on INPUT-STREAM is a colon. ;;; Try to interpret the line as a colon command (or possibly just a keyword.) (defun read-command-or-keyword (input-stream eof-value) (let* ((line (read-line input-stream nil eof-value))) (if (eq line eof-value) eof-value (let* ((in (make-string-input-stream line)) (keyword (read in nil eof-value))) (if (eq keyword eof-value) eof-value (if (not (keywordp keyword)) keyword (collect ((params)) (loop (let* ((param (read in nil eof-value))) (if (eq param eof-value) (return (let* ((params (params))) (if params (cons keyword params) keyword))) (params (eval param)))))))))))) ;;; Read a form from the specified stream. (defun toplevel-read (&key (input-stream *standard-input*) (output-stream *standard-output*) (prompt-function #'print-listener-prompt) (eof-value *eof-value*) (map nil)) (force-output output-stream) (funcall prompt-function output-stream) (read-toplevel-form input-stream :eof-value eof-value :map map)) (defvar *always-eval-user-defvars* nil) (defun process-single-selection (form) (if (and *always-eval-user-defvars* (listp form) (eq (car form) 'defvar) (cddr form)) `(defparameter ,@(cdr form)) form)) (defun toplevel-eval (form &optional env) (destructuring-bind (vars . vals) (or env '(nil . nil)) (progv vars vals (setq +++ ++ ++ + + - - form) (unwind-protect (let* ((package *package*) (values (multiple-value-list (cheap-eval-in-environment form nil)))) (unless (eq package *package*) ;; If changing a local value (e.g. buffer-local), not useful to notify app ;; without more info. Perhaps should have a *source-context* that can send along? (unless (member '*package* vars) (application-ui-operation *application* :note-current-package *package*))) values) (loop for var in vars as pval on vals do (setf (car pval) (symbol-value var))))))) (defun toplevel-print (values &optional (out *standard-output*)) (setq /// // // / / values) (unless (eq (car values) (%unbound-marker)) (setq *** ** ** * * (%car values))) (when values (fresh-line out) (dolist (val values) (write val :stream out) (terpri out)))) (defparameter *listener-prompt-format* "~[?~:;~:*~d >~] ") (defun print-listener-prompt (stream &optional (force t)) (unless *quiet-flag* (when (or force (neq *break-level* *last-break-level*)) (let* ((*listener-indent* nil)) (fresh-line stream) (format stream *listener-prompt-format* *break-level*)) (setq *last-break-level* *break-level*))) (force-output stream)) ;;; Fairly crude default error-handlingbehavior, and a fairly crude mechanism ;;; for customizing it. (defvar *app-error-handler-mode* :quit "one of :quit, :quit-quietly, :listener might be useful.") (defmethod application-error ((a application) condition error-pointer) (case *app-error-handler-mode* (:listener (break-loop-handle-error condition error-pointer)) (:quit-quietly (quit -1)) (:quit (format t "~&Fatal error in ~s : ~a" (pathname-name (car *command-line-argument-list*)) condition) (quit -1)))) (defun make-application-error-handler (app mode) (declare (ignore app)) (setq *app-error-handler-mode* mode)) ; You may want to do this anyway even if your application ; does not otherwise wish to be a "lisp-development-system" (defmethod application-error ((a lisp-development-system) condition error-pointer) (break-loop-handle-error condition error-pointer)) (defun abnormal-application-exit () (ignore-errors (print-call-history) (write-line (lisp-implementation-version) *debug-io*) (force-output *debug-io*) (quit -1)) (#__exit -1)) ;; Make these available to debugger hook (defvar *top-error-frame* nil) (defvar *break-loop-type* nil) ;; e.g. "Debug", "Signal", "Error". (defun break-loop-handle-error (condition *top-error-frame*) (multiple-value-bind (bogus-globals newvals oldvals) (%check-error-globals) (dolist (x bogus-globals) (set x (funcall (pop newvals)))) (let ((msg (if *batch-flag* ;; Give a little more info if exiting (format nil "Error of type ~s" (type-of condition)) "Error"))) (when (and *debugger-hook* *break-on-errors* (not *batch-flag*)) (let ((hook *debugger-hook*) (*debugger-hook* nil) (*break-loop-type* msg)) (funcall hook condition hook))) (%break-message msg condition)) (let* ((s *error-output*)) (dolist (bogusness bogus-globals) (let ((oldval (pop oldvals))) (format s "~&; NOTE: ~S was " bogusness) (if (eq oldval (%unbound-marker-8)) (format s "unbound") (format s "~s" oldval)) (format s ", was reset to ~s ." (symbol-value bogusness))))) (if (and *break-on-errors* (not *batch-flag*)) (break-loop condition) (if *batch-flag* (abnormal-application-exit) (abort))))) (defun break (&optional string &rest args) "Print a message and invoke the debugger without allowing any possibility of condition handling occurring." (if *batch-flag* (apply #'error (or string "BREAK invoked in batch mode") args) (apply #'%break-in-frame (%get-frame-ptr) string args))) (defun %break-in-frame (fp &optional string &rest args) (flet ((do-break-loop () (let ((c (if (typep string 'condition) string (make-condition 'simple-condition :format-control (or string "") :format-arguments args)))) (cbreak-loop "Break" "Return from BREAK." c fp)))) (cond ((%i> *interrupt-level* -1) (do-break-loop)) (*break-loop-when-uninterruptable* (format *error-output* "Break while interrupt-level less than zero; binding to 0 during break-loop.") (let ((interrupt-level (interrupt-level))) (unwind-protect (progn (setf (interrupt-level) 0) (do-break-loop)) (setf (interrupt-level) interrupt-level)))) (t (format *error-output* "Break while interrupt-level less than zero; ignored."))))) (defun invoke-debugger (condition &aux (*top-error-frame* (%get-frame-ptr))) "Enter the debugger." (let ((c (require-type condition 'condition)) (msg "Debug")) (when *debugger-hook* (let ((hook *debugger-hook*) (*debugger-hook* nil) (*break-loop-type* msg)) (funcall hook c hook))) (%break-message msg c) (break-loop c))) (defun %break-message (msg condition &optional (error-pointer *top-error-frame*) (prefixchar #\>)) (let ((*print-circle* *error-print-circle*) ;(*print-prett*y nil) (*print-array* nil) (*print-escape* t) (*print-gensym* t) (*print-length* *error-print-length*) (*print-level* *error-print-level*) (*print-lines* nil) (*print-miser-width* nil) (*print-readably* nil) (*print-right-margin* nil) (*signal-printing-errors* nil) (s (make-indenting-string-output-stream prefixchar nil)) (sub (make-string-output-stream)) (indent 0)) (format s "~A~@[ ~A:~] " prefixchar msg) (setf (indenting-string-output-stream-indent s) (setq indent (column s))) (decf (stream-line-length sub) indent) ;(format s "~A" condition) ; evil if circle (report-condition condition sub) (format s "~A" (get-output-stream-string sub)) (if (not (and (typep condition 'simple-program-error) (simple-program-error-context condition))) (format *error-output* "~&~A~%~A While executing: ~S" (get-output-stream-string s) prefixchar (%real-err-fn-name error-pointer)) (format *error-output* "~&~A" (get-output-stream-string s))) (if *current-process* (format *error-output* ", in process ~a(~d).~%" (process-name *current-process*) (process-serial-number *current-process*)) (format *error-output* ", in an uninitialized process~%")) (force-output *error-output*))) ; returns NIL (defvar *break-hook* nil) (defun cbreak-loop (msg cont-string condition *top-error-frame*) (let* ((*print-readably* nil) (hook *break-hook*)) (restart-case (progn (when (and (eq (type-of condition) 'simple-condition) (equal (simple-condition-format-control condition) "")) (setq condition (make-condition 'simple-condition :format-control "~a" :format-arguments (list msg)))) (when hook (let ((*break-hook* nil) (*break-loop-type* msg)) (funcall hook condition hook)) (setq hook nil)) (%break-message msg condition) (break-loop condition)) (continue () :report (lambda (stream) (write-string cont-string stream)))) (unless hook (fresh-line *error-output*)) nil)) (defun warn (condition-or-format-string &rest args) "Warn about a situation by signalling a condition formed by DATUM and ARGUMENTS. While the condition is being signaled, a MUFFLE-WARNING restart exists that causes WARN to immediately return NIL." (when (typep condition-or-format-string 'condition) (unless (typep condition-or-format-string 'warning) (report-bad-arg condition-or-format-string 'warning)) (when args (error 'type-error :datum args :expected-type 'null :format-control "Extra arguments in ~s."))) (let ((fp (%get-frame-ptr)) (c (require-type (condition-arg condition-or-format-string args 'simple-warning) 'warning))) (when *break-on-warnings* (cbreak-loop "Warning" "Signal the warning." c fp)) (restart-case (signal c) (muffle-warning () :report "Skip the warning" (return-from warn nil))) (%break-message (if (typep c 'compiler-warning) "Compiler warning" "Warning") c fp #\;) )) (defmacro new-backtrace-info (dialog youngest oldest tcr condition current fake db-link level) (let* ((cond (gensym))) `(let* ((,cond ,condition)) (vector ,dialog ,youngest ,oldest ,tcr (cons nil (compute-restarts ,cond)) (%catch-top ,tcr) ,cond ,current ,fake ,db-link ,level)))) (defmethod backtrace-context-continuable-p ((context vector)) (not (null (find 'continue (cdr (bt.restarts context)) :key #'restart-name)))) (defmethod backtrace-context-break-level ((context vector)) (bt.break-level context)) (defmethod backtrace-context-restarts ((context vector)) (cdr (bt.restarts context))) ;;; Each of these stack ranges defines the entire range of (control/value/temp) ;;; addresses; they can be used to addresses of stack-allocated objects ;;; for printing. #-arm-target (defun make-tsp-stack-range (tcr bt-info) (list (cons (%catch-tsp (bt.top-catch bt-info)) (%fixnum-ref (%fixnum-ref tcr target::tcr.ts-area) target::area.high)))) #+ppc-target (defun make-vsp-stack-range (tcr bt-info) (list (cons (%fixnum-ref (%svref (bt.top-catch bt-info) target::catch-frame.csp-cell) target::lisp-frame.savevsp) (%fixnum-ref (%fixnum-ref tcr target::tcr.vs-area) target::area.high)))) #+x8632-target (defun make-vsp-stack-range (tcr bt-info) (list (cons (%svref (bt.top-catch bt-info) target::catch-frame.esp-cell) (%fixnum-ref (%fixnum-ref tcr (- target::tcr.vs-area target::tcr-bias)) target::area.high)))) #+x8664-target (defun make-vsp-stack-range (tcr bt-info) (list (cons (%svref (bt.top-catch bt-info) target::catch-frame.rsp-cell) (%fixnum-ref (%fixnum-ref tcr target::tcr.vs-area) target::area.high)))) #+arm-target (defun make-vsp-stack-range (tcr bt-info) (list (cons (%fixnum-ref (catch-frame-sp (bt.top-catch bt-info)) target::lisp-frame.savevsp) (%fixnum-ref (%fixnum-ref tcr target::tcr.vs-area) target::area.high)))) #+ppc-target (defun make-csp-stack-range (tcr bt-info) (list (cons (%svref (bt.top-catch bt-info) target::catch-frame.csp-cell) (%fixnum-ref (%fixnum-ref tcr target::tcr.cs-area) target::area.high)))) #+x8632-target (defun make-csp-stack-range (tcr bt-info) (let ((cs-area nil)) #+windows-target (let ((aux (%fixnum-ref tcr (- target::tcr.aux target::tcr-bias)))) (setq cs-area (%fixnum-ref aux target::tcr-aux.cs-area))) #-windows-target (setq cs-area (%fixnum-ref tcr target::tcr.cs-area)) (list (cons (%svref (bt.top-catch bt-info) target::catch-frame.foreign-sp-cell) (%fixnum-ref cs-area target::area.high))))) #+x8664-target (defun make-csp-stack-range (tcr bt-info) (list (cons (%svref (bt.top-catch bt-info) target::catch-frame.foreign-sp-cell) (%fixnum-ref (%fixnum-ref tcr target::tcr.cs-area) target::area.high)))) #+arm-target (defun make-csp-stack-range (tcr bt-info) (list (cons (catch-frame-sp (bt.top-catch bt-info)) (%fixnum-ref (%fixnum-ref tcr target::tcr.cs-area) target::area.high)))) (declaim (notinline select-backtrace)) (defun select-backtrace () (declare (notinline select-backtrace)) ;(require 'new-backtrace) (require :inspector) (select-backtrace)) (defvar *break-condition* nil "condition argument to innermost break-loop.") (defvar *break-frame* nil "frame-pointer arg to break-loop") (defvar *break-loop-when-uninterruptable* t) (defvar *show-restarts-on-break* nil) (defvar *show-available-restarts* nil) (defvar *error-reentry-count* 0) (defun funcall-with-error-reentry-detection (thunk) (let* ((count *error-reentry-count*) (*error-reentry-count* (1+ count))) (cond ((eql count 0) (funcall thunk)) ((eql count 1) (error "Error reporting error")) (t (bug "Error reporting error"))))) (defvar %last-continue% nil) (defun break-loop (condition &optional (frame-pointer *top-error-frame*)) "Never returns" (let* ((%handlers% (last %handlers%)) ; firewall (*break-frame* frame-pointer) (*break-condition* condition) (*compiling-file* nil) (*backquote-stack* nil) (continue (find-restart 'continue)) (*continuablep* (unless (eq %last-continue% continue) continue)) (%last-continue% continue) (*standard-input* *debug-io*) (*standard-output* *debug-io*) (*signal-printing-errors* nil) (*read-suppress* nil) (*print-readably* nil) (context (new-backtrace-info nil frame-pointer (if *backtrace-contexts* (or (child-frame (bt.youngest (car *backtrace-contexts*)) nil) (last-frame-ptr)) (last-frame-ptr)) (%current-tcr) condition (%current-frame-ptr) #+ppc-target *fake-stack-frames* #+x86-target (%current-frame-ptr) #+arm-target (or (current-fake-stack-frame) (%current-frame-ptr)) (db-link) (1+ *break-level*))) (*default-integer-command* `(:c 0 ,(1- (length (cdr (bt.restarts context)))))) (*backtrace-contexts* (cons context *backtrace-contexts*))) (with-terminal-input (with-toplevel-commands :break (if *continuablep* (let* ((*print-circle* *error-print-circle*) (*print-level* *error-print-level*) (*print-length* *error-print-length*) ;(*print-pretty* nil) (*print-array* nil)) (format t (or (application-ui-operation *application* :break-options-string t) "~&> Type :GO to continue, :POP to abort, :R for a list of available restarts.")) (format t "~&> If continued: ~A~%" continue)) (format t (or (application-ui-operation *application* :break-options-string nil) "~&> Type :POP to abort, :R for a list of available restarts.~%"))) (format t "~&> Type :? for other options.") (terpri) (force-output) (clear-input *debug-io*) (setq *error-reentry-count* 0) ; succesfully reported error (ignoring-without-interrupts (unwind-protect (progn (application-ui-operation *application* :enter-backtrace-context context) (run-read-loop :break-level (1+ *break-level*) :input-stream *debug-io* :output-stream *debug-io*)) (application-ui-operation *application* :exit-backtrace-context context))))))) (defun display-restarts (&optional (condition *break-condition*)) (loop for restart in (compute-restarts condition) for count upfrom 0 do (format *debug-io* "~&~D. ~A" count restart) finally (fresh-line *debug-io*))) (defun select-restart (n &optional (condition *break-condition*)) (let* ((restarts (compute-restarts condition))) (invoke-restart-interactively (nth (require-type n `(integer 0 (,(length restarts)))) restarts)))) ; End of l1-readloop-lds.lisp