-;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, dbx, or xdb
-;;; under Emacs
+;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, dbx, or xdb under Emacs
;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
;; Maintainer: FSF
;; 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.
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; added support for xdb (HPUX debugger). Rick Sladkey <jrs@world.std.com>
;; wrote the GDB command completion code. Dave Love <d.love@dl.ac.uk>
;; added the IRIX kluge, re-implemented the Mips-ish variant and added
-;; a menu.
+;; a menu. Brian D. Carlstrom <bdc@ai.mit.edu> combined the IRIX kluge with
+;; the gud-xdb-directories hack producing gud-dbx-directories.
;;; Code:
;; before use.)
(defvar gud-menu-map (make-sparse-keymap "Gud") nil)
(define-key gud-menu-map [refresh] '("Refresh" . gud-refresh))
-(define-key gud-menu-map [remove] '("Remove breakpoint" . gud-remove))
+(define-key gud-menu-map [remove] '("Remove Breakpoint" . gud-remove))
(define-key gud-menu-map [tbreak] nil) ; gdb, sdb and xdb
-(define-key gud-menu-map [break] '("Set breakpoint" . gud-break))
+(define-key gud-menu-map [break] '("Set Breakpoint" . gud-break))
(define-key gud-menu-map [up] nil) ; gdb, dbx, and xdb
(define-key gud-menu-map [down] nil) ; gdb, dbx, and xdb
-(define-key gud-menu-map [print] '("Print expression" . gud-print))
+(define-key gud-menu-map [print] '("Print Expression" . gud-print))
(define-key gud-menu-map [finish] nil) ; gdb or xdb
-(define-key gud-menu-map [stepi] '("Step instruction" . gud-stepi))
-(define-key gud-menu-map [step] '("Step line" . gud-step))
-(define-key gud-menu-map [next] '("Next line" . gud-next))
+(define-key gud-menu-map [stepi] '("Step Instruction" . gud-stepi))
+(define-key gud-menu-map [step] '("Step Line" . gud-step))
+(define-key gud-menu-map [next] '("Next Line" . gud-next))
(define-key gud-menu-map [cont] '("Continue" . gud-cont))
\f
;; ======================================================================
"Make sure the current local map has a [menu-bar debug] submap.
If it doesn't, replace it with a new map that inherits it,
and create such a submap in that new map."
- (if (lookup-key (current-local-map) [menu-bar debug])
+ (if (and (current-local-map)
+ (lookup-key (current-local-map) [menu-bar debug]))
nil
(use-local-map (gud-new-keymap (current-local-map)))
(define-key (current-local-map) [menu-bar debug]
(set-buffer buf)
(gud-make-debug-menu)
(local-set-key [menu-bar debug tbreak]
- '("Temporary breakpoint" . gud-tbreak))
- (local-set-key [menu-bar debug finish] '("Finish function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
+ '("Temporary Breakpoint" . gud-tbreak))
+ (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
buf)))
(defvar gdb-minibuffer-local-map nil
(gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.")
(local-set-key "\C-i" 'gud-gdb-complete-command)
- (local-set-key [menu-bar debug tbreak] '("Temporary breakpoint" . gud-tbreak))
- (local-set-key [menu-bar debug finish] '("Finish function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
+ (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
+ (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
(setq comint-prompt-regexp "^(.*gdb[+]?) *")
(setq paragraph-start comint-prompt-regexp)
(run-hooks 'gdb-mode-hook)
(while
(cond
;; System V Release 3.2 uses this format
- ((string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n"
+ ((string-match "\\(^\\|\n\\)\\*?\\(0x\\w* in \\)?\\([^:\n]*\\):\\([0-9]*\\):.*\n"
gud-marker-acc start)
(setq gud-last-frame
(cons
- (substring gud-marker-acc (match-beginning 2) (match-end 2))
+ (substring gud-marker-acc (match-beginning 3) (match-end 3))
(string-to-int
- (substring gud-marker-acc (match-beginning 3) (match-end 3))))))
+ (substring gud-marker-acc (match-beginning 4) (match-end 4))))))
;; System V Release 4.0 quite often clumps two lines together
((string-match "^\\(BREAKPOINT\\|STEPPED\\) process [0-9]+ function [^ ]+ in \\(.+\\)\n\\([0-9]+\\):"
gud-marker-acc start)
(setq start (match-end 0)))
;; If we have an incomplete line, store it in gud-marker-acc.
- ;; Otherwise clear gud-marker-acc. to avoid an
- ;; unnecessary concat when this function runs next.
- (setq gud-marker-acc
- (if (= start (length gud-marker-acc))
- (substring gud-marker-acc start)
- nil)))
+ (setq gud-marker-acc (substring gud-marker-acc (or start 0))))
string)
(defun gud-sdb-find-file (f)
(find-file-noselect f))))
(set-buffer buf)
(gud-make-debug-menu)
- (local-set-key [menu-bar debug tbreak] '("Temporary breakpoint" . gud-tbreak))
+ (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
buf)))
;;;###autoload
(setq comint-prompt-regexp "\\(^\\|\n\\)\\*")
(setq paragraph-start comint-prompt-regexp)
(local-set-key [menu-bar debug tbreak]
- '("Temporary breakpoint" . gud-tbreak))
+ '("Temporary Breakpoint" . gud-tbreak))
(run-hooks 'sdb-mode-hook)
)
\f
;;; History of argument lists passed to dbx.
(defvar gud-dbx-history nil)
-(defun gud-dbx-massage-args (file args) args)
+(defvar gud-dbx-directories nil
+ "*A list of directories that dbx should search for source code.
+If nil, only source files in the program directory
+will be known to dbx.
+
+The file names should be absolute, or relative to the directory
+containing the executable being debugged.")
+
+(defun gud-dbx-massage-args (file args)
+ (nconc (let ((directories gud-dbx-directories)
+ (result nil))
+ (while directories
+ (setq result (cons (car directories) (cons "-I" result)))
+ (setq directories (cdr directories)))
+ (nreverse result))
+ args))
+
+(defun gud-dbx-file-name (f)
+ "Transform a relative file name to an absolute file name, for dbx."
+ (let ((result nil))
+ (if (file-exists-p f)
+ (setq result (expand-file-name f))
+ (let ((directories gud-dbx-directories))
+ (while directories
+ (let ((path (concat (car directories) "/" f)))
+ (if (file-exists-p path)
+ (setq result (expand-file-name path)
+ directories nil)))
+ (setq directories (cdr directories)))))
+ result))
(defun gud-dbx-marker-filter (string)
(setq gud-marker-acc (if gud-marker-acc (concat gud-marker-acc string) string))
result)
((string-match ; kluged-up marker as above
"\032\032\\([0-9]*\\):\\(.*\\)\n" result)
- (let ((file (substring result (match-beginning 2) (match-end 2))))
- (if (file-exists-p file)
+ (let ((file (gud-dbx-file-name
+ (substring result (match-beginning 2) (match-end 2)))))
+ (if (and file (file-exists-p file))
(setq gud-last-frame
(cons
file
(defun gud-dbx-find-file (f)
(save-excursion
- (let ((buf (find-file-noselect f)))
- (set-buffer buf)
- (gud-make-debug-menu)
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
- buf)))
+ (let ((realf (gud-dbx-file-name f)))
+ (if realf
+ (let ((buf (find-file-noselect realf)))
+ (set-buffer buf)
+ (gud-make-debug-menu)
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
+ buf)
+ nil))))
;;;###autoload
(defun dbx (command-line)
(setq comint-prompt-regexp "^[^)\n]*dbx) *")
(setq paragraph-start comint-prompt-regexp)
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
(run-hooks 'dbx-mode-hook)
)
\f
gud-marker-acc "")
(setq gud-marker-acc (concat gud-marker-acc string)))
(if result
- (if (or (string-match "\\([^\n \t:]+\\): [^:]+: \\([0-9]+\\):" result)
+ (if (or (string-match "\\([^\n \t:]+\\): [^:]+: \\([0-9]+\\)[: ]"
+ result)
(string-match "[^: \t]+:[ \t]+\\([^:]+\\): [^:]+: \\([0-9]+\\):"
result))
- (let ((line (string-to-int
+ (let ((line (string-to-int
(substring result (match-beginning 2) (match-end 2))))
(file (gud-xdb-file-name
(substring result (match-beginning 1) (match-end 1)))))
(set-buffer buf)
(gud-make-debug-menu)
(local-set-key [menu-bar debug tbreak]
- '("Temporary breakpoint" . gud-tbreak))
+ '("Temporary Breakpoint" . gud-tbreak))
(local-set-key [menu-bar debug finish]
- '("Finish function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
+ '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
buf)
nil))))
(setq comint-prompt-regexp "^>")
(setq paragraph-start comint-prompt-regexp)
- (local-set-key [menu-bar debug tbreak] '("Temporary breakpoint" . gud-tbreak))
- (local-set-key [menu-bar debug finish] '("Finish function" . gud-finish))
- (local-set-key [menu-bar debug up] '("Up stack" . gud-up))
- (local-set-key [menu-bar debug down] '("Down stack" . gud-down))
+ (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
+ (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
(run-hooks 'xdb-mode-hook))
\f
;; ======================================================================
(save-excursion
(let ((buf (find-file-noselect f)))
(set-buffer buf)
- (define-key (current-local-map) [menu-bar debug] (cons "Gud" (copy-keymap gud-menu-map)))
+ (gud-make-debug-menu)
buf)))
;;;###autoload
"Major mode for interacting with an inferior debugger process.
You start it up with one of the commands M-x gdb, M-x sdb, M-x dbx,
-or M-x xdb. Each entry point finishes by executing a hook; `gdb-mode-hook',
-`sdb-mode-hook', `dbx-mode-hook' or `xdb-mode-hook' respectively.
+M-x perldb, or M-x xdb. Each entry point finishes by executing a
+hook; `gdb-mode-hook', `sdb-mode-hook', `dbx-mode-hook',
+`perldb-mode-hook', or `xdb-mode-hook' respectively.
After startup, the following commands are available in both the GUD
interaction buffer and any source buffer GUD visits due to a breakpoint stop
(if w
(setcar w file)))
(apply 'make-comint (concat "gud" filepart) program nil
- (if file-word (funcall massage-args file args) args)))
+ (funcall massage-args file args)))
;; Since comint clobbered the mode, we don't set it until now.
(gud-mode)
(make-local-variable 'gud-marker-filter)
(cond ((eq major-mode 'gud-mode)
(setq gud-comint-buffer (current-buffer)))))
+(defvar gud-filter-defer-flag nil
+ "Non-nil means don't process anything from the debugger right now.
+It is saved for when this flag is not set.")
+
+(defvar gud-filter-pending-text nil
+ "Non-nil means this is text that has been saved for later in `gud-filter'.")
+
;; These functions are responsible for inserting output from your debugger
;; into the buffer. The hard work is done by the method that is
;; the value of gud-marker-filter.
(defun gud-filter (proc string)
;; Here's where the actual buffer insertion is done
- (let (output)
+ (let (output process-window)
(if (buffer-name (process-buffer proc))
- (save-excursion
- (set-buffer (process-buffer proc))
- ;; If we have been so requested, delete the debugger prompt.
- (if (marker-buffer gud-delete-prompt-marker)
- (progn
- (delete-region (process-mark proc) gud-delete-prompt-marker)
- (set-marker gud-delete-prompt-marker nil)))
- ;; Save the process output, checking for source file markers.
- (setq output (gud-marker-filter string))
- ;; Check for a filename-and-line number.
- ;; Don't display the specified file
- ;; unless (1) point is at or after the position where output appears
- ;; and (2) this buffer is on the screen.
- (if (and gud-last-frame
- (>= (point) (process-mark proc))
- (get-buffer-window (current-buffer)))
- (gud-display-frame))
- ;; Let the comint filter do the actual insertion.
- ;; That lets us inherit various comint features.
- (comint-output-filter proc output)))))
+ (if gud-filter-defer-flag
+ ;; If we can't process any text now,
+ ;; save it for later.
+ (setq gud-filter-pending-text
+ (concat (or gud-filter-pending-text "") string))
+
+ ;; If we have to ask a question during the processing,
+ ;; defer any additional text that comes from the debugger
+ ;; during that time.
+ (let ((gud-filter-defer-flag t))
+ ;; Process now any text we previously saved up.
+ (if gud-filter-pending-text
+ (setq string (concat gud-filter-pending-text string)
+ gud-filter-pending-text nil))
+ (save-excursion
+ (set-buffer (process-buffer proc))
+ ;; If we have been so requested, delete the debugger prompt.
+ (if (marker-buffer gud-delete-prompt-marker)
+ (progn
+ (delete-region (process-mark proc) gud-delete-prompt-marker)
+ (set-marker gud-delete-prompt-marker nil)))
+ ;; Save the process output, checking for source file markers.
+ (setq output (gud-marker-filter string))
+ ;; Check for a filename-and-line number.
+ ;; Don't display the specified file
+ ;; unless (1) point is at or after the position where output appears
+ ;; and (2) this buffer is on the screen.
+ (setq process-window
+ (and gud-last-frame
+ (>= (point) (process-mark proc))
+ (get-buffer-window (current-buffer))))
+
+ ;; Let the comint filter do the actual insertion.
+ ;; That lets us inherit various comint features.
+ (comint-output-filter proc output)))
+
+ ;; Put the arrow on the source line.
+ ;; This must be outside of the save-excursion
+ ;; in case the source file is our current buffer.
+ (if process-window
+ (save-selected-window
+ (select-window process-window)
+ (gud-display-frame))
+ ;; We have to be in the proper buffer, (process-buffer proc),
+ ;; but not in a save-excursion, because that would restore point.
+ (let ((old-buf (current-buffer)))
+ (set-buffer (process-buffer proc))
+ (unwind-protect
+ (gud-display-frame)
+ (set-buffer old-buf))))
+
+ ;; If we deferred text that arrived during this processing,
+ ;; handle it now.
+ (if gud-filter-pending-text
+ (gud-filter proc ""))))))
(defun gud-sentinel (proc msg)
(cond ((null (buffer-name (process-buffer proc)))
(defun gud-display-line (true-file line)
(let* ((last-nonmenu-event t) ; Prevent use of dialog box for questions.
- (buffer (gud-find-file true-file))
+ (buffer
+ (save-excursion
+ (or (eq (current-buffer) gud-comint-buffer)
+ (set-buffer gud-comint-buffer))
+ (gud-find-file true-file)))
(window (display-buffer buffer))
(pos))
-;;; (if (equal buffer (current-buffer))
-;;; nil
-;;; (setq buffer-read-only nil))
(save-excursion
-;;; (setq buffer-read-only t)
(set-buffer buffer)
(save-restriction
(widen)