1*a9fa9459Szrj;;; dwarf-mode.el --- Browser for DWARF information. 2*a9fa9459Szrj 3*a9fa9459Szrj;; Version: 1.2 4*a9fa9459Szrj 5*a9fa9459Szrj;; Copyright (C) 2012-2016 Free Software Foundation, Inc. 6*a9fa9459Szrj 7*a9fa9459Szrj;; This file is not part of GNU Emacs, but is distributed under the 8*a9fa9459Szrj;; same terms: 9*a9fa9459Szrj 10*a9fa9459Szrj;; GNU Emacs is free software: you can redistribute it and/or modify 11*a9fa9459Szrj;; it under the terms of the GNU General Public License as published by 12*a9fa9459Szrj;; the Free Software Foundation, either version 3 of the License, or 13*a9fa9459Szrj;; (at your option) any later version. 14*a9fa9459Szrj 15*a9fa9459Szrj;; GNU Emacs is distributed in the hope that it will be useful, 16*a9fa9459Szrj;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17*a9fa9459Szrj;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*a9fa9459Szrj;; GNU General Public License for more details. 19*a9fa9459Szrj 20*a9fa9459Szrj;; You should have received a copy of the GNU General Public License 21*a9fa9459Szrj;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. 22*a9fa9459Szrj 23*a9fa9459Szrj;;; Code: 24*a9fa9459Szrj 25*a9fa9459Szrj(defvar dwarf-objdump-program "objdump") 26*a9fa9459Szrj 27*a9fa9459Szrj(defconst dwarf-font-lock-keywords 28*a9fa9459Szrj '( 29*a9fa9459Szrj ;; Name and linkage name. 30*a9fa9459Szrj ("DW_AT_[a-z_]*name\\s *: .*:\\(.*\\)\\s *$" 31*a9fa9459Szrj (1 font-lock-function-name-face)) 32*a9fa9459Szrj 33*a9fa9459Szrj ("Compilation Unit @ offset 0x[0-9a-f]+" 34*a9fa9459Szrj (0 font-lock-string-face)) 35*a9fa9459Szrj )) 36*a9fa9459Szrj 37*a9fa9459Szrj(defvar dwarf-file nil 38*a9fa9459Szrj "Buffer-local variable holding the file name passed to objdump.") 39*a9fa9459Szrj 40*a9fa9459Szrj;; Expand a "..." to show all the child DIES. NEW-DEPTH controls how 41*a9fa9459Szrj;; deep to display the new dies; `nil' means display all of them. 42*a9fa9459Szrj(defun dwarf-do-insert-substructure (new-depth die) 43*a9fa9459Szrj (let ((inhibit-read-only t)) 44*a9fa9459Szrj (beginning-of-line) 45*a9fa9459Szrj (delete-region (point) (progn 46*a9fa9459Szrj (end-of-line) 47*a9fa9459Szrj (forward-char) 48*a9fa9459Szrj (point))) 49*a9fa9459Szrj (save-excursion 50*a9fa9459Szrj (apply #'call-process dwarf-objdump-program nil (current-buffer) nil 51*a9fa9459Szrj "-Wi" (concat "--dwarf-start=0x" die) 52*a9fa9459Szrj (expand-file-name dwarf-file) 53*a9fa9459Szrj (if new-depth (list (concat "--dwarf-depth=" 54*a9fa9459Szrj (int-to-string new-depth)))))) 55*a9fa9459Szrj (set-buffer-modified-p nil))) 56*a9fa9459Szrj 57*a9fa9459Szrj(defun dwarf-insert-substructure-button (die) 58*a9fa9459Szrj (beginning-of-line) 59*a9fa9459Szrj (unless (looking-at "^ <\\([0-9]+\\)>") 60*a9fa9459Szrj (error "Unrecognized line.")) 61*a9fa9459Szrj (let ((new-depth (1+ (string-to-number (match-string 1))))) 62*a9fa9459Szrj (dwarf-do-insert-substructure new-depth die))) 63*a9fa9459Szrj 64*a9fa9459Szrj(defun dwarf-insert-substructure (arg) 65*a9fa9459Szrj "Expand a `...' to show children of the current DIE. 66*a9fa9459SzrjBy default, expands just one level of children. 67*a9fa9459SzrjA prefix argument means expand all children." 68*a9fa9459Szrj (interactive "P") 69*a9fa9459Szrj (beginning-of-line) 70*a9fa9459Szrj (unless (looking-at "^ <\\([0-9]+\\)><\\([0-9a-f]+\\)>") 71*a9fa9459Szrj (error "Unrecognized line.")) 72*a9fa9459Szrj (let ((die (match-string 2))) 73*a9fa9459Szrj (if arg 74*a9fa9459Szrj (dwarf-do-insert-substructure nil die) 75*a9fa9459Szrj (dwarf-insert-substructure-button die)))) 76*a9fa9459Szrj 77*a9fa9459Szrj;; Called when a button is pressed. 78*a9fa9459Szrj;; Either follows a DIE reference, or expands a "...". 79*a9fa9459Szrj(defun dwarf-die-button-action (button) 80*a9fa9459Szrj (let* ((die (button-get button 'die)) 81*a9fa9459Szrj ;; Note that the first number can only be decimal. 82*a9fa9459Szrj (die-rx (concat "^\\s *\\(<[0-9]+>\\)?<" 83*a9fa9459Szrj die ">[^<]")) 84*a9fa9459Szrj (old (point)) 85*a9fa9459Szrj (is-ref (button-get button 'die-ref))) 86*a9fa9459Szrj (if is-ref 87*a9fa9459Szrj (progn 88*a9fa9459Szrj (goto-char (point-min)) 89*a9fa9459Szrj (if (re-search-forward die-rx nil 'move) 90*a9fa9459Szrj (push-mark old) 91*a9fa9459Szrj (goto-char old) 92*a9fa9459Szrj (error "Could not find DIE <0x%s>" die))) 93*a9fa9459Szrj (dwarf-insert-substructure-button die)))) 94*a9fa9459Szrj 95*a9fa9459Szrj;; Button definition. 96*a9fa9459Szrj(define-button-type 'dwarf-die-button 97*a9fa9459Szrj 'follow-link t 98*a9fa9459Szrj 'action #'dwarf-die-button-action) 99*a9fa9459Szrj 100*a9fa9459Szrj;; Helper regexp to match a DIE reference. 101*a9fa9459Szrj(defconst dwarf-die-reference "\\(<0x\\([0-9a-f]+\\)>\\)") 102*a9fa9459Szrj 103*a9fa9459Szrj;; Helper regexp to match a `...' indicating that there are hidden 104*a9fa9459Szrj;; children. 105*a9fa9459Szrj(defconst dwarf-die-more "^ <[0-9]+><\\([0-9a-z]+\\)>: \\([.][.][.]\\)") 106*a9fa9459Szrj 107*a9fa9459Szrj;; jit-lock callback function to fontify a region. This applies the 108*a9fa9459Szrj;; buttons, since AFAICT there is no good way to apply buttons via 109*a9fa9459Szrj;; font-lock. 110*a9fa9459Szrj(defun dwarf-fontify-region (start end) 111*a9fa9459Szrj (save-excursion 112*a9fa9459Szrj (let ((beg-line (progn (goto-char start) (line-beginning-position))) 113*a9fa9459Szrj (end-line (progn (goto-char end) (line-end-position)))) 114*a9fa9459Szrj (goto-char beg-line) 115*a9fa9459Szrj (while (re-search-forward dwarf-die-reference end-line 'move) 116*a9fa9459Szrj (let ((b-start (match-beginning 1)) 117*a9fa9459Szrj (b-end (match-end 1)) 118*a9fa9459Szrj (hex (match-string-no-properties 2))) 119*a9fa9459Szrj (make-text-button b-start b-end :type 'dwarf-die-button 120*a9fa9459Szrj 'die hex 'die-ref t))) 121*a9fa9459Szrj ;; This is a bogus approach. Why can't we make buttons from the 122*a9fa9459Szrj ;; font-lock defaults? 123*a9fa9459Szrj (goto-char beg-line) 124*a9fa9459Szrj (while (re-search-forward dwarf-die-more end-line 'move) 125*a9fa9459Szrj (let ((hex (match-string-no-properties 1)) 126*a9fa9459Szrj (b-start (match-beginning 2)) 127*a9fa9459Szrj (b-end (match-end 2))) 128*a9fa9459Szrj (make-text-button b-start b-end :type 'dwarf-die-button 129*a9fa9459Szrj 'die hex 'die-ref nil)))))) 130*a9fa9459Szrj 131*a9fa9459Szrj;; Run objdump and insert the contents into the buffer. The arguments 132*a9fa9459Szrj;; are the way they are because this is also called as a 133*a9fa9459Szrj;; revert-buffer-function. 134*a9fa9459Szrj(defun dwarf-do-refresh (&rest ignore) 135*a9fa9459Szrj (let ((inhibit-read-only t)) 136*a9fa9459Szrj (erase-buffer) 137*a9fa9459Szrj (save-excursion 138*a9fa9459Szrj (call-process dwarf-objdump-program 139*a9fa9459Szrj nil (current-buffer) nil 140*a9fa9459Szrj "-Wi" "--dwarf-depth=1" 141*a9fa9459Szrj (expand-file-name dwarf-file))) 142*a9fa9459Szrj (set-buffer-modified-p nil))) 143*a9fa9459Szrj 144*a9fa9459Szrj(define-derived-mode dwarf-mode special-mode "DWARF" 145*a9fa9459Szrj "Major mode for browsing DWARF output. 146*a9fa9459Szrj 147*a9fa9459Szrj\\{dwarf-mode-map}" 148*a9fa9459Szrj 149*a9fa9459Szrj (set (make-local-variable 'font-lock-defaults) '(dwarf-font-lock-keywords)) 150*a9fa9459Szrj ;; FIXME: we could be smarter and check the file time. 151*a9fa9459Szrj (set (make-local-variable 'revert-buffer-function) #'dwarf-do-refresh) 152*a9fa9459Szrj (jit-lock-register #'dwarf-fontify-region)) 153*a9fa9459Szrj 154*a9fa9459Szrj(define-key dwarf-mode-map [(control ?m)] #'dwarf-insert-substructure) 155*a9fa9459Szrj 156*a9fa9459Szrj;;;###autoload 157*a9fa9459Szrj(defun dwarf-browse (file) 158*a9fa9459Szrj "Invoke `objdump' and put output into a `dwarf-mode' buffer. 159*a9fa9459SzrjThis is the main interface to `dwarf-mode'." 160*a9fa9459Szrj (interactive "fFile name: ") 161*a9fa9459Szrj (let* ((base-name (file-name-nondirectory file)) 162*a9fa9459Szrj (buffer (generate-new-buffer (concat "*DWARF for " base-name "*")))) 163*a9fa9459Szrj (pop-to-buffer buffer) 164*a9fa9459Szrj (dwarf-mode) 165*a9fa9459Szrj (set (make-local-variable 'dwarf-file) file) 166*a9fa9459Szrj (dwarf-do-refresh))) 167*a9fa9459Szrj 168*a9fa9459Szrj(provide 'dwarf-mode) 169*a9fa9459Szrj 170*a9fa9459Szrj;;; dwarf-mode.el ends here 171