home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 49
/
Amiga_Dream_49.iso
/
atari
/
texte
/
1857bin-d2.zoo
/
lisp
/
disass.el
< prev
next >
Wrap
Lisp/Scheme
|
1991-12-02
|
12KB
|
447 lines
;;; Disassembler for compiled Emacs Lisp code
;; Copyright (C) 1986 Free Software Foundation
;;; By Doug Cutting (doug@csli.stanford.edu)
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 1, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
(require 'byte-compile "bytecomp")
(defvar disassemble-column-1-indent 4 "*")
(defvar disassemble-column-2-indent 9 "*")
(defvar disassemble-recursive-indent 3 "*")
;(defun d (x)
; (interactive "xDiss ")
; (with-output-to-temp-buffer "*Disassemble*"
; (disassemble-internal (list 'lambda '() x ''return-value)
; standard-output 0 t)))
(defun disassemble (object &optional stream indent interactive-p)
"Print disassembled code for OBJECT on (optional) STREAM.
OBJECT can be a function name, lambda expression or any function object
returned by SYMBOL-FUNCTION. If OBJECT is not already compiled, we will
compile it (but not redefine it)."
(interactive (list (intern (completing-read "Disassemble function: "
obarray 'fboundp t))
nil 0 t))
(or indent (setq indent 0)) ;Default indent to zero
(if interactive-p
(with-output-to-temp-buffer "*Disassemble*"
(disassemble-internal object standard-output indent t))
(disassemble-internal object (or stream standard-output) indent nil))
nil)
(defun disassemble-internal (obj stream indent interactive-p)
(let ((macro 'nil)
(name 'nil)
(doc 'nil)
args)
(while (symbolp obj)
(setq name obj
obj (symbol-function obj)))
(if (subrp obj)
(error "Can't disassemble #<subr %s>" name))
(if (eq (car obj) 'macro) ;handle macros
(setq macro t
obj (cdr obj)))
(if (not (eq (car obj) 'lambda))
(error "not a function"))
(if (assq 'byte-code obj)
nil
(if interactive-p (message (if name
"Compiling %s's definition..."
"Compiling definition...")
name))
(setq obj (byte-compile-lambda obj))
(if interactive-p (message "Done compiling. Disassembling...")))
(setq obj (cdr obj)) ;throw lambda away
(setq args (car obj)) ;save arg list
(setq obj (cdr obj))
(write-spaces indent stream)
(princ (format "byte code%s%s%s:\n"
(if (or macro name) " for" "")
(if macro " macro" "")
(if name (format " %s" name) ""))
stream)
(let ((doc (and (stringp (car obj)) (car obj))))
(if doc
(progn (setq obj (cdr obj))
(write-spaces indent stream)
(princ " doc: " stream)
(princ doc stream)
(terpri stream))))
(write-spaces indent stream)
(princ " args: " stream)
(prin1 args stream)
(terpri stream)
(let ((interactive (car (cdr (assq 'interactive obj)))))
(if interactive
(progn (write-spaces indent stream)
(princ " interactive: " stream)
(if (eq (car-safe interactive) 'byte-code)
(disassemble-1 interactive stream
(+ indent disassemble-recursive-indent))
(prin1 interactive stream)
(terpri stream)))))
(setq obj (assq 'byte-code obj)) ;obj is now call to byte-code
(disassemble-1 obj stream indent))
(if interactive-p
(message "")))
(defun disassemble-1 (obj &optional stream indent)
"Prints the byte-code call OBJ to (optional) STREAM.
OBJ should be a call to BYTE-CODE generated by the byte compiler."
(or indent (setq indent 0)) ;default indent to 0
(or stream (setq stream standard-output))
(let ((bytes (car (cdr obj))) ;the byte code
(ptr -1) ;where we are in it
(constants (car (cdr (cdr obj)))) ;constant vector
;(next-indent indent)
offset tmp length)
(setq length (length bytes))
(terpri stream)
(while (< (setq ptr (1+ ptr)) length)
;(setq indent next-indent)
(write-spaces indent stream) ;indent to recursive indent
(princ (setq tmp (prin1-to-string ptr)) stream) ;print line #
(write-char ?\ stream)
(write-spaces (- disassemble-column-1-indent (length tmp) 1)
stream)
(setq op (aref bytes ptr)) ;fetch opcode
;; Note: as offsets are either encoded in opcodes or stored as
;; bytes in the code, this function (disassemble-offset)
;; can set OP and/or PTR.
(setq offset (disassemble-offset));fetch offset
(setq tmp (aref byte-code-vector op))
(if (consp tmp)
(setq ;next-indent (if (numberp (cdr tmp))
; (+ indent (cdr tmp))
; (+ indent (funcall (cdr tmp) offset)))
tmp (car tmp)))
(setq tmp (symbol-name tmp))
(princ tmp stream) ;print op-name for opcode
(if (null offset)
nil
(write-char ?\ stream)
(write-spaces (- disassemble-column-2-indent (length tmp) 1)
stream) ;indent to col 2
(princ ;print offset
(cond ((or (eq op byte-varref)
(eq op byte-varset)
(eq op byte-varbind))
;; it's a varname (atom)
(aref constants offset)) ;fetch it from constants
((or (eq op byte-goto)
(eq op byte-goto-if-nil)
(eq op byte-goto-if-not-nil)
(eq op byte-goto-if-nil-else-pop)
(eq op byte-goto-if-not-nil-else-pop)
(eq op byte-call)
(eq op byte-unbind))
;; it's a number
offset) ;return it
((or (eq op byte-constant)
(eq op byte-constant2))
;; it's a constant
(setq tmp (aref constants offset))
;; but is constant byte code?
(cond ((and (eq (car-safe tmp) 'lambda)
(assq 'byte-code tmp))
(princ "<compiled lambda>" stream)
(terpri stream)
(disassemble ;recurse on compiled lambda
tmp
stream
(+ indent disassemble-recursive-indent))
"")
((eq (car-safe tmp) 'byte-code)
(princ "<byte code>" stream)
(terpri stream)
(disassemble-1 ;recurse on byte-code object
tmp
stream
(+ indent disassemble-recursive-indent))
"")
((eq (car-safe (car-safe tmp)) 'byte-code)
(princ "(<byte code>...)" stream)
(terpri stream)
(mapcar ;recurse on list of byte-code objects
(function (lambda (obj)
(disassemble-1
obj
stream
(+ indent disassemble-recursive-indent))))
tmp)
"")
((and (eq tmp 'byte-code)
(eq (aref bytes (+ ptr 4)) (+ byte-call 3)))
;; this won't catch cases where args are pushed w/
;; constant2.
(setq ptr (+ ptr 4))
"<compiled call to byte-code. compiled code compiled?>")
(t
;; really just a constant
(let ((print-escape-newlines t))
(prin1-to-string tmp)))))
(t "<error in disassembler>"))
stream))
(terpri stream)))
nil)
(defun disassemble-offset ()
"Don't call this!"
;; fetch and return the offset for the current opcode.
;; return NIL if this opcode has no offset
;; OP, PTR and BYTES are used and set dynamically
(let (tem)
(cond ((< op byte-nth)
(setq tem (logand op 7))
(setq op (logand op 248))
(cond ((eq tem 6)
(setq ptr (1+ ptr)) ;offset in next byte
(aref bytes ptr))
((eq tem 7)
(setq ptr (1+ ptr)) ;offset in next 2 bytes
(+ (aref bytes ptr)
(progn (setq ptr (1+ ptr))
(lsh (aref bytes ptr) 8))))
(t tem))) ;offset was in opcode
((>= op byte-constant)
(setq tem (- op byte-constant)) ;offset in opcode
(setq op byte-constant)
tem)
((or (= op byte-constant2)
(and (>= op byte-goto)
(<= op byte-goto-if-not-nil-else-pop)))
(setq ptr (1+ ptr)) ;offset in next 2 bytes
(+ (aref bytes ptr)
(progn (setq ptr (1+ ptr))
(lsh (aref bytes ptr) 8))))
(t nil)))) ;no offset
(defun write-spaces (n &optional stream)
"Print N spaces to (optional) STREAM."
(or stream (setq stream standard-output))
(if (< n 0) (setq n 0))
(if (eq stream (current-buffer))
(insert-char ?\ n)
(while (> n 0)
(write-char ?\ stream)
(setq n (1- n)))))
(defconst byte-code-vector
'[<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(varref . 1)
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(varset . -1)
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(varbind . 0);Pops a value, "pushes" a binding
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(call . -); #'-, not -1!
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(unbind . -);"pops" bindings
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(nth . -1)
symbolp
consp
stringp
listp
(eq . -1)
(memq . -1)
not
car
cdr
(cons . -1)
list1
(list2 . -1)
(list3 . -2)
(list4 . -3)
length
(aref . -1)
(aset . -2)
symbol-value
symbol-function
(set . -1)
(fset . -1)
(get . -1)
(substring . -2)
(concat2 . -1)
(concat3 . -2)
(concat4 . -3)
sub1
add1
(eqlsign . -1) ;=
(gtr . -1) ;>
(lss . -1) ;<
(leq . -1) ;<=
(geq . -1) ;>=
(diff . -1) ;-
negate ;unary -
(plus . -1) ;+
(max . -1)
(min . -1)
<not-an-opcode>
(point . 1)
(mark\(obsolete\) . 1)
goto-char
insert
(point-max . 1)
(point-min . 1)
char-after
(following-char . 1)
(preceding-char . 1)
(current-column . 1)
(indent-to . 1)
(scan-buffer\(obsolete\) . -2)
(eolp . 1)
(eobp . 1)
(bolp . 1)
(bobp . 1)
(current-buffer . 1)
set-buffer
(read-char . 1)
set-mark\(obsolete\)
interactive-p
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(constant2 . 1)
goto;>>>
goto-if-nil;>>
goto-if-not-nil;>>
(goto-if-nil-else-pop . -1)
(goto-if-not-nil-else-pop . -1)
return
(discard . -1)
(dup . 1)
(save-excursion . 1);Pushes a binding
(save-window-excursion . 1);Pushes a binding
(save-restriction . 1);Pushes a binding
(catch . -1);Takes one argument, returns a value
(unwind-protect . 1);Takes one argument, pushes a binding, returns a value
(condition-case . -2);Takes three arguments, returns a value
(temp-output-buffer-setup . -1)
temp-output-buffer-show
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
<not-an-opcode>
(constant . 1)
])