home *** CD-ROM | disk | FTP | other *** search
- ;;;; gdb.jl -- run gdb in a buffer
- ;;; Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
-
- ;;; This file is part of Jade.
-
- ;;; Jade 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 2, or (at your option)
- ;;; any later version.
-
- ;;; Jade 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 Jade; see the file COPYING. If not, write to
- ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- (require 'shell)
- (provide 'gdb)
-
- (defvar gdb-file-name "gdb"
- "The file name of the gdb program to run.")
-
- (defvar gdb-auto-centre nil
- "When non-nil the current line in the source window is automatically
- centred each time it changes.")
-
- (defvar gdb-last-frame nil
- "(FILE . LINE-NUMBER) representing the last frame we displayed.")
- (make-variable-buffer-local 'gdb-last-frame)
-
- (defvar gdb-last-buffer nil
- "This is the last *gdb* buffer which was used.")
-
- (defvar gdb-buffer-p nil
- "Flag that says this buffer is for running a gdb process.")
- (make-variable-buffer-local 'gdb-buffer-p)
-
- (defvar gdb-spare-output nil)
- (make-variable-buffer-local 'gdb-spare-output)
-
- (defvar gdb-delete-prompt nil)
- (make-variable-buffer-local 'gdb-delete-prompt)
-
- (defvar gdb-ctrl-c-keymap (copy-sequence shell-ctrl-c-keymap))
- (bind-keys gdb-ctrl-c-keymap
- "Ctrl-n" '(gdb-command "next %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl-s" '(gdb-command "step %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl-i" '(gdb-command "stepi %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl-I" '(gdb-command "nexti %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl-f" '(gdb-command "finish\n")
- "Ctrl-r" '(gdb-command "cont\n")
- "Ctrl-<" '(gdb-command "up %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl->" '(gdb-command "down %d\n" (prefix-numeric-argument current-prefix-arg))
- "Ctrl-b" '(gdb-command "break %s:%d\n" (gdb-current-file) (gdb-current-line))
- "Ctrl-t" '(gdb-command "tbreak %s:%d\n" (gdb-current-file) (gdb-current-line))
- "Ctrl-d" '(gdb-command "clear %d\n" (gdb-current-line))
- "Ctrl-l" 'gdb-redisplay-frame)
-
- (bind-keys ctrl-x-keymap
- "Ctrl-a" '(setq next-keymap-path '(gdb-ctrl-c-keymap)))
-
- ;;;###autoload
- (defun gdb (prog)
- "Run the gdb debugger in an editor buffer (called `*gdb*'). PROG is the
- program which is to be debugged.
- See the `gdb-mode' documentation for details of the available commands.
- There is no limit to the number of gdb processes you may run at once."
- (interactive "fProgram to debug:")
- (let*
- ((buffer (get-buffer "*gdb*")))
- (if (or (not buffer) (with-buffer buffer shell-process))
- (progn
- (setq buffer (make-buffer "*gdb*"))
- (set-buffer-special buffer t))
- (clear-buffer buffer))
- (goto-buffer buffer)
- (kill-all-buffer-variables)
- (set-buffer-file-name buffer prog)
- (setq shell-program gdb-file-name
- shell-program-args (list "-fullname" (file-name-nondirectory prog))
- shell-prompt-regexp "^(.*\\(.+\\) *|.+---)"
- shell-output-stream (list 'lambda '(x)
- (list 'gdb-output-filter
- (current-buffer)
- 'x)))
- (shell-mode)
- (setq mode-name (concat "GDB:" (file-name-nondirectory prog))
- major-mode 'gdb-mode
- ctrl-c-keymap gdb-ctrl-c-keymap
- gdb-last-buffer buffer
- gdb-buffer-p t
- mildly-special-buffer t)
- (eval-hook 'gdb-hook)))
-
- (defun gdb-mode ()
- "Gdb Mode:\n
- This major-mode is used to run the GDB debugger in an editor buffer. To
- start a gdb subprocess use the `ESC x gdb' command.\n
- Each time the target process stops executing the source line of the
- current frame is highlighted in a separate window.\n
- The following commands are available in the `*gdb*' buffer,\n
- `Ctrl-c Ctrl-n' Next line
- `Ctrl-c Ctrl-s' Step
- `Ctrl-c Ctrl-i' Step the next instruction
- `Ctrl-c Ctrl-I' Next instruction
- `Ctrl-c Ctrl-f' Finish this frame
- `Ctrl-c Ctrl-r' Continue execution
- `Ctrl-c Ctrl-<' Move up one frame
- `Ctrl-c Ctrl->' Move down one frame
- `Ctrl-c Ctrl-b' Set a breakpoint at the current line
- `Ctrl-c Ctrl-t' Set a temporary breakpoint
- `Ctrl-c Ctrl-d' Delete the breakpoint at the current line
- `Ctrl-c Ctrl-l' Redisplay the current frame\n
- They are also accessible in any buffer by replacing the `Ctrl-c' prefix
- with `Ctrl-x Ctrl-a'.\n
- Since this command is built on top of the shell-mode all commands from
- that mode are available as well.")
-
-
- ;; Digs the variable VAR out of the gdb-last-buffer
- (defmacro gdb-get-buffer-var (var)
- (list 'with-buffer 'gdb-last-buffer var))
-
- ;; Gets the name of the current file
- (defun gdb-current-file ()
- (file-name-nondirectory (if gdb-buffer-p
- (car gdb-last-frame)
- (buffer-file-name))))
-
- ;; Gets the current line number, it increments it as well
- (defun gdb-current-line ()
- (1+ (if gdb-buffer-p
- (cdr gdb-last-frame)
- (pos-line (cursor-pos)))))
-
- ;; Send a command to the correct gdb process
- (defun gdb-command (format-spec &rest format-args)
- (when gdb-buffer-p
- (setq gdb-last-buffer (current-buffer)))
- (apply 'format
- (gdb-get-buffer-var shell-process)
- format-spec format-args)
- (with-buffer gdb-last-buffer
- (when (regexp-match-line "^\\(.*gdb.*\\) *" (buffer-end))
- (setq gdb-delete-prompt t))))
-
- ;; Receives all output from the gdb subprocess, it acts upon and removes
- ;; any frame markers
- (defun gdb-output-filter (buffer data)
- (let
- (new-frame)
- (with-buffer buffer
- (when gdb-spare-output
- (setq data (concat gdb-spare-output data)))
- (goto-buffer-end)
- (when (and gdb-delete-prompt
- (regexp-match-line shell-prompt-regexp))
- (delete-area (match-start) (match-end))
- (setq gdb-delete-prompt nil))
- (while (regexp-match "\032\032([^:\n]+):([0-9]+):([0-9]+):.*\n" data)
- ;; A whole marker to process
- (insert (substring data 0 (match-start 0)))
- (setq
- gdb-last-frame (cons (substring data (match-start 1) (match-end 1))
- (1- (read (cons 0 (substring data
- (match-start 2)
- (match-end 2))))))
- new-frame t
- data (substring data (match-end 0))))
- (if (regexp-match "\032" data)
- ;; Start of an incomplete marker; save it for later
- (progn
- (insert (substring data 0 (match-start 0)))
- (setq gdb-spare-output (substring data (match-start 0))))
- (insert data)
- (setq gdb-spare-output nil)))
- (when new-frame
- (setq gdb-last-buffer buffer)
- ;; Now redisplay the frame and its highlight
- (let*
- ((frame (with-buffer buffer gdb-last-frame))
- (window (if gdb-buffer-p (other-window) (current-window)))
- (line-pos (pos 0 (cdr frame)))
- old-buf)
- (with-window window
- (setq old-buf (current-buffer))
- (goto-buffer (open-file (car frame)))
- (mark-block line-pos (line-end line-pos))
- (goto-char (line-end line-pos))
- (when (or gdb-auto-centre (not (eq old-buf (current-buffer))))
- (centre-display)))))))
-
- (defun gdb-redisplay-frame ()
- (interactive)
- (when gdb-buffer-p
- (setq gdb-last-buffer (current-buffer)))
- (let*
- ((frame (gdb-get-buffer-var gdb-last-frame))
- (line-pos (pos 0 (cdr frame))))
- (goto-buffer (open-file (car frame)))
- (mark-block line-pos (line-end line-pos))
- (goto-char (line-end line-pos))
- (centre-display)))
-