-;;; 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:
"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]
(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)
;;; 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)
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)))))
"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
(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))
+ (save-excursion
+ ;; 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))
+ (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)))))
+ (if process-window
+ (save-selected-window
+ (select-window process-window)
+ (gud-display-frame)))
+
+ ;; Let the comint filter do the actual insertion.
+ ;; That lets us inherit various comint features.
+ (comint-output-filter proc output)
+
+ ;; 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))