(sort insts #'> :key #'specializer-rank))
(defun specialization-error (insts)
- (error "~@<internal disassembler error: ~2I~_Instructions either aren't related or conflict in some way: ~4I~_~S~:>"
- insts))
+ (bug
+ "~@<Instructions either aren't related or conflict in some way: ~4I~_~S~:>"
+ insts))
;;; Given a list of instructions INSTS, Sees if one of these instructions is a
;;; more general form of all the others, in which case they are put into its
\f
(defstruct (offs-hook (:copier nil))
(offset 0 :type offset)
- (function (missing-arg) :type function)
+ (fun (missing-arg) :type function)
(before-address nil :type (member t nil)))
(defstruct (segment (:conc-name seg-)
(:copier nil))
(sap-maker (missing-arg)
:type (function () sb!sys:system-area-pointer))
- (length 0 :type length)
+ (length 0 :type disassem-length)
(virtual-location 0 :type address)
(storage-info nil :type (or null storage-info))
(code nil :type (or null sb!kernel:code-component))
(seg-virtual-location seg)
(seg-code seg)))))
\f
-;;; All state during disassembly. We store some seemingly redundant
-;;; information so that we can allow garbage collect during disassembly and
-;;; not get tripped up by a code block being moved...
-(defstruct (disassem-state (:conc-name dstate-)
- (:constructor %make-dstate)
- (:copier nil))
- ;; offset of current pos in segment
- (cur-offs 0 :type offset)
- ;; offset of next position
- (next-offs 0 :type offset)
- ;; a sap pointing to our segment
- (segment-sap (missing-arg) :type sb!sys:system-area-pointer)
- ;; the current segment
- (segment nil :type (or null segment))
- ;; what to align to in most cases
- (alignment sb!vm:n-word-bytes :type alignment)
- (byte-order :little-endian
- :type (member :big-endian :little-endian))
- ;; for user code to hang stuff off of
- (properties nil :type list)
- (filtered-values (make-array max-filtered-value-index)
- :type filtered-value-vector)
- ;; used for prettifying printing
- (addr-print-len nil :type (or null (integer 0 20)))
- (argument-column 0 :type column)
- ;; to make output look nicer
- (output-state :beginning
- :type (member :beginning
- :block-boundary
- nil))
-
- ;; alist of (address . label-number)
- (labels nil :type list)
- ;; same as LABELS slot data, but in a different form
- (label-hash (make-hash-table) :type hash-table)
- ;; list of function
- (fun-hooks nil :type list)
-
- ;; alist of (address . label-number), popped as it's used
- (cur-labels nil :type list) ;
- ;; list of offs-hook, popped as it's used
- (cur-offs-hooks nil :type list)
-
- ;; for the current location
- (notes nil :type list)
-
- ;; currently active source variables
- (current-valid-locations nil :type (or null (vector bit))))
-(def!method print-object ((dstate disassem-state) stream)
- (print-unreadable-object (dstate stream :type t)
- (format stream
- "+~W~@[ in ~S~]"
- (dstate-cur-offs dstate)
- (dstate-segment dstate))))
-
-;;; Return the absolute address of the current instruction in DSTATE.
-(defun dstate-cur-addr (dstate)
- (the address (+ (seg-virtual-location (dstate-segment dstate))
- (dstate-cur-offs dstate))))
-
-;;; Return the absolute address of the next instruction in DSTATE.
-(defun dstate-next-addr (dstate)
- (the address (+ (seg-virtual-location (dstate-segment dstate))
- (dstate-next-offs dstate))))
-\f
;;;; function ops
(defun fun-self (fun)
(declare (type compiled-function fun))
(sb!kernel:%simple-fun-next fun))
-(defun fun-address (function)
- (declare (type compiled-function function))
- (- (sb!kernel:get-lisp-obj-address function) sb!vm:fun-pointer-lowtag))
+(defun fun-address (fun)
+ (declare (type compiled-function fun))
+ (ecase (sb!kernel:widetag-of fun)
+ (#.sb!vm:simple-fun-header-widetag
+ (- (sb!kernel:get-lisp-obj-address fun) sb!vm:fun-pointer-lowtag))
+ (#.sb!vm:closure-header-widetag
+ (fun-address (sb!kernel:%closure-fun fun)))
+ (#.sb!vm:funcallable-instance-header-widetag
+ (fun-address (sb!kernel:funcallable-instance-fun fun)))))
;;; the offset of FUNCTION from the start of its code-component's
;;; instruction area
(declare (type sb!kernel:code-component code-component))
(sb!sys:sap-int (sb!kernel:code-instructions code-component)))
+;;; unused as of sbcl-0.pre7.129
+#|
;;; Return the first function in CODE-COMPONENT.
(defun code-first-function (code-component)
(declare (type sb!kernel:code-component code-component))
(sb!kernel:code-header-ref code-component
sb!vm:code-trace-table-offset-slot))
+|#
(defun segment-offs-to-code-offs (offset segment)
(sb!sys:without-gcing
(1- lra-size))))
sb!vm:return-pc-header-widetag))
(unless (null stream)
- (princ '.lra stream))
- (incf (dstate-next-offs dstate) lra-size))
+ (note "possible LRA header" dstate)))
nil)
;;; Print the fun-header (entry-point) pseudo-instruction at the
(setf (dstate-cur-offs dstate) 0)
(setf (dstate-cur-labels dstate) (dstate-labels dstate)))
-(defun do-offs-hooks (before-address stream dstate)
+(defun call-offs-hooks (before-address stream dstate)
(declare (type (or null stream) stream)
(type disassem-state dstate))
(let ((cur-offs (dstate-cur-offs dstate)))
(unless (= (dstate-next-offs dstate) cur-offs)
(return)))))))
-(defun do-fun-hooks (chunk stream dstate)
+(defun call-fun-hooks (chunk stream dstate)
(let ((hooks (dstate-fun-hooks dstate))
(cur-offs (dstate-cur-offs dstate)))
(setf (dstate-next-offs dstate) cur-offs)
(when (> words 0)
(print-words words stream dstate))
(when (> bytes 0)
- (print-bytes bytes stream dstate))))
+ (print-inst bytes stream dstate)))
+ (print-bytes alignment stream dstate))
(incf (dstate-next-offs dstate) alignment)))
;;; Iterate through the instructions in SEGMENT, calling FUNCTION for
(setf (dstate-next-offs dstate) (dstate-cur-offs dstate))
- (do-offs-hooks t stream dstate)
+ (call-offs-hooks t stream dstate)
(unless (or prefix-p (null stream))
(print-current-address stream dstate))
- (do-offs-hooks nil stream dstate)
+ (call-offs-hooks nil stream dstate)
(unless (> (dstate-next-offs dstate) (dstate-cur-offs dstate))
(sb!sys:without-gcing
(sap-ref-dchunk (dstate-segment-sap dstate)
(dstate-cur-offs dstate)
(dstate-byte-order dstate))))
- (let ((fun-prefix-p (do-fun-hooks chunk stream dstate)))
+ (let ((fun-prefix-p (call-fun-hooks chunk stream dstate)))
(if (> (dstate-next-offs dstate) (dstate-cur-offs dstate))
(setf prefix-p fun-prefix-p)
- (let ((inst (find-inst chunk ispace)))
- (cond ((null inst)
- (handle-bogus-instruction stream dstate))
- (t
- (setf (dstate-next-offs dstate)
- (+ (dstate-cur-offs dstate)
- (inst-length inst)))
-
+ (let ((inst (find-inst chunk ispace)))
+ (cond ((null inst)
+ (handle-bogus-instruction stream dstate))
+ (t
+ (setf (dstate-inst-properties dstate) nil)
+ (setf (dstate-next-offs dstate)
+ (+ (dstate-cur-offs dstate)
+ (inst-length inst)))
+ (let ((orig-next (dstate-next-offs dstate)))
+ (print-inst (inst-length inst) stream dstate :trailing-space nil)
(let ((prefilter (inst-prefilter inst))
(control (inst-control inst)))
(when prefilter
(funcall prefilter chunk dstate))
-
+
+ ;; print any instruction bytes recognized by the prefilter which calls read-suffix
+ ;; and updates next-offs
+ (when stream
+ (let ((suffix-len (- (dstate-next-offs dstate) orig-next)))
+ (when (plusp suffix-len)
+ (print-inst suffix-len stream dstate :offset (inst-length inst) :trailing-space nil))
+ (dotimes (i (- *disassem-inst-column-width* (* 2 (+ (inst-length inst) suffix-len))))
+ (write-char #\space stream)))
+ (write-char #\space stream))
+
(funcall function chunk inst)
-
+
(setf prefix-p (null (inst-printer inst)))
-
+
(when control
- (funcall control chunk inst stream dstate))))))
- )))))
-
+ (funcall control chunk inst stream dstate))
+ ))))))))))
+
(setf (dstate-cur-offs dstate) (dstate-next-offs dstate))
-
+
(unless (null stream)
(unless prefix-p
(print-notes-and-newline stream dstate))
(fresh-line stream)
(setf (dstate-notes dstate) nil)))
+;;; Print NUM instruction bytes to STREAM as hex values.
+(defun print-inst (num stream dstate &key (offset 0) (trailing-space t))
+ (let ((sap (dstate-segment-sap dstate))
+ (start-offs (+ offset (dstate-cur-offs dstate))))
+ (dotimes (offs num)
+ (format stream "~2,'0x" (sb!sys:sap-ref-8 sap (+ offs start-offs))))
+ (when trailing-space
+ (dotimes (i (- *disassem-inst-column-width* (* 2 num)))
+ (write-char #\space stream))
+ (write-char #\space stream))))
+
;;; Disassemble NUM bytes to STREAM as simple `BYTE' instructions.
(defun print-bytes (num stream dstate)
(declare (type offset num)
((null fun))
(let ((offset (code-offs-to-segment-offs (fun-offset fun) segment)))
(when (<= 0 offset length)
- (push (make-offs-hook :offset offset :function #'fun-header-hook)
+ (push (make-offs-hook :offset offset :fun #'fun-header-hook)
(seg-hooks segment))))))
\f
;;; A SAP-MAKER is a no-argument function that returns a SAP.
debug-fun source-form-cache
hooks)
(declare (type (function () sb!sys:system-area-pointer) sap-maker)
- (type length length)
+ (type disassem-length length)
(type (or null address) virtual-location)
(type (or null sb!di:debug-fun) debug-fun)
(type (or null source-form-cache) source-form-cache))
(file-position f char-offset))
(t
(warn "Source file ~S has been modified; ~@
- using form offset instead of ~
+ using form offset instead of ~
file index."
name)
(let ((*read-suppress* t))
nil)
((> form-number (length mapping-table))
(warn "bogus form-number in form! The source file has probably ~@
- been changed too much to cope with.")
+ been changed too much to cope with.")
(when cache
;; Disable future warnings.
(setf (sfcache-toplevel-form cache) nil))
(let ((last-block-pc -1))
(flet ((add-hook (pc fun &optional before-address)
(push (make-offs-hook
- :offset pc ;; ##### FIX to account for non-zero offs in code
- :function fun
+ :offset pc ;; ### FIX to account for non-zero offs in code
+ :fun fun
:before-address before-address)
(seg-hooks segment))))
(handler-case
(storage-info-for-debug-fun debug-fun))
(add-source-tracking-hooks segment debug-fun sfcache)
(let ((kind (sb!di:debug-fun-kind debug-fun)))
- (flet ((anh (n)
+ (flet ((add-new-hook (n)
(push (make-offs-hook
:offset 0
- :function (lambda (stream dstate)
- (declare (ignore stream))
- (note n dstate)))
+ :fun (lambda (stream dstate)
+ (declare (ignore stream))
+ (note n dstate)))
(seg-hooks segment))))
(case kind
(:external)
((nil)
- (anh "no-arg-parsing entry point"))
+ (add-new-hook "no-arg-parsing entry point"))
(t
- (anh (lambda (stream)
- (format stream "~S entry point" kind)))))))))
+ (add-new-hook (lambda (stream)
+ (format stream "~S entry point" kind)))))))))
\f
;;; Return a list of the segments of memory containing machine code
;;; instructions for FUNCTION.
(length (code-inst-area-length code)))
(declare (type sb!kernel:code-component code)
(type offset start-offset)
- (type length length))
+ (type disassem-length length))
(let ((segments nil))
(when code
(let ((fun-map (code-fun-map code))
(compile nil lambda)))
(defun compiled-fun-or-lose (thing &optional (name thing))
- (cond ((or (symbolp thing)
- (and (listp thing)
- (eq (car thing) 'setf)))
+ (cond ((legal-fun-name-p thing)
(compiled-fun-or-lose (fdefinition thing) thing))
((functionp thing)
thing)
code-component
(use-labels t))
(declare (type (or address sb!sys:system-area-pointer) address)
- (type length length)
+ (type disassem-length length)
(type stream stream)
(type (or null sb!kernel:code-component) code-component)
(type (member t nil) use-labels))
(setf *assembler-routines-by-addr*
(invert-address-hash sb!fasl:*assembler-routines*))
(setf *assembler-routines-by-addr*
- (invert-address-hash sb!fasl:*static-foreign-symbols*
+ (invert-address-hash sb!sys:*static-foreign-symbols*
*assembler-routines-by-addr*)))
(gethash address *assembler-routines-by-addr*))
\f
(defun sap-ref-int (sap offset length byte-order)
(declare (type sb!sys:system-area-pointer sap)
(type (unsigned-byte 16) offset)
- (type (member 1 2 4) length)
+ (type (member 1 2 4 8) length)
(type (member :little-endian :big-endian) byte-order)
(optimize (speed 3) (safety 0)))
(ecase length
(+ (sb!sys:sap-ref-8 sap offset)
(ash (sb!sys:sap-ref-8 sap (+ 1 offset)) 8)
(ash (sb!sys:sap-ref-8 sap (+ 2 offset)) 16)
- (ash (sb!sys:sap-ref-8 sap (+ 3 offset)) 24))))))
+ (ash (sb!sys:sap-ref-8 sap (+ 3 offset)) 24))))
+ (8 (if (eq byte-order :big-endian)
+ (+ (ash (sb!sys:sap-ref-8 sap offset) 56)
+ (ash (sb!sys:sap-ref-8 sap (+ 1 offset)) 48)
+ (ash (sb!sys:sap-ref-8 sap (+ 2 offset)) 40)
+ (ash (sb!sys:sap-ref-8 sap (+ 3 offset)) 32)
+ (ash (sb!sys:sap-ref-8 sap (+ 4 offset)) 24)
+ (ash (sb!sys:sap-ref-8 sap (+ 5 offset)) 16)
+ (ash (sb!sys:sap-ref-8 sap (+ 6 offset)) 8)
+ (sb!sys:sap-ref-8 sap (+ 7 offset)))
+ (+ (sb!sys:sap-ref-8 sap offset)
+ (ash (sb!sys:sap-ref-8 sap (+ 1 offset)) 8)
+ (ash (sb!sys:sap-ref-8 sap (+ 2 offset)) 16)
+ (ash (sb!sys:sap-ref-8 sap (+ 3 offset)) 24)
+ (ash (sb!sys:sap-ref-8 sap (+ 4 offset)) 32)
+ (ash (sb!sys:sap-ref-8 sap (+ 5 offset)) 40)
+ (ash (sb!sys:sap-ref-8 sap (+ 6 offset)) 48)
+ (ash (sb!sys:sap-ref-8 sap (+ 7 offset)) 56))))))
(defun read-suffix (length dstate)
- (declare (type (member 8 16 32) length)
+ (declare (type (member 8 16 32 64) length)
(type disassem-state dstate)
(optimize (speed 3) (safety 0)))
- (let ((length (ecase length (8 1) (16 2) (32 4))))
- (declare (type (unsigned-byte 3) length))
+ (let ((length (ecase length (8 1) (16 2) (32 4) (64 8))))
+ (declare (type (unsigned-byte 4) length))
(prog1
(sap-ref-int (dstate-segment-sap dstate)
(dstate-next-offs dstate)
(declare (type disassem-state dstate))
(unless (typep address 'address)
(return-from maybe-note-assembler-routine nil))
- (let ((name (find-assembler-routine address)))
+ (let ((name (or
+ #!+linkage-table
+ (sb!sys:foreign-symbol-in-address (sb!sys:int-sap address))
+ (find-assembler-routine address))))
(unless (null name)
(note (lambda (stream)
(if note-address-p
assoc-with
(sb!di:debug-var-symbol
(aref (dstate-debug-vars dstate)
- storage-location))
- stream))
+ storage-location))))
dstate)
t)))
\f
(let ((num (pop lengths)))
(print-notes-and-newline stream dstate)
(print-current-address stream dstate)
+ (print-inst num stream dstate)
(print-bytes num stream dstate)
(incf (dstate-cur-offs dstate) num)
(when note