0.8.18.34:
[sbcl.git] / src / compiler / target-disassem.lisp
index 8e042ee..cb8c476 100644 (file)
@@ -44,8 +44,9 @@
   (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
                                         (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-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