|
|
1.1 ! root 1: ;;; Disassembler for compiled Emacs Lisp code ! 2: ;; Copyright (C) 1986 Free Software Foundation ! 3: ;;; By Doug Cutting ([email protected]) ! 4: ! 5: ;; This file is part of GNU Emacs. ! 6: ! 7: ;; GNU Emacs is free software; you can redistribute it and/or modify ! 8: ;; it under the terms of the GNU General Public License as published by ! 9: ;; the Free Software Foundation; either version 1, or (at your option) ! 10: ;; any later version. ! 11: ! 12: ;; GNU Emacs is distributed in the hope that it will be useful, ! 13: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: ;; GNU General Public License for more details. ! 16: ! 17: ;; You should have received a copy of the GNU General Public License ! 18: ;; along with GNU Emacs; see the file COPYING. If not, write to ! 19: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 20: ! 21: ! 22: (require 'byte-compile "bytecomp") ! 23: ! 24: (defvar disassemble-column-1-indent 4 "*") ! 25: ! 26: (defvar disassemble-column-2-indent 9 "*") ! 27: ! 28: (defvar disassemble-recursive-indent 3 "*") ! 29: ! 30: ;(defun d (x) ! 31: ; (interactive "xDiss ") ! 32: ; (with-output-to-temp-buffer "*Disassemble*" ! 33: ; (disassemble-internal (list 'lambda '() x ''return-value) ! 34: ; standard-output 0 t))) ! 35: ! 36: (defun disassemble (object &optional stream indent interactive-p) ! 37: "Print disassembled code for OBJECT on (optional) STREAM. ! 38: OBJECT can be a function name, lambda expression or any function object ! 39: returned by SYMBOL-FUNCTION. If OBJECT is not already compiled, we will ! 40: compile it (but not redefine it)." ! 41: (interactive (list (intern (completing-read "Disassemble function: " ! 42: obarray 'fboundp t)) ! 43: nil 0 t)) ! 44: (or indent (setq indent 0)) ;Default indent to zero ! 45: (if interactive-p ! 46: (with-output-to-temp-buffer "*Disassemble*" ! 47: (disassemble-internal object standard-output indent t)) ! 48: (disassemble-internal object (or stream standard-output) indent nil)) ! 49: nil) ! 50: ! 51: (defun disassemble-internal (obj stream indent interactive-p) ! 52: (let ((macro 'nil) ! 53: (name 'nil) ! 54: (doc 'nil) ! 55: args) ! 56: (while (symbolp obj) ! 57: (setq name obj ! 58: obj (symbol-function obj))) ! 59: (if (subrp obj) ! 60: (error "Can't disassemble #<subr %s>" name)) ! 61: (if (eq (car obj) 'macro) ;handle macros ! 62: (setq macro t ! 63: obj (cdr obj))) ! 64: (if (not (eq (car obj) 'lambda)) ! 65: (error "not a function")) ! 66: (if (assq 'byte-code obj) ! 67: nil ! 68: (if interactive-p (message (if name ! 69: "Compiling %s's definition..." ! 70: "Compiling definition...") ! 71: name)) ! 72: (setq obj (byte-compile-lambda obj)) ! 73: (if interactive-p (message "Done compiling. Disassembling..."))) ! 74: (setq obj (cdr obj)) ;throw lambda away ! 75: (setq args (car obj)) ;save arg list ! 76: (setq obj (cdr obj)) ! 77: (write-spaces indent stream) ! 78: (princ (format "byte code%s%s%s:\n" ! 79: (if (or macro name) " for" "") ! 80: (if macro " macro" "") ! 81: (if name (format " %s" name) "")) ! 82: stream) ! 83: (let ((doc (and (stringp (car obj)) (car obj)))) ! 84: (if doc ! 85: (progn (setq obj (cdr obj)) ! 86: (write-spaces indent stream) ! 87: (princ " doc: " stream) ! 88: (princ doc stream) ! 89: (terpri stream)))) ! 90: (write-spaces indent stream) ! 91: (princ " args: " stream) ! 92: (prin1 args stream) ! 93: (terpri stream) ! 94: (let ((interactive (car (cdr (assq 'interactive obj))))) ! 95: (if interactive ! 96: (progn (write-spaces indent stream) ! 97: (princ " interactive: " stream) ! 98: (if (eq (car-safe interactive) 'byte-code) ! 99: (disassemble-1 interactive stream ! 100: (+ indent disassemble-recursive-indent)) ! 101: (prin1 interactive stream) ! 102: (terpri stream))))) ! 103: (setq obj (assq 'byte-code obj)) ;obj is now call to byte-code ! 104: (disassemble-1 obj stream indent)) ! 105: (if interactive-p ! 106: (message ""))) ! 107: ! 108: (defun disassemble-1 (obj &optional stream indent) ! 109: "Prints the byte-code call OBJ to (optional) STREAM. ! 110: OBJ should be a call to BYTE-CODE generated by the byte compiler." ! 111: (or indent (setq indent 0)) ;default indent to 0 ! 112: (or stream (setq stream standard-output)) ! 113: (let ((bytes (car (cdr obj))) ;the byte code ! 114: (ptr -1) ;where we are in it ! 115: (constants (car (cdr (cdr obj)))) ;constant vector ! 116: ;(next-indent indent) ! 117: offset tmp length) ! 118: (setq length (length bytes)) ! 119: (terpri stream) ! 120: (while (< (setq ptr (1+ ptr)) length) ! 121: ;(setq indent next-indent) ! 122: (write-spaces indent stream) ;indent to recursive indent ! 123: (princ (setq tmp (prin1-to-string ptr)) stream) ;print line # ! 124: (write-char ?\ stream) ! 125: (write-spaces (- disassemble-column-1-indent (length tmp) 1) ! 126: stream) ! 127: (setq op (aref bytes ptr)) ;fetch opcode ! 128: ;; Note: as offsets are either encoded in opcodes or stored as ! 129: ;; bytes in the code, this function (disassemble-offset) ! 130: ;; can set OP and/or PTR. ! 131: (setq offset (disassemble-offset));fetch offset ! 132: (setq tmp (aref byte-code-vector op)) ! 133: (if (consp tmp) ! 134: (setq ;next-indent (if (numberp (cdr tmp)) ! 135: ; (+ indent (cdr tmp)) ! 136: ; (+ indent (funcall (cdr tmp) offset))) ! 137: tmp (car tmp))) ! 138: (setq tmp (symbol-name tmp)) ! 139: (princ tmp stream) ;print op-name for opcode ! 140: (if (null offset) ! 141: nil ! 142: (write-char ?\ stream) ! 143: (write-spaces (- disassemble-column-2-indent (length tmp) 1) ! 144: stream) ;indent to col 2 ! 145: (princ ;print offset ! 146: (cond ((or (eq op byte-varref) ! 147: (eq op byte-varset) ! 148: (eq op byte-varbind)) ! 149: ;; it's a varname (atom) ! 150: (aref constants offset)) ;fetch it from constants ! 151: ((or (eq op byte-goto) ! 152: (eq op byte-goto-if-nil) ! 153: (eq op byte-goto-if-not-nil) ! 154: (eq op byte-goto-if-nil-else-pop) ! 155: (eq op byte-goto-if-not-nil-else-pop) ! 156: (eq op byte-call) ! 157: (eq op byte-unbind)) ! 158: ;; it's a number ! 159: offset) ;return it ! 160: ((or (eq op byte-constant) ! 161: (eq op byte-constant2)) ! 162: ;; it's a constant ! 163: (setq tmp (aref constants offset)) ! 164: ;; but is constant byte code? ! 165: (cond ((and (eq (car-safe tmp) 'lambda) ! 166: (assq 'byte-code tmp)) ! 167: (princ "<compiled lambda>" stream) ! 168: (terpri stream) ! 169: (disassemble ;recurse on compiled lambda ! 170: tmp ! 171: stream ! 172: (+ indent disassemble-recursive-indent)) ! 173: "") ! 174: ((eq (car-safe tmp) 'byte-code) ! 175: (princ "<byte code>" stream) ! 176: (terpri stream) ! 177: (disassemble-1 ;recurse on byte-code object ! 178: tmp ! 179: stream ! 180: (+ indent disassemble-recursive-indent)) ! 181: "") ! 182: ((eq (car-safe (car-safe tmp)) 'byte-code) ! 183: (princ "(<byte code>...)" stream) ! 184: (terpri stream) ! 185: (mapcar ;recurse on list of byte-code objects ! 186: (function (lambda (obj) ! 187: (disassemble-1 ! 188: obj ! 189: stream ! 190: (+ indent disassemble-recursive-indent)))) ! 191: tmp) ! 192: "") ! 193: ((and (eq tmp 'byte-code) ! 194: (eq (aref bytes (+ ptr 4)) (+ byte-call 3))) ! 195: ;; this won't catch cases where args are pushed w/ ! 196: ;; constant2. ! 197: (setq ptr (+ ptr 4)) ! 198: "<compiled call to byte-code. compiled code compiled?>") ! 199: (t ! 200: ;; really just a constant ! 201: (let ((print-escape-newlines t)) ! 202: (prin1-to-string tmp))))) ! 203: (t "<error in disassembler>")) ! 204: stream)) ! 205: (terpri stream))) ! 206: nil) ! 207: ! 208: ! 209: (defun disassemble-offset () ! 210: "Don't call this!" ! 211: ;; fetch and return the offset for the current opcode. ! 212: ;; return NIL if this opcode has no offset ! 213: ;; OP, PTR and BYTES are used and set dynamically ! 214: (let (tem) ! 215: (cond ((< op byte-nth) ! 216: (setq tem (logand op 7)) ! 217: (setq op (logand op 248)) ! 218: (cond ((eq tem 6) ! 219: (setq ptr (1+ ptr)) ;offset in next byte ! 220: (aref bytes ptr)) ! 221: ((eq tem 7) ! 222: (setq ptr (1+ ptr)) ;offset in next 2 bytes ! 223: (+ (aref bytes ptr) ! 224: (progn (setq ptr (1+ ptr)) ! 225: (lsh (aref bytes ptr) 8)))) ! 226: (t tem))) ;offset was in opcode ! 227: ((>= op byte-constant) ! 228: (setq tem (- op byte-constant)) ;offset in opcode ! 229: (setq op byte-constant) ! 230: tem) ! 231: ((or (= op byte-constant2) ! 232: (and (>= op byte-goto) ! 233: (<= op byte-goto-if-not-nil-else-pop))) ! 234: (setq ptr (1+ ptr)) ;offset in next 2 bytes ! 235: (+ (aref bytes ptr) ! 236: (progn (setq ptr (1+ ptr)) ! 237: (lsh (aref bytes ptr) 8)))) ! 238: (t nil)))) ;no offset ! 239: ! 240: ! 241: (defun write-spaces (n &optional stream) ! 242: "Print N spaces to (optional) STREAM." ! 243: (or stream (setq stream standard-output)) ! 244: (if (< n 0) (setq n 0)) ! 245: (if (eq stream (current-buffer)) ! 246: (insert-char ?\ n) ! 247: (while (> n 0) ! 248: (write-char ?\ stream) ! 249: (setq n (1- n))))) ! 250: ! 251: (defconst byte-code-vector ! 252: '[<not-an-opcode> ! 253: <not-an-opcode> ! 254: <not-an-opcode> ! 255: <not-an-opcode> ! 256: <not-an-opcode> ! 257: <not-an-opcode> ! 258: <not-an-opcode> ! 259: <not-an-opcode> ! 260: (varref . 1) ! 261: <not-an-opcode> ! 262: <not-an-opcode> ! 263: <not-an-opcode> ! 264: <not-an-opcode> ! 265: <not-an-opcode> ! 266: <not-an-opcode> ! 267: <not-an-opcode> ! 268: (varset . -1) ! 269: <not-an-opcode> ! 270: <not-an-opcode> ! 271: <not-an-opcode> ! 272: <not-an-opcode> ! 273: <not-an-opcode> ! 274: <not-an-opcode> ! 275: <not-an-opcode> ! 276: (varbind . 0);Pops a value, "pushes" a binding ! 277: <not-an-opcode> ! 278: <not-an-opcode> ! 279: <not-an-opcode> ! 280: <not-an-opcode> ! 281: <not-an-opcode> ! 282: <not-an-opcode> ! 283: <not-an-opcode> ! 284: (call . -); #'-, not -1! ! 285: <not-an-opcode> ! 286: <not-an-opcode> ! 287: <not-an-opcode> ! 288: <not-an-opcode> ! 289: <not-an-opcode> ! 290: <not-an-opcode> ! 291: <not-an-opcode> ! 292: (unbind . -);"pops" bindings ! 293: <not-an-opcode> ! 294: <not-an-opcode> ! 295: <not-an-opcode> ! 296: <not-an-opcode> ! 297: <not-an-opcode> ! 298: <not-an-opcode> ! 299: <not-an-opcode> ! 300: <not-an-opcode> ! 301: <not-an-opcode> ! 302: <not-an-opcode> ! 303: <not-an-opcode> ! 304: <not-an-opcode> ! 305: <not-an-opcode> ! 306: <not-an-opcode> ! 307: <not-an-opcode> ! 308: (nth . -1) ! 309: symbolp ! 310: consp ! 311: stringp ! 312: listp ! 313: (eq . -1) ! 314: (memq . -1) ! 315: not ! 316: car ! 317: cdr ! 318: (cons . -1) ! 319: list1 ! 320: (list2 . -1) ! 321: (list3 . -2) ! 322: (list4 . -3) ! 323: length ! 324: (aref . -1) ! 325: (aset . -2) ! 326: symbol-value ! 327: symbol-function ! 328: (set . -1) ! 329: (fset . -1) ! 330: (get . -1) ! 331: (substring . -2) ! 332: (concat2 . -1) ! 333: (concat3 . -2) ! 334: (concat4 . -3) ! 335: sub1 ! 336: add1 ! 337: (eqlsign . -1) ;= ! 338: (gtr . -1) ;> ! 339: (lss . -1) ;< ! 340: (leq . -1) ;<= ! 341: (geq . -1) ;>= ! 342: (diff . -1) ;- ! 343: negate ;unary - ! 344: (plus . -1) ;+ ! 345: (max . -1) ! 346: (min . -1) ! 347: <not-an-opcode> ! 348: (point . 1) ! 349: (mark\(obsolete\) . 1) ! 350: goto-char ! 351: insert ! 352: (point-max . 1) ! 353: (point-min . 1) ! 354: char-after ! 355: (following-char . 1) ! 356: (preceding-char . 1) ! 357: (current-column . 1) ! 358: (indent-to . 1) ! 359: (scan-buffer\(obsolete\) . -2) ! 360: (eolp . 1) ! 361: (eobp . 1) ! 362: (bolp . 1) ! 363: (bobp . 1) ! 364: (current-buffer . 1) ! 365: set-buffer ! 366: (read-char . 1) ! 367: set-mark\(obsolete\) ! 368: interactive-p ! 369: <not-an-opcode> ! 370: <not-an-opcode> ! 371: <not-an-opcode> ! 372: <not-an-opcode> ! 373: <not-an-opcode> ! 374: <not-an-opcode> ! 375: <not-an-opcode> ! 376: <not-an-opcode> ! 377: <not-an-opcode> ! 378: <not-an-opcode> ! 379: <not-an-opcode> ! 380: <not-an-opcode> ! 381: (constant2 . 1) ! 382: goto;>>> ! 383: goto-if-nil;>> ! 384: goto-if-not-nil;>> ! 385: (goto-if-nil-else-pop . -1) ! 386: (goto-if-not-nil-else-pop . -1) ! 387: return ! 388: (discard . -1) ! 389: (dup . 1) ! 390: (save-excursion . 1);Pushes a binding ! 391: (save-window-excursion . 1);Pushes a binding ! 392: (save-restriction . 1);Pushes a binding ! 393: (catch . -1);Takes one argument, returns a value ! 394: (unwind-protect . 1);Takes one argument, pushes a binding, returns a value ! 395: (condition-case . -2);Takes three arguments, returns a value ! 396: (temp-output-buffer-setup . -1) ! 397: temp-output-buffer-show ! 398: <not-an-opcode> ! 399: <not-an-opcode> ! 400: <not-an-opcode> ! 401: <not-an-opcode> ! 402: <not-an-opcode> ! 403: <not-an-opcode> ! 404: <not-an-opcode> ! 405: <not-an-opcode> ! 406: <not-an-opcode> ! 407: <not-an-opcode> ! 408: <not-an-opcode> ! 409: <not-an-opcode> ! 410: <not-an-opcode> ! 411: <not-an-opcode> ! 412: <not-an-opcode> ! 413: <not-an-opcode> ! 414: <not-an-opcode> ! 415: <not-an-opcode> ! 416: <not-an-opcode> ! 417: <not-an-opcode> ! 418: <not-an-opcode> ! 419: <not-an-opcode> ! 420: <not-an-opcode> ! 421: <not-an-opcode> ! 422: <not-an-opcode> ! 423: <not-an-opcode> ! 424: <not-an-opcode> ! 425: <not-an-opcode> ! 426: <not-an-opcode> ! 427: <not-an-opcode> ! 428: <not-an-opcode> ! 429: <not-an-opcode> ! 430: <not-an-opcode> ! 431: <not-an-opcode> ! 432: <not-an-opcode> ! 433: <not-an-opcode> ! 434: <not-an-opcode> ! 435: <not-an-opcode> ! 436: <not-an-opcode> ! 437: <not-an-opcode> ! 438: <not-an-opcode> ! 439: <not-an-opcode> ! 440: <not-an-opcode> ! 441: <not-an-opcode> ! 442: <not-an-opcode> ! 443: <not-an-opcode> ! 444: (constant . 1) ! 445: ]) ! 446:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.