1 ;;;; stuff that creates debugger information from the compiler's
2 ;;;; internal data structures
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
15 (deftype byte-buffer
() '(vector (unsigned-byte 8)))
16 (defvar *byte-buffer
*)
17 (declaim (type byte-buffer
*byte-buffer
*))
21 (deftype location-kind
()
22 '(member :unknown-return
:known-return
:internal-error
:non-local-exit
23 :block-start
:call-site
:single-value-return
:non-local-entry
26 ;;; The LOCATION-INFO structure holds the information what we need
27 ;;; about locations which code generation decided were "interesting".
28 (defstruct (location-info
29 (:constructor make-location-info
(kind label vop
))
31 ;; The kind of location noted.
32 (kind nil
:type location-kind
)
33 ;; The label pointing to the interesting code location.
34 (label nil
:type
(or label index null
))
35 ;; The VOP that emitted this location (for node, save-set, ir2-block, etc.)
38 ;;; This is called during code generation in places where there is an
39 ;;; "interesting" location: someplace where we are likely to end up
40 ;;; in the debugger, and thus want debug info.
41 (defun note-debug-location (vop label kind
)
42 (declare (type vop vop
) (type (or label null
) label
)
43 (type location-kind kind
))
44 (let ((location (make-location-info kind label vop
)))
45 (setf (ir2-block-locations (vop-block vop
))
46 (nconc (ir2-block-locations (vop-block vop
))
50 #!-sb-fluid
(declaim (inline ir2-block-physenv
))
51 (defun ir2-block-physenv (2block)
52 (declare (type ir2-block
2block
))
53 (block-physenv (ir2-block-block 2block
)))
55 (defun leaf-visible-to-debugger-p (leaf node
)
56 (or (rassoc leaf
(lexenv-vars (node-lexenv node
)))
57 (labels ((visible-in-call-lexenv (lambda)
59 (let ((call-lexenv (lambda-call-lexenv lambda
)))
61 (or (rassoc leaf
(lexenv-vars call-lexenv
))
62 (visible-in-call-lexenv (lexenv-lambda call-lexenv
))))))))
63 (visible-in-call-lexenv (lexenv-lambda (node-lexenv node
))))))
65 ;;; Given a local conflicts vector and an IR2 block to represent the
66 ;;; set of live TNs, and the VAR-LOCS hash-table representing the
67 ;;; variables dumped, compute a bit-vector representing the set of
68 ;;; live variables. If the TN is environment-live, we only mark it as
69 ;;; live when it is in scope at NODE.
70 (defun compute-live-vars (live node block var-locs vop
)
71 (declare (type ir2-block block
) (type local-tn-bit-vector live
)
72 (type hash-table var-locs
) (type node node
)
73 (type (or vop null
) vop
))
74 (let ((res (make-array (logandc2 (+ (hash-table-count var-locs
) 7) 7)
78 (ir2-component-spilled-vops
79 (component-info *component-being-compiled
*)))))
80 (do-live-tns (tn live block
)
81 (let ((leaf (tn-leaf tn
)))
82 (when (and (lambda-var-p leaf
)
83 (or (not (member (tn-kind tn
)
84 '(:environment
:debug-environment
)))
85 (leaf-visible-to-debugger-p leaf node
))
87 (not (member tn spilled
))))
88 (let ((num (gethash leaf var-locs
)))
90 (setf (sbit res num
) 1))))))
93 ;;; The PC for the location most recently dumped.
94 (defvar *previous-location
*)
95 (declaim (type index
*previous-location
*))
97 ;;; Dump a compiled debug-location into *BYTE-BUFFER* that describes
98 ;;; the code/source map and live info. If true, VOP is the VOP
99 ;;; associated with this location, for use in determining whether TNs
101 (defun dump-1-location (node block kind tlf-num label live var-locs vop
)
102 (declare (type node node
) (type ir2-block block
)
103 (type (or null local-tn-bit-vector
) live
)
104 (type (or label index
) label
)
105 (type location-kind kind
) (type (or index null
) tlf-num
)
106 (type hash-table var-locs
) (type (or vop null
) vop
))
108 (let ((byte-buffer *byte-buffer
*))
110 (position-or-lose kind
*compiled-code-location-kinds
*)
113 (let ((loc (if (fixnump label
) label
(label-position label
))))
114 (write-var-integer (- loc
*previous-location
*) byte-buffer
)
115 (setq *previous-location
* loc
))
117 (let ((path (node-source-path node
)))
119 (write-var-integer (source-path-tlf-number path
) byte-buffer
))
120 (write-var-integer (source-path-form-number path
) byte-buffer
))
123 (write-packed-bit-vector (compute-live-vars live node block var-locs vop
)
125 (write-packed-bit-vector
126 (make-array (logandc2 (+ (hash-table-count var-locs
) 7) 7)
131 (write-var-string (or (and (typep node
'combination
)
132 (combination-step-info node
))
137 ;;; Extract context info from a Location-Info structure and use it to
138 ;;; dump a compiled code-location.
139 (defun dump-location-from-info (loc tlf-num var-locs
)
140 (declare (type location-info loc
) (type (or index null
) tlf-num
)
141 (type hash-table var-locs
))
142 (let ((vop (location-info-vop loc
)))
143 (dump-1-location (vop-node vop
)
145 (location-info-kind loc
)
147 (location-info-label loc
)
153 ;;; Scan all the blocks, determining if all locations are in the same
154 ;;; TLF, and returning it or NIL.
155 (defun find-tlf-number (fun)
156 (declare (type clambda fun
))
157 (let* ((source-path (node-source-path (lambda-bind fun
)))
158 (res (source-path-tlf-number source-path
)))
159 (declare (type (or index null
) res
))
160 (do-physenv-ir2-blocks (2block (lambda-physenv fun
))
161 (let ((block (ir2-block-block 2block
)))
162 (when (eq (block-info block
) 2block
)
163 (unless (eql (source-path-tlf-number
165 (block-start-node block
)))
169 (dolist (loc (ir2-block-locations 2block
))
170 (unless (eql (source-path-tlf-number
172 (vop-node (location-info-vop loc
))))
175 (values res
(source-path-form-number source-path
))))
177 ;;; Dump out the number of locations and the locations for Block.
178 (defun dump-block-locations (block locations tlf-num var-locs
)
179 (declare (type cblock block
) (list locations
))
181 (eq (location-info-kind (first locations
))
183 (write-var-integer (length locations
) *byte-buffer
*)
184 (let ((2block (block-info block
)))
185 (write-var-integer (+ (length locations
) 1) *byte-buffer
*)
186 (dump-1-location (block-start-node block
)
187 2block
:block-start tlf-num
188 (ir2-block-%label
2block
)
189 (ir2-block-live-out 2block
)
192 (dolist (loc locations
)
193 (dump-location-from-info loc tlf-num var-locs
))
196 ;;; Return a vector and an integer (or null) suitable for use as the
197 ;;; BLOCKS and TLF-NUMBER in FUN's DEBUG-FUN.
198 (defun compute-debug-blocks (fun var-locs
)
199 (declare (type clambda fun
) (type hash-table var-locs
))
200 (multiple-value-bind (tlf-num form-number
) (find-tlf-number fun
)
201 (let ((*previous-location
* 0)
202 (physenv (lambda-physenv fun
))
203 (byte-buffer *byte-buffer
*)
207 (setf (fill-pointer byte-buffer
) 0)
208 (do-physenv-ir2-blocks (2block physenv
)
209 (let ((block (ir2-block-block 2block
)))
210 (when (eq (block-info block
) 2block
)
212 (dump-block-locations prev-block
(nreverse (shiftf locations nil
))
214 (setf prev-block block
)))
215 (dolist (loc (ir2-block-locations 2block
))
216 (if (label-elsewhere-p (location-info-label loc
)
217 (location-info-kind loc
))
218 (push loc elsewhere-locations
)
219 (push loc locations
))))
221 (dump-block-locations prev-block
(nreverse locations
)
224 (when elsewhere-locations
225 (write-var-integer (length elsewhere-locations
) byte-buffer
)
226 (dolist (loc (nreverse elsewhere-locations
))
228 (dump-location-from-info loc tlf-num var-locs
)))
230 (values (!make-specialized-array
(length byte-buffer
) '(unsigned-byte 8)
232 tlf-num form-number
))))
234 ;;; Return DEBUG-SOURCE structure containing information derived from
236 (defun debug-source-for-info (info &key function
)
237 (declare (type source-info info
))
238 (let ((file-info (get-toplevelish-file-info info
)))
240 :compiled
(source-info-start-time info
)
242 :namestring
(or *source-namestring
*
243 (make-file-info-namestring
244 (if (pathnamep (file-info-name file-info
))
245 (file-info-name file-info
))
247 :created
(file-info-write-date file-info
)
248 :source-root
(file-info-source-root file-info
)
249 :start-positions
(coerce-to-smallest-eltype
250 (file-info-positions file-info
))
252 :form
(let ((direct-file-info (source-info-file-info info
)))
253 (when (eq :lisp
(file-info-name direct-file-info
))
254 (elt (file-info-forms direct-file-info
) 0)))
255 :function function
)))
257 ;;; Given an arbitrary sequence, coerce it to an unsigned vector if
258 ;;; possible. Ordinarily we coerce it to the smallest specialized
260 ;;; During cross-compilation the in-memory representation is opaque -
261 ;;; we don't care how it looks, but can recover the intended specialization.
263 (defun coerce-to-smallest-eltype (seq)
264 (let ((maxoid 0) (length 0))
266 (if (typep x
'unsigned-byte
)
269 (return-from coerce-to-smallest-eltype
270 (coerce seq
'simple-vector
)))))
273 (incf length
) ; so not to traverse again to compute it
275 (dovector (i seq
(setq length
(length seq
)))
277 (let ((specializer (etypecase maxoid
278 ((unsigned-byte 8) '(unsigned-byte 8))
279 ((unsigned-byte 16) '(unsigned-byte 16))
280 ((unsigned-byte 32) '(unsigned-byte 32))
281 ((unsigned-byte 64) '(unsigned-byte 64)))))
282 ;; formerly (coerce seq `(simple-array ,specializer (*)))
283 ;; plus a kludge for cross-compilation. This is nicer.
284 (!make-specialized-array length specializer seq
)))))
288 ;;; Return a SC-OFFSET describing TN's location.
289 (defun tn-sc-offset (tn)
290 (declare (type tn tn
))
291 (make-sc-offset (sc-number (tn-sc tn
))
294 (defun lambda-ancestor-p (maybe-ancestor maybe-descendant
)
295 (declare (type clambda maybe-ancestor
)
296 (type (or clambda null
) maybe-descendant
))
298 (when (eq maybe-ancestor maybe-descendant
)
300 (setf maybe-descendant
(lambda-parent maybe-descendant
))
301 (when (null maybe-descendant
)
304 ;;; Dump info to represent VAR's location being TN. ID is an integer
305 ;;; that makes VAR's name unique in the function. BUFFER is the vector
306 ;;; we stick the result in. If MINIMAL, we suppress name dumping, and
307 ;;; set the minimal flag.
309 ;;; The DEBUG-VAR is only marked as always-live if the TN is
310 ;;; environment live and is an argument. If a :DEBUG-ENVIRONMENT TN,
311 ;;; then we also exclude set variables, since the variable is not
312 ;;; guaranteed to be live everywhere in that case.
313 (defun dump-1-var (fun var tn id minimal buffer
)
314 (declare (type lambda-var var
) (type (or tn null
) tn
) (type index id
)
316 (let* ((name (leaf-debug-name var
))
317 (save-tn (and tn
(tn-save-tn tn
)))
318 (kind (and tn
(tn-kind tn
)))
320 (info (lambda-var-arg-info var
))
321 (indirect (and (lambda-var-indirect var
)
322 (not (lambda-var-explicit-value-cell var
))
323 (neq (lambda-physenv fun
)
324 (lambda-physenv (lambda-var-home var
))))))
325 (declare (type index flags
))
327 (setq flags
(logior flags compiled-debug-var-minimal-p
))
328 (unless (and tn
(tn-offset tn
))
329 (setq flags
(logior flags compiled-debug-var-deleted-p
))))
330 (when (and (or (eq kind
:environment
)
331 (and (eq kind
:debug-environment
)
332 (null (basic-var-sets var
))))
333 (not (gethash tn
(ir2-component-spilled-tns
334 (component-info *component-being-compiled
*))))
335 (lambda-ancestor-p (lambda-var-home var
) fun
))
336 (setq flags
(logior flags compiled-debug-var-environment-live
)))
338 (setq flags
(logior flags compiled-debug-var-save-loc-p
)))
339 (unless (or (zerop id
) minimal
)
340 (setq flags
(logior flags compiled-debug-var-id-p
)))
342 (setq flags
(logior flags compiled-debug-var-indirect-p
)))
344 (case (arg-info-kind info
)
346 (setq flags
(logior flags compiled-debug-var-more-context-p
)))
348 (setq flags
(logior flags compiled-debug-var-more-count-p
)))))
351 (setf (ldb (byte 27 8) flags
) (tn-sc-offset tn
))
353 (setf (ldb (byte 27 35) flags
) (tn-sc-offset save-tn
))))
355 (if (and tn
(tn-offset tn
))
356 (setf (ldb (byte 27 8) flags
) (tn-sc-offset tn
))
359 (setf (ldb (byte 27 35) flags
) (tn-sc-offset save-tn
)))))
360 (vector-push-extend flags buffer
)
362 (vector-push-extend name buffer
)
364 (vector-push-extend id buffer
)))
367 ;; Indirect variables live in the parent frame, and are
368 ;; accessed through a saved frame pointer.
369 ;; The first one/two sc-offsets are for the frame pointer,
370 ;; the third is for the stack offset.
372 (vector-push-extend (tn-sc-offset tn
) buffer
)
375 (vector-push-extend (tn-sc-offset save-tn
) buffer
))
376 (vector-push-extend (tn-sc-offset (leaf-info var
)) buffer
))
379 (if (and tn
(tn-offset tn
))
380 (vector-push-extend (tn-sc-offset tn
) buffer
)
383 (vector-push-extend (tn-sc-offset save-tn
) buffer
)))))
386 ;;; Return a vector suitable for use as the DEBUG-FUN-VARS
387 ;;; of FUN. LEVEL is the current DEBUG-INFO quality. VAR-LOCS is a
388 ;;; hash table in which we enter the translation from LAMBDA-VARS to
389 ;;; the relative position of that variable's location in the resulting
391 (defun compute-vars (fun level var-locs
)
392 (declare (type clambda fun
) (type hash-table var-locs
))
394 (labels ((frob-leaf (leaf tn gensym-p
)
395 (let ((name (leaf-debug-name leaf
)))
396 (when (and name
(leaf-refs leaf
) (tn-offset tn
)
397 (or gensym-p
(symbol-package name
)))
398 (vars (cons leaf tn
)))))
399 (frob-lambda (x gensym-p
)
400 (dolist (leaf (lambda-vars x
))
401 (frob-leaf leaf
(leaf-info leaf
) gensym-p
))))
404 (dolist (x (ir2-physenv-closure (physenv-info (lambda-physenv fun
))))
405 (let ((thing (car x
)))
406 (when (lambda-var-p thing
)
407 (frob-leaf thing
(cdr x
) (= level
3)))))
409 (dolist (let (lambda-lets fun
))
410 (frob-lambda let
(= level
3)))))
412 (let ((sorted (sort (vars) #'string
<
414 (symbol-name (leaf-debug-name (car x
))))))
418 (buffer (make-array 0 :fill-pointer
0 :adjustable t
)))
419 (declare (type (or simple-string null
) prev-name
)
423 (name (symbol-name (leaf-debug-name var
))))
424 (cond ((and prev-name
(string= prev-name name
))
427 (setq id
0 prev-name name
)))
428 (dump-1-var fun var
(cdr x
) id nil buffer
)
429 (setf (gethash var var-locs
) i
)
431 (coerce buffer
'simple-vector
))))
433 ;;; Return a vector suitable for use as the DEBUG-FUN-VARS of
434 ;;; FUN, representing the arguments to FUN in minimal variable format.
435 (defun compute-minimal-vars (fun)
436 (declare (type clambda fun
))
437 (let ((buffer (make-array 0 :fill-pointer
0 :adjustable t
)))
438 (dolist (var (lambda-vars fun
))
439 (dump-1-var fun var
(leaf-info var
) 0 t buffer
))
440 (coerce buffer
'simple-vector
)))
442 ;;; Return VAR's relative position in the function's variables (determined
443 ;;; from the VAR-LOCS hashtable). If VAR is deleted, then return DELETED.
444 (defun debug-location-for (var var-locs
)
445 (declare (type lambda-var var
) (type hash-table var-locs
))
446 (let ((res (gethash var var-locs
)))
449 (aver (or (null (leaf-refs var
))
450 (not (tn-offset (leaf-info var
)))))
453 ;;;; arguments/returns
455 ;;; Return a vector to be used as the COMPILED-DEBUG-FUN-ARGS for FUN.
456 ;;; If FUN is the MAIN-ENTRY for an optional dispatch, then look at
457 ;;; the ARGLIST to determine the syntax, otherwise pretend all
458 ;;; arguments are fixed.
460 ;;; ### This assumption breaks down in EPs other than the main-entry,
461 ;;; since they may or may not have supplied-p vars, etc.
462 (defun compute-args (fun var-locs
)
463 (declare (type clambda fun
) (type hash-table var-locs
))
465 (let ((od (lambda-optional-dispatch fun
)))
466 (if (and od
(eq (optional-dispatch-main-entry od
) fun
))
467 (let ((actual-vars (lambda-vars fun
))
469 (labels ((one-arg (arg)
470 (let ((info (lambda-var-arg-info arg
))
471 (actual (pop actual-vars
)))
473 (case (arg-info-kind info
)
475 (res (arg-info-key info
)))
477 (let ((more (arg-info-default info
)))
478 (cond ((and (consp more
) (third more
))
479 (one-arg (first (arg-info-default info
)))
480 (one-arg (second (arg-info-default info
)))
481 (return-from one-arg
))
483 (setf (arg-info-default info
) t
)))
490 (setq saw-optional t
))))
491 (res (debug-location-for actual var-locs
))
492 (when (arg-info-supplied-p info
)
494 (res (debug-location-for (pop actual-vars
) var-locs
))))
496 (res (debug-location-for actual var-locs
)))))))
497 (dolist (arg (optional-dispatch-arglist od
))
499 (dolist (var (lambda-vars fun
))
500 (res (debug-location-for var var-locs
)))))
502 (coerce-to-smallest-eltype (res))))
504 ;;; Return a vector of SC offsets describing FUN's return locations.
505 ;;; (Must be known values return...)
506 (defun compute-debug-returns (fun)
507 (coerce-to-smallest-eltype
508 (mapcar (lambda (loc)
510 (return-info-locations (tail-set-info (lambda-tail-set fun
))))))
514 ;;; Return a C-D-F structure with all the mandatory slots filled in.
515 (defun dfun-from-fun (fun)
516 (declare (type clambda fun
))
517 (let* ((2env (physenv-info (lambda-physenv fun
)))
518 (dispatch (lambda-optional-dispatch fun
))
519 (main-p (and dispatch
520 (eq fun
(optional-dispatch-main-entry dispatch
)))))
521 (make-compiled-debug-fun
522 :name
(leaf-debug-name fun
)
523 :kind
(if main-p nil
(functional-kind fun
))
524 #!-fp-and-pc-standard-save
:return-pc
525 #!-fp-and-pc-standard-save
(tn-sc-offset (ir2-physenv-return-pc 2env
))
526 #!-fp-and-pc-standard-save
:old-fp
527 #!-fp-and-pc-standard-save
(tn-sc-offset (ir2-physenv-old-fp 2env
))
528 :start-pc
(label-position (ir2-physenv-environment-start 2env
))
529 :elsewhere-pc
(label-position (ir2-physenv-elsewhere-start 2env
))
530 :closure-save
(when (ir2-physenv-closure-save-tn 2env
)
531 (tn-sc-offset (ir2-physenv-closure-save-tn 2env
)))
532 #!+unwind-to-frame-and-call-vop
534 #!+unwind-to-frame-and-call-vop
535 (when (ir2-physenv-bsp-save-tn 2env
)
536 (tn-sc-offset (ir2-physenv-bsp-save-tn 2env
))))))
538 ;;; Return a complete C-D-F structure for FUN. This involves
539 ;;; determining the DEBUG-INFO level and filling in optional slots as
541 (defun compute-1-debug-fun (fun var-locs
)
542 (declare (type clambda fun
) (type hash-table var-locs
))
543 (let* ((dfun (dfun-from-fun fun
))
544 (actual-level (policy (lambda-bind fun
) compute-debug-fun
))
545 (level (if #!+sb-dyncount
*collect-dynamic-statistics
*
549 (toplevel-p (eq :toplevel
(compiled-debug-fun-kind dfun
))))
550 (cond ((or (zerop level
) toplevel-p
))
552 (let ((od (lambda-optional-dispatch fun
)))
554 (not (eq (optional-dispatch-main-entry od
) fun
)))))
555 (setf (compiled-debug-fun-vars dfun
)
556 (compute-minimal-vars fun
))
557 (setf (compiled-debug-fun-arguments dfun
) :minimal
))
559 (setf (compiled-debug-fun-vars dfun
)
560 (compute-vars fun level var-locs
))
561 (setf (compiled-debug-fun-arguments dfun
)
562 (compute-args fun var-locs
))))
564 (if (and (>= level
2) (not toplevel-p
))
565 (multiple-value-bind (blocks tlf-num form-number
)
566 (compute-debug-blocks fun var-locs
)
567 (setf (compiled-debug-fun-blocks dfun
) blocks
568 (compiled-debug-fun-tlf-number dfun
) tlf-num
569 (compiled-debug-fun-form-number dfun
) form-number
))
570 (multiple-value-bind (tlf-num form-number
) (find-tlf-number fun
)
571 (setf (compiled-debug-fun-tlf-number dfun
) tlf-num
572 (compiled-debug-fun-form-number dfun
) form-number
)))
574 (setf (compiled-debug-fun-returns dfun
) :standard
)
575 (let ((info (tail-set-info (lambda-tail-set fun
))))
577 (cond ((eq (return-info-kind info
) :unknown
)
578 (setf (compiled-debug-fun-returns dfun
)
581 (setf (compiled-debug-fun-returns dfun
)
582 (compute-debug-returns fun
)))))))
585 ;;;; full component dumping
587 ;;; Compute the full form (simple-vector) function map.
588 (defun compute-debug-fun-map (sorted)
589 (declare (list sorted
))
590 (let* ((len (1- (* (length sorted
) 2)))
591 (funs-vec (make-array len
)))
593 (sorted sorted
(cdr sorted
)))
596 (let ((dfun (car sorted
)))
598 (setf (svref funs-vec i
) (car dfun
)))
599 (setf (svref funs-vec
(1+ i
)) (cdr dfun
))))
602 ;;; Return a DEBUG-INFO structure describing COMPONENT. This has to be
603 ;;; called after assembly so that source map information is available.
604 (defun debug-info-for-component (component)
605 (declare (type component component
))
607 (var-locs (make-hash-table :test
'eq
))
608 (*byte-buffer
* (make-array 10
609 :element-type
'(unsigned-byte 8)
612 (dolist (lambda (component-lambdas component
))
614 (push (cons (label-position (block-label (lambda-block lambda
)))
615 (compute-1-debug-fun lambda var-locs
))
617 (let* ((sorted (sort dfuns
#'< :key
#'car
))
618 (fun-map (compute-debug-fun-map sorted
)))
619 (make-compiled-debug-info :name
(component-name component
)
622 ;;; Write BITS out to BYTE-BUFFER in backend byte order. The length of
623 ;;; BITS must be evenly divisible by eight.
624 (defun write-packed-bit-vector (bits byte-buffer
)
625 (declare (type simple-bit-vector bits
) (type byte-buffer byte-buffer
))
627 ;; Enforce constraint from CMU-CL-era comment.
628 (aver (zerop (mod (length bits
) 8)))
630 (multiple-value-bind (initial step done
)
631 (ecase *backend-byte-order
*
632 (:little-endian
(values 0 1 8))
633 (:big-endian
(values 7 -
1 -
1)))
634 (let ((shift initial
)
636 (dotimes (i (length bits
))
637 (let ((int (aref bits i
)))
638 (setf byte
(logior byte
(ash int shift
)))
641 (vector-push-extend byte byte-buffer
)
644 (unless (= shift initial
)
645 (vector-push-extend byte byte-buffer
))))