X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fdebug-int.lisp;h=fc38784880a06513d0663a2da53af05c1c17e619;hb=a6a12ed609d5467ec43b411283e5b3568fee81df;hp=7411bc59a10f25a2997d59c9e1a2bde051de75f5;hpb=cdd026dddac3eaddbaa0221503e49e2673d54545;p=sbcl.git diff --git a/src/code/debug-int.lisp b/src/code/debug-int.lisp index 7411bc5..fc38784 100644 --- a/src/code/debug-int.lisp +++ b/src/code/debug-int.lisp @@ -539,8 +539,7 @@ (sb!alien:define-alien-routine component-ptr-from-pc (system-area-pointer) (pc system-area-pointer)) -#!+gencgc (declaim (inline valid-lisp-pointer-p)) -#!+gencgc +(declaim (inline valid-lisp-pointer-p)) (sb!alien:define-alien-routine valid-lisp-pointer-p sb!alien:int (pointer system-area-pointer)) @@ -867,7 +866,15 @@ (component-from-component-ptr component-ptr)))) (/noshow0 "got CODE") (when (null code) - (return (values code 0 context))) + ;; KLUDGE: Detect undefined functions by a range-check + ;; against the trampoline address and the following + ;; function in the runtime. + (if (< (foreign-symbol-address "undefined_tramp") + (sap-int (sb!vm:context-pc context)) + (foreign-symbol-address #!+x86 "closure_tramp" + #!+x86-64 "alloc_tramp")) + (return (values :undefined-function 0 context)) + (return (values code 0 context)))) (let* ((code-header-len (* (get-header-data code) sb!vm:n-word-bytes)) (pc-offset @@ -1974,6 +1981,18 @@ register." ;;; (Such values can arise in registers on machines with conservative ;;; GC, and might also arise in debug variable locations when ;;; those variables are invalid.) +;;; +;;; NOTE: this function is not GC-safe in the slightest when creating +;;; a pointer to an object in dynamic space. If a GC occurs between +;;; the start of the call to VALID-LISP-POINTER-P and the end of +;;; %MAKE-LISP-OBJ then the object could move before the boxed pointer +;;; is constructed. This can happen on CHENEYGC if an asynchronous +;;; interrupt occurs within the window. This can happen on GENCGC +;;; under the same circumstances, but is more likely due to all GENCGC +;;; platforms supporting threaded operation. This is somewhat +;;; mitigated on x86oids due to the conservative stack and interrupt +;;; context "scavenging" on such platforms, but there still may be a +;;; vulnerable window. (defun make-lisp-obj (val &optional (errorp t)) (if (or ;; fixnum @@ -1986,22 +2005,17 @@ register." (= (logand val #xff) sb!vm:character-widetag)) ; char tag ;; unbound marker (= val sb!vm:unbound-marker-widetag) + ;; undefined_tramp doesn't validate properly as a pointer, and + ;; the actual value can vary by backend (x86oids need not + ;; apply) + #!+(or alpha hppa mips ppc) + (= val (+ (- (foreign-symbol-address "undefined_tramp") + (* sb!vm:n-word-bytes sb!vm:simple-fun-code-offset)) + sb!vm:fun-pointer-lowtag)) + #!+sparc + (= val (foreign-symbol-address "undefined_tramp")) ;; pointer - #!+gencgc - (not (zerop (valid-lisp-pointer-p (int-sap val)))) - ;; FIXME: There is no fundamental reason not to use the above - ;; function on other platforms as well, but I didn't have - ;; others available while doing this. --NS 2007-06-21 - #!-gencgc - (and (logbitp 0 val) - (or (< sb!vm:read-only-space-start val - (ash sb!vm:*read-only-space-free-pointer* - sb!vm:n-fixnum-tag-bits)) - (< sb!vm:static-space-start val - (ash sb!vm:*static-space-free-pointer* - sb!vm:n-fixnum-tag-bits)) - (< (current-dynamic-space-start) val - (sap-int (dynamic-space-free-pointer)))))) + (not (zerop (valid-lisp-pointer-p (int-sap val))))) (values (%make-lisp-obj val) t) (if errorp (error "~S is not a valid argument to ~S" @@ -2511,6 +2525,70 @@ register." (nconc (subseq form 0 n) (cons res (nthcdr (1+ n) form)))))))) (frob form path context)))) + +;;; Given a code location, return the associated form-number +;;; translations and the actual top level form. +(defun get-toplevel-form (location) + (let ((d-source (code-location-debug-source location))) + (let* ((offset (code-location-toplevel-form-offset location)) + (res + (cond ((debug-source-form d-source) + (debug-source-form d-source)) + ((debug-source-namestring d-source) + (get-file-toplevel-form location)) + (t (bug "Don't know how to use a DEBUG-SOURCE without ~ + a namestring or a form."))))) + (values (form-number-translations res offset) res)))) + +;;; To suppress the read-time evaluation #. macro during source read, +;;; *READTABLE* is modified. +;;; +;;; FIXME: This breaks #+#.(cl:if ...) Maybe we need a SAFE-READ-EVAL, which +;;; this code can use for side- effect free #. calls? +;;; +;;; FIXME: This also knows nothing of custom readtables. The assumption +;;; is that the current readtable is a decent approximation for what +;;; we want, but that's lossy. +(defun safe-readtable () + (let ((rt (copy-readtable))) + (set-dispatch-macro-character + #\# #\. (lambda (stream sub-char &rest rest) + (declare (ignore rest sub-char)) + (let ((token (read stream t nil t))) + (format nil "#.~S" token))) + rt) + rt)) + +;;; Locate the source file (if it still exists) and grab the top level +;;; form. If the file is modified, we use the top level form offset +;;; instead of the recorded character offset. +(defun get-file-toplevel-form (location) + (let* ((d-source (code-location-debug-source location)) + (tlf-offset (code-location-toplevel-form-offset location)) + (local-tlf-offset (- tlf-offset + (debug-source-root-number d-source))) + (char-offset + (aref (or (sb!di:debug-source-start-positions d-source) + (error "no start positions map")) + local-tlf-offset)) + (namestring (debug-source-namestring d-source))) + ;; FIXME: External format? + (with-open-file (f namestring :if-does-not-exist nil) + (unless f + (error "The source file no longer exists:~% ~A" namestring)) + (format *debug-io* "~%; file: ~A~%" namestring) + (let ((*readtable* (safe-readtable))) + (cond ((eql (debug-source-created d-source) (file-write-date f)) + (file-position f char-offset)) + (t + (format *debug-io* + "~%; File has been modified since compilation:~%; ~A~@ + ; Using form offset instead of character position.~%" + namestring) + (let ((*read-suppress* t)) + (loop repeat local-tlf-offset + do (read f))))) + (read f))))) ;;;; PREPROCESS-FOR-EVAL