diff options
| author | Eric S. Raymond | 1993-04-08 16:35:48 +0000 |
|---|---|---|
| committer | Eric S. Raymond | 1993-04-08 16:35:48 +0000 |
| commit | ee0155df12d8b26fcf8f690535b08386ec86e524 (patch) | |
| tree | d639a1ba22a69ee78c01c46566e4d321b263437b | |
| parent | 235aa29bda408d144ba409e572daa557dc9c6f57 (diff) | |
| download | emacs-ee0155df12d8b26fcf8f690535b08386ec86e524.tar.gz emacs-ee0155df12d8b26fcf8f690535b08386ec86e524.zip | |
Massive changes, amounting nearly to a rewrite. The new features
include auto-configuring support for SVr4, more commands, and a full minor-mode
implementation that binds all GUD commands not just in the GUD interaction
mode, but in C buffers visited by GUD. The common prefix of GUD commands is
now C-x X, like electric-debug mode.
| -rw-r--r-- | lisp/gud.el | 807 |
1 files changed, 513 insertions, 294 deletions
diff --git a/lisp/gud.el b/lisp/gud.el index 13e510d8d55..fc30025ff00 100644 --- a/lisp/gud.el +++ b/lisp/gud.el | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | ;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, or dbx under Emacs | 1 | ;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, or dbx under Emacs |
| 2 | 2 | ||
| 3 | ;; Author: Eric S. Raymond <eric@snark.thyrsus.com> | 3 | ;; Author: Eric S. Raymond <esr@snark.thyrsus.com> |
| 4 | ;; Version: 1.1 | ||
| 4 | ;; Keywords: unix, tools | 5 | ;; Keywords: unix, tools |
| 5 | 6 | ||
| 6 | ;; %W% | ||
| 7 | |||
| 8 | ;; Copyright (C) 1992 Free Software Foundation, Inc. | 7 | ;; Copyright (C) 1992 Free Software Foundation, Inc. |
| 9 | 8 | ||
| 10 | ;; This file is part of GNU Emacs. | 9 | ;; This file is part of GNU Emacs. |
| @@ -31,14 +30,25 @@ | |||
| 31 | ;; The overloading code was then rewritten by Barry Warsaw <bwarsaw@cen.com>, | 30 | ;; The overloading code was then rewritten by Barry Warsaw <bwarsaw@cen.com>, |
| 32 | ;; who also hacked the mode to use comint.el. | 31 | ;; who also hacked the mode to use comint.el. |
| 33 | 32 | ||
| 34 | ;; Note: use of this package with sdb requires that your tags.el support | 33 | ;; This code will not work under Emacs 18. It relies on Emacs 19's |
| 35 | ;; the find-tag-noselect entry point. Stock distributions up to 18.57 do | 34 | ;; minor-mode-keymap support and the find-tag-noselect entry point of etags. |
| 36 | ;; *not* include this feature; if it's not included with this file, email | 35 | |
| 37 | ;; esr@snark.thyrsus.com for it or get 18.58. | 36 | ;;; Change Log: |
| 38 | 37 | ||
| 39 | ;; Further note: due to lossage in the Emacs-18 byte compiler, compiled | 38 | ;; Version 1.1: ESR 6 Apr 1993 |
| 40 | ;; versions of this code will fail with a complaint about gud-step if | 39 | ;; * Facility to accept and parse command-line switches other than the |
| 41 | ;; you invoke the gdb or sdb initializers. This should be fixed in 19. | 40 | ;; filename added. |
| 41 | ;; * System V Release 4 support added. | ||
| 42 | ;; * Can now set temporary breakpoints in sdb. | ||
| 43 | ;; * A GUD minor mode using the 19 minor-mode-keymap facilities is now | ||
| 44 | ;; enabled in visited C buffers. | ||
| 45 | ;; * Command bindings are now automatically the same in gud-minor-mode | ||
| 46 | ;; as they are in the GUD buffer itself, and use ^XX as a common | ||
| 47 | ;; prefix (for compatibility with electric-debug). | ||
| 48 | ;; * There is a new command for printing the C expression around point. | ||
| 49 | |||
| 50 | ;; Version 1.0: ESR | ||
| 51 | ;; * Created. | ||
| 42 | 52 | ||
| 43 | ;;; Code: | 53 | ;;; Code: |
| 44 | 54 | ||
| @@ -46,6 +56,42 @@ | |||
| 46 | (require 'etags) | 56 | (require 'etags) |
| 47 | 57 | ||
| 48 | ;; ====================================================================== | 58 | ;; ====================================================================== |
| 59 | ;; minor-mode machinery for C buffers visited by GUD | ||
| 60 | |||
| 61 | (defvar gud-key-prefix "\C-xX" | ||
| 62 | "Prefix of all GUD minor-mode commands valid in C buffers.") | ||
| 63 | |||
| 64 | (defvar gud-minor-mode nil) | ||
| 65 | (or (assq 'gud-minor-mode minor-mode-alist) | ||
| 66 | (setq minor-mode-alist | ||
| 67 | (cons '(gud-minor-mode " GUD") minor-mode-alist))) | ||
| 68 | |||
| 69 | (defvar gud-mode-map nil) | ||
| 70 | (if gud-mode-map | ||
| 71 | nil | ||
| 72 | (setq gud-mode-map (make-sparse-keymap)) | ||
| 73 | (define-key gud-mode-map gud-key-prefix (make-sparse-keymap)) | ||
| 74 | (define-key gud-mode-map (concat gud-key-prefix "\C-l") 'gud-refresh) | ||
| 75 | ) | ||
| 76 | |||
| 77 | (or (assq 'gud-minor-mode minor-mode-map-alist) | ||
| 78 | (setq minor-mode-map-alist | ||
| 79 | (cons | ||
| 80 | (cons 'gud-minor-mode gud-mode-map) | ||
| 81 | minor-mode-map-alist))) | ||
| 82 | |||
| 83 | (defun gud-minor-mode (&optional enable) | ||
| 84 | "GUD minor mode is enabled in C buffers visited due to a GUD stop at | ||
| 85 | breakpoint. All GUD-specific commands defined in GUD major mode will work, | ||
| 86 | but they get their current file and current line number from the context of | ||
| 87 | this buffer." | ||
| 88 | (interactive "P") | ||
| 89 | (setq gud-minor-mode | ||
| 90 | (if (null enable) (not gud-minor-mode) | ||
| 91 | (> (prefix-numeric-value enable) 0))) | ||
| 92 | ) | ||
| 93 | |||
| 94 | ;; ====================================================================== | ||
| 49 | ;; the overloading mechanism | 95 | ;; the overloading mechanism |
| 50 | 96 | ||
| 51 | (defun gud-overload-functions (gud-overload-alist) | 97 | (defun gud-overload-functions (gud-overload-alist) |
| @@ -56,17 +102,17 @@ This association list has elements of the form | |||
| 56 | (function (lambda (p) (fset (car p) (symbol-function (cdr p))))) | 102 | (function (lambda (p) (fset (car p) (symbol-function (cdr p))))) |
| 57 | gud-overload-alist)) | 103 | gud-overload-alist)) |
| 58 | 104 | ||
| 59 | (defun gud-debugger-startup (f d) | 105 | (defun gud-debugger-startup (file args) |
| 60 | (error "GUD not properly entered.")) | 106 | (error "GUD not properly entered.")) |
| 61 | 107 | ||
| 62 | (defun gud-marker-filter (proc s) | 108 | (defun gud-marker-filter (str) |
| 63 | (error "GUD not properly entered.")) | 109 | (error "GUD not properly entered.")) |
| 64 | 110 | ||
| 65 | (defun gud-visit-file (f) | 111 | (defun gud-find-file (f) |
| 66 | (error "GUD not properly entered.")) | 112 | (error "GUD not properly entered.")) |
| 67 | 113 | ||
| 68 | (defun gud-set-break (proc f n rest) | 114 | ;; ====================================================================== |
| 69 | (error "GUD not properly entered.")) | 115 | ;; command definition |
| 70 | 116 | ||
| 71 | ;; This macro is used below to define some basic debugger interface commands. | 117 | ;; This macro is used below to define some basic debugger interface commands. |
| 72 | ;; Of course you may use `gud-def' with any other debugger command, including | 118 | ;; Of course you may use `gud-def' with any other debugger command, including |
| @@ -74,29 +120,46 @@ This association list has elements of the form | |||
| 74 | 120 | ||
| 75 | ;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form | 121 | ;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form |
| 76 | ;; which defines FUNC to send the command NAME to the debugger, gives | 122 | ;; which defines FUNC to send the command NAME to the debugger, gives |
| 77 | ;; it the docstring DOC, and binds that function to KEY. NAME should | 123 | ;; it the docstring DOC, and binds that function to KEY in the GUD |
| 78 | ;; be a string. If a numeric prefix argument is given to FUNC, it | 124 | ;; major mode. The function is also bound in the GUD minor-mode |
| 79 | ;; gets sent after NAME. | 125 | ;; keymap. If a numeric prefix argument is given to FUNC, it gets |
| 80 | 126 | ;; sent after NAME. | |
| 81 | (defmacro gud-def (func name key &optional doc) | 127 | |
| 82 | (let* ((cstr (list 'if '(not (= 1 arg)) | 128 | (defmacro gud-def (func cmd key &optional doc) |
| 83 | (list 'format "%s %s" name 'arg) | 129 | "Define FUNC to be a command sending STR and bound to KEY, with |
| 84 | name))) | 130 | optional doc string DOC. Certain %-escapes in the string arguments |
| 85 | (list 'progn | 131 | are interpreted specially if present. These are: |
| 86 | (list 'defun func '(arg) | 132 | |
| 87 | (or doc "") | 133 | %f name of current source file. |
| 88 | '(interactive "p") | 134 | %l number of current source line |
| 89 | (list 'gud-call cstr)) | 135 | %e text of the C lvalue or function-call expression surrounding point. |
| 90 | (if key | 136 | %a text of the hexadecimal address surrounding point |
| 91 | (list 'define-key 'gud-mode-map key (list 'quote func)))))) | 137 | %p prefix argument to the command (if any) as a number |
| 138 | |||
| 139 | The `current' source file is the file of the current buffer (if we're in a | ||
| 140 | C file with gud-minor-mode active) or the source file current at the last | ||
| 141 | break or step (if we're in the GUD buffer). | ||
| 142 | The `current' line is that of the current buffer (if we're in a source | ||
| 143 | file with gud-minor-mode active) or the source line number at the last | ||
| 144 | break or step (if we're in the GUD buffer)." | ||
| 145 | (list 'progn | ||
| 146 | (list 'defun func '(arg) | ||
| 147 | (or doc "") | ||
| 148 | '(interactive "p") | ||
| 149 | (list 'gud-call cmd 'arg)) | ||
| 150 | (if key | ||
| 151 | (list 'define-key | ||
| 152 | 'gud-mode-map | ||
| 153 | (concat gud-key-prefix key) | ||
| 154 | (list 'quote func))))) | ||
| 92 | 155 | ||
| 93 | ;; Where gud-display-frame should put the debugging arrow. This is | 156 | ;; Where gud-display-frame should put the debugging arrow. This is |
| 94 | ;; set by the marker-filter, which scans the debugger's output for | 157 | ;; set by the marker-filter, which scans the debugger's output for |
| 95 | ;; indications of the current pc. | 158 | ;; indications of the current program counter. |
| 96 | (defvar gud-last-frame nil) | 159 | (defvar gud-last-frame nil) |
| 97 | 160 | ||
| 98 | ;; All debugger-specific information is collected here | 161 | ;; All debugger-specific information is collected here. |
| 99 | ;; Here's how it works, in case you ever need to add a debugger to the table. | 162 | ;; Here's how it works, in case you ever need to add a debugger to the mode. |
| 100 | ;; | 163 | ;; |
| 101 | ;; Each entry must define the following at startup: | 164 | ;; Each entry must define the following at startup: |
| 102 | ;; | 165 | ;; |
| @@ -104,11 +167,10 @@ This association list has elements of the form | |||
| 104 | ;; comint-prompt-regexp | 167 | ;; comint-prompt-regexp |
| 105 | ;; gud-<name>-debugger-startup | 168 | ;; gud-<name>-debugger-startup |
| 106 | ;; gud-<name>-marker-filter | 169 | ;; gud-<name>-marker-filter |
| 107 | ;; gud-<name>-visit-file | 170 | ;; gud-<name>-find-file |
| 108 | ;; gud-<name>-set-break | ||
| 109 | ;; | 171 | ;; |
| 110 | ;; The job of the startup-command method is to fire up a copy of the debugger, | 172 | ;; The job of the startup-command method is to fire up a copy of the debugger, |
| 111 | ;; given an object file and source directory. | 173 | ;; given a list of debugger arguments. |
| 112 | ;; | 174 | ;; |
| 113 | ;; The job of the marker-filter method is to detect file/line markers in | 175 | ;; The job of the marker-filter method is to detect file/line markers in |
| 114 | ;; strings and set the global gud-last-frame to indicate what display | 176 | ;; strings and set the global gud-last-frame to indicate what display |
| @@ -117,26 +179,17 @@ This association list has elements of the form | |||
| 117 | ;; can filter the debugger's output, interpreting some and passing on | 179 | ;; can filter the debugger's output, interpreting some and passing on |
| 118 | ;; the rest. | 180 | ;; the rest. |
| 119 | ;; | 181 | ;; |
| 120 | ;; The job of the visit-file method is to visit and return the buffer indicated | 182 | ;; The job of the find-file method is to visit and return the buffer indicated |
| 121 | ;; by the car of gud-tag-frame. This may be a file name, a tag name, or | 183 | ;; by the car of gud-tag-frame. This may be a file name, a tag name, or |
| 122 | ;; something else. | 184 | ;; something else. |
| 123 | ;; | ||
| 124 | ;; The job of the gud-set-break method is to send the commands | ||
| 125 | ;; necessary to set a breakpoint at a given line in a given source | ||
| 126 | ;; file. If its third argument TEMP is non-nil, the breakpoint set | ||
| 127 | ;; should be temporary - it should be deleted when it is reached. If | ||
| 128 | ;; the debugger doesn't support such breakpoints, it should set an | ||
| 129 | ;; ordinary breakpoint. | ||
| 130 | ;; | ||
| 131 | ;; Debugger-specific information begins here: | ||
| 132 | 185 | ||
| 133 | ;; ====================================================================== | 186 | ;; ====================================================================== |
| 134 | ;; gdb functions | 187 | ;; gdb functions |
| 135 | 188 | ||
| 136 | (defun gud-gdb-debugger-startup (f d) | 189 | (defun gud-gdb-debugger-startup (file args) |
| 137 | (make-comint (concat "gud-" f) "gdb" nil "-fullname" "-cd" d f)) | 190 | (apply 'make-comint (concat "gud-" file) "gdb" nil "-fullname" args)) |
| 138 | 191 | ||
| 139 | (defun gud-gdb-marker-filter (proc string) | 192 | (defun gud-gdb-marker-filter (string) |
| 140 | (if (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" string) | 193 | (if (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" string) |
| 141 | (progn | 194 | (progn |
| 142 | (setq gud-last-frame | 195 | (setq gud-last-frame |
| @@ -152,33 +205,33 @@ This association list has elements of the form | |||
| 152 | )) | 205 | )) |
| 153 | string)) | 206 | string)) |
| 154 | 207 | ||
| 155 | (defun gud-gdb-visit-file (f) | 208 | (defun gud-gdb-find-file (f) |
| 156 | (find-file-noselect f)) | 209 | (find-file-noselect f)) |
| 157 | 210 | ||
| 158 | (defun gud-gdb-set-break (proc f n temp) | ||
| 159 | (gud-call "%s %s:%d" (if temp "tbreak" "break") f n)) | ||
| 160 | |||
| 161 | ;;;###autoload | 211 | ;;;###autoload |
| 162 | (defun gdb (path) | 212 | (defun gdb (args) |
| 163 | "Run gdb on program FILE in buffer *gud-FILE*. | 213 | "Run gdb on program FILE in buffer *gud-FILE*. |
| 164 | The directory containing FILE becomes the initial working directory | 214 | The directory containing FILE becomes the initial working directory |
| 165 | and source-file directory for your debugger." | 215 | and source-file directory for your debugger." |
| 166 | (interactive "fRun gdb on file: ") | 216 | (interactive "sgdb ") |
| 167 | (gud-overload-functions '((gud-debugger-startup . gud-gdb-debugger-startup) | 217 | (gud-overload-functions '((gud-debugger-startup . gud-gdb-debugger-startup) |
| 168 | (gud-marker-filter . gud-gdb-marker-filter) | 218 | (gud-marker-filter . gud-gdb-marker-filter) |
| 169 | (gud-visit-file . gud-gdb-visit-file) | 219 | (gud-find-file . gud-gdb-find-file) |
| 170 | (gud-set-break . gud-gdb-set-break))) | 220 | )) |
| 171 | 221 | ||
| 172 | (gud-def gud-step "step" "\C-c\C-s" "Step one source line with display") | 222 | (gud-def gud-break "break %f:%l" "b" "Set breakpoint at current line.") |
| 173 | (gud-def gud-stepi "stepi" "\C-c\C-i" "Step one instruction with display") | 223 | (gud-def gud-tbreak "tbreak %f:%l" "t" "Set breakpoint at current line.") |
| 174 | (gud-def gud-next "next" "\C-c\C-n" "Step one line (skip functions)") | 224 | (gud-def gud-remove "clear %l" "d" "Remove breakpoint at current line") |
| 175 | (gud-def gud-cont "cont" "\C-c\C-r" "Continue with display") | 225 | (gud-def gud-step "step %p" "s" "Step one source line with display.") |
| 176 | 226 | (gud-def gud-stepi "stepi %p" "i" "Step one instruction with display.") | |
| 177 | (gud-def gud-finish "finish" "\C-c\C-f" "Finish executing current function") | 227 | (gud-def gud-next "next %p" "n" "Step one line (skip functions).") |
| 178 | (gud-def gud-up "up" "\C-c<" "Up N stack frames (numeric arg)") | 228 | (gud-def gud-cont "cont" "r" "Continue with display.") |
| 179 | (gud-def gud-down "down" "\C-c>" "Down N stack frames (numeric arg)") | 229 | (gud-def gud-finish "finish" "f" "Finish executing current function.") |
| 180 | 230 | (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") | |
| 181 | (gud-common-init path) | 231 | (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") |
| 232 | (gud-def gud-print "print %e" "p" "Evaluate C expression at point.") | ||
| 233 | |||
| 234 | (gud-common-init args) | ||
| 182 | 235 | ||
| 183 | (setq comint-prompt-regexp "^(.*gdb[+]?) *") | 236 | (setq comint-prompt-regexp "^(.*gdb[+]?) *") |
| 184 | (run-hooks 'gdb-mode-hook) | 237 | (run-hooks 'gdb-mode-hook) |
| @@ -188,47 +241,68 @@ and source-file directory for your debugger." | |||
| 188 | ;; ====================================================================== | 241 | ;; ====================================================================== |
| 189 | ;; sdb functions | 242 | ;; sdb functions |
| 190 | 243 | ||
| 191 | (defun gud-sdb-debugger-startup (f d) | 244 | (defvar gud-sdb-needs-tags (not (file-exists-p "/var")) |
| 192 | (make-comint (concat "gud-" f) "sdb" nil f "-" d)) | 245 | "If nil, we're on a System V Release 4 and don't need the tags hack.") |
| 246 | |||
| 247 | (defvar gud-sdb-lastfile nil) | ||
| 248 | |||
| 249 | (defun gud-sdb-debugger-startup (file args) | ||
| 250 | (apply 'make-comint (concat "gud-" file) "sdb" nil args)) | ||
| 193 | 251 | ||
| 194 | (defun gud-sdb-marker-filter (proc string) | 252 | (defun gud-sdb-marker-filter (string) |
| 195 | (if (string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n" | 253 | (cond |
| 254 | ;; System V Release 3.2 uses this format | ||
| 255 | ((string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n" | ||
| 196 | string) | 256 | string) |
| 197 | (setq gud-last-frame | 257 | (setq gud-last-frame |
| 198 | (cons | 258 | (cons |
| 199 | (substring string (match-beginning 2) (match-end 2)) | 259 | (substring string (match-beginning 2) (match-end 2)) |
| 200 | (string-to-int | 260 | (string-to-int |
| 201 | (substring string (match-beginning 3) (match-end 3)))))) | 261 | (substring string (match-beginning 3) (match-end 3)))))) |
| 262 | ;; System V Release 4.0 | ||
| 263 | ((string-match "^\\(BREAKPOINT\\|STEPPED\\) process [0-9]+ function [^ ]+ in \\(.+\\)\n" | ||
| 264 | string) | ||
| 265 | (setq gud-sdb-lastfile | ||
| 266 | (substring string (match-beginning 2) (match-end 2)))) | ||
| 267 | ((and gud-sdb-lastfile (string-match "^\\([0-9]+\\):" string)) | ||
| 268 | (setq gud-last-frame | ||
| 269 | (cons | ||
| 270 | gud-sdb-lastfile | ||
| 271 | (string-to-int | ||
| 272 | (substring string (match-beginning 1) (match-end 1)))))) | ||
| 273 | (t | ||
| 274 | (setq gud-sdb-lastfile nil))) | ||
| 202 | string) | 275 | string) |
| 203 | 276 | ||
| 204 | (defun gud-sdb-visit-file (f) | 277 | (defun gud-sdb-find-file (f) |
| 205 | (find-tag-noselect f)) | 278 | (if gud-sdb-needs-tags |
| 206 | 279 | (find-tag-noselect f) | |
| 207 | ;;; We'll just ignore the TEMP argument for now; I don't know how to | 280 | (find-file-noselect f))) |
| 208 | ;;; set temporary breakpoints in sdb. (See the description of the | ||
| 209 | ;;; gud-set-break method for details.) | ||
| 210 | (defun gud-sdb-set-break (proc f n temp) | ||
| 211 | (gud-queue-send (format "e %s" f) (format "%d b" n))) | ||
| 212 | 281 | ||
| 213 | ;;;###autoload | 282 | ;;;###autoload |
| 214 | (defun sdb (path) | 283 | (defun sdb (args) |
| 215 | "Run sdb on program FILE in buffer *gud-FILE*. | 284 | "Run sdb on program FILE in buffer *gud-FILE*. |
| 216 | The directory containing FILE becomes the initial working directory | 285 | The directory containing FILE becomes the initial working directory |
| 217 | and source-file directory for your debugger." | 286 | and source-file directory for your debugger." |
| 218 | (interactive "fRun sdb on file: ") | 287 | (interactive "ssdb ") |
| 219 | (if (not (and (boundp 'tags-file-name) (file-exists-p tags-file-name))) | 288 | (if (and gud-sdb-needs-tags |
| 289 | (not (and (boundp 'tags-file-name) (file-exists-p tags-file-name)))) | ||
| 220 | (error "The sdb support requires a valid tags table to work.")) | 290 | (error "The sdb support requires a valid tags table to work.")) |
| 221 | (gud-overload-functions '((gud-debugger-startup . gud-sdb-debugger-startup) | 291 | (gud-overload-functions '((gud-debugger-startup . gud-sdb-debugger-startup) |
| 222 | (gud-marker-filter . gud-sdb-marker-filter) | 292 | (gud-marker-filter . gud-sdb-marker-filter) |
| 223 | (gud-visit-file . gud-sdb-visit-file) | 293 | (gud-find-file . gud-sdb-find-file) |
| 224 | (gud-set-break . gud-sdb-set-break))) | 294 | )) |
| 225 | 295 | ||
| 226 | (gud-def gud-step "s" "\C-c\C-s" "Step one source line with display") | 296 | (gud-def gud-break "%l b" "b" "Set breakpoint at current line.") |
| 227 | (gud-def gud-stepi "i" "\C-c\C-i" "Step one instruction with display") | 297 | (gud-def gud-tbreak "%l c" "t" "Set temporary breakpoint at current line.") |
| 228 | (gud-def gud-next "S" "\C-c\C-n" "Step one source line (skip functions)") | 298 | (gud-def gud-remove "%l d" "d" "Remove breakpoint at current line") |
| 229 | (gud-def gud-cont "c" "\C-c\C-r" "Continue with display (`resume')") | 299 | (gud-def gud-step "s %p" "s" "Step one source line with display.") |
| 300 | (gud-def gud-stepi "i %p" "i" "Step one instruction with display.") | ||
| 301 | (gud-def gud-next "S %p" "n" "Step one line (skip functions).") | ||
| 302 | (gud-def gud-cont "c" "r" "Continue with display.") | ||
| 303 | (gud-def gud-print "%e/" "p" "Evaluate C expression at point.") | ||
| 230 | 304 | ||
| 231 | (gud-common-init path) | 305 | (gud-common-init args) |
| 232 | 306 | ||
| 233 | (setq comint-prompt-regexp "\\(^\\|\n\\)\\*") | 307 | (setq comint-prompt-regexp "\\(^\\|\n\\)\\*") |
| 234 | (run-hooks 'sdb-mode-hook) | 308 | (run-hooks 'sdb-mode-hook) |
| @@ -237,10 +311,10 @@ and source-file directory for your debugger." | |||
| 237 | ;; ====================================================================== | 311 | ;; ====================================================================== |
| 238 | ;; dbx functions | 312 | ;; dbx functions |
| 239 | 313 | ||
| 240 | (defun gud-dbx-debugger-startup (f d) | 314 | (defun gud-dbx-debugger-startup (file args) |
| 241 | (make-comint (concat "gud-" f) "dbx" nil f)) | 315 | (apply 'make-comint (concat "gud-" file) "dbx" nil args)) |
| 242 | 316 | ||
| 243 | (defun gud-dbx-marker-filter (proc string) | 317 | (defun gud-dbx-marker-filter (string) |
| 244 | (if (string-match | 318 | (if (string-match |
| 245 | "stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" string) | 319 | "stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" string) |
| 246 | (setq gud-last-frame | 320 | (setq gud-last-frame |
| @@ -250,35 +324,32 @@ and source-file directory for your debugger." | |||
| 250 | (substring string (match-beginning 1) (match-end 1)))))) | 324 | (substring string (match-beginning 1) (match-end 1)))))) |
| 251 | string) | 325 | string) |
| 252 | 326 | ||
| 253 | (defun gud-dbx-visit-file (f) | 327 | (defun gud-dbx-find-file (f) |
| 254 | (find-file-noselect f)) | 328 | (find-file-noselect f)) |
| 255 | 329 | ||
| 256 | ;;; We'll just ignore the TEMP argument for now; I don't know how to | ||
| 257 | ;;; set temporary breakpoints in dbx. (See the description of the | ||
| 258 | ;;; gud-set-break method for details.) | ||
| 259 | (defun gud-dbx-set-break (proc f n temp) | ||
| 260 | (gud-call "stop at \"%s\":%d" f n)) | ||
| 261 | |||
| 262 | ;;;###autoload | 330 | ;;;###autoload |
| 263 | (defun dbx (path) | 331 | (defun dbx (args) |
| 264 | "Run dbx on program FILE in buffer *gud-FILE*. | 332 | "Run dbx on program FILE in buffer *gud-FILE*. |
| 265 | The directory containing FILE becomes the initial working directory | 333 | The directory containing FILE becomes the initial working directory |
| 266 | and source-file directory for your debugger." | 334 | and source-file directory for your debugger." |
| 267 | (interactive "fRun dbx on file: ") | 335 | (interactive "sdbx") |
| 268 | (gud-overload-functions '((gud-debugger-startup . gud-dbx-debugger-startup) | 336 | (gud-overload-functions '((gud-debugger-startup . gud-dbx-debugger-startup) |
| 269 | (gud-marker-filter . gud-dbx-marker-filter) | 337 | (gud-marker-filter . gud-dbx-marker-filter) |
| 270 | (gud-visit-file . gud-dbx-visit-file) | 338 | (gud-find-file . gud-dbx-find-file) |
| 271 | (gud-set-break . gud-dbx-set-break))) | 339 | )) |
| 272 | 340 | ||
| 273 | (gud-def gud-step "step" "\C-c\C-s" "Step one source line with display") | 341 | (gud-def gud-break "stop at \"%f\":%l" |
| 274 | (gud-def gud-stepi "stepi" "\C-c\C-i" "Step one instruction with display") | 342 | "b" "Set breakpoint at current line.") |
| 275 | (gud-def gud-next "next" "\C-c\C-n" "Step one line (skip functions)") | 343 | (gud-def gud-remove "clear %l" "d" "Remove breakpoint at current line") |
| 276 | (gud-def gud-cont "cont" "\C-c\C-r" "Continue with display (`resume')") | 344 | (gud-def gud-step "step %p" "s" "Step one line with display.") |
| 277 | 345 | (gud-def gud-stepi "stepi %p" "i" "Step one instruction with display.") | |
| 278 | (gud-def gud-up "up" "\C-c<" "Up N stack frames (numeric arg)") | 346 | (gud-def gud-next "next %p" "n" "Step one line (skip functions).") |
| 279 | (gud-def gud-down "down" "\C-c>" "Down N stack frames (numeric arg)") | 347 | (gud-def gud-cont "cont" "r" "Continue with display.") |
| 280 | 348 | (gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.") | |
| 281 | (gud-common-init path) | 349 | (gud-def gud-down "down %p" ">" "Down (numeric arg) stack frames.") |
| 350 | (gud-def gud-print "print %e" "p" "Evaluate C expression at point.") | ||
| 351 | |||
| 352 | (gud-common-init args) | ||
| 282 | (setq comint-prompt-regexp "^[^)]*dbx) *") | 353 | (setq comint-prompt-regexp "^[^)]*dbx) *") |
| 283 | 354 | ||
| 284 | (run-hooks 'dbx-mode-hook) | 355 | (run-hooks 'dbx-mode-hook) |
| @@ -288,15 +359,6 @@ and source-file directory for your debugger." | |||
| 288 | ;; End of debugger-specific information | 359 | ;; End of debugger-specific information |
| 289 | ;; | 360 | ;; |
| 290 | 361 | ||
| 291 | (defvar gud-mode-map nil | ||
| 292 | "Keymap for gud-mode.") | ||
| 293 | |||
| 294 | (defvar gud-commands nil | ||
| 295 | "List of strings or functions used by send-gud-command. | ||
| 296 | It is for customization by you.") | ||
| 297 | |||
| 298 | (defvar gud-command-queue nil) | ||
| 299 | |||
| 300 | ;;; When we send a command to the debugger via gud-call, it's annoying | 362 | ;;; When we send a command to the debugger via gud-call, it's annoying |
| 301 | ;;; to see the command and the new prompt inserted into the debugger's | 363 | ;;; to see the command and the new prompt inserted into the debugger's |
| 302 | ;;; buffer; we have other ways of knowing the command has completed. | 364 | ;;; buffer; we have other ways of knowing the command has completed. |
| @@ -339,15 +401,6 @@ It is for customization by you.") | |||
| 339 | ;;; prompt alone. | 401 | ;;; prompt alone. |
| 340 | (defvar gud-delete-prompt-marker nil) | 402 | (defvar gud-delete-prompt-marker nil) |
| 341 | 403 | ||
| 342 | (if gud-mode-map | ||
| 343 | nil | ||
| 344 | (setq gud-mode-map (copy-keymap comint-mode-map)) | ||
| 345 | (define-key gud-mode-map "\C-c\C-l" 'gud-refresh)) | ||
| 346 | |||
| 347 | ;; Global mappings --- we'll invoke these from a source buffer. | ||
| 348 | (define-key ctl-x-map " " 'gud-break) | ||
| 349 | (define-key ctl-x-map "&" 'send-gud-command) | ||
| 350 | |||
| 351 | 404 | ||
| 352 | (defun gud-mode () | 405 | (defun gud-mode () |
| 353 | "Major mode for interacting with an inferior debugger process. | 406 | "Major mode for interacting with an inferior debugger process. |
| @@ -356,52 +409,56 @@ It is for customization by you.") | |||
| 356 | M-x dbx. Each entry point finishes by executing a hook; gdb-mode-hook, | 409 | M-x dbx. Each entry point finishes by executing a hook; gdb-mode-hook, |
| 357 | sdb-mode-hook or dbx-mode-hook respectively. | 410 | sdb-mode-hook or dbx-mode-hook respectively. |
| 358 | 411 | ||
| 359 | After startup, the following commands are available: | 412 | After startup, the following commands are available in both the GUD |
| 413 | interaction buffer and any source buffer GUD visits due to a breakpoint stop | ||
| 414 | or step operation: | ||
| 360 | 415 | ||
| 361 | \\{gud-mode-map} | 416 | \\{gud-mode-map} |
| 362 | 417 | ||
| 363 | \\[gud-refresh] displays in the other window the last line referred to | 418 | \\[gud-break] sets a breakpoint at the current file and line. In the |
| 419 | GUD buffer, the current file and line are those of the last breakpoint or | ||
| 420 | step. In a source buffer, they are the buffer's file and current line. | ||
| 421 | |||
| 422 | \\[gud-refresh] displays in the source window the last line referred to | ||
| 364 | in the gud buffer. | 423 | in the gud buffer. |
| 365 | 424 | ||
| 366 | \\[gud-step], \\[gud-next], and \\[gud-stepi] in the gud window, | 425 | \\[gud-step], \\[gud-next], and \\[gud-stepi] do a step-one-line, |
| 367 | do a step-one-line, step-one-line (not entering function calls), and | 426 | step-one-line (not entering function calls), and step-one-instruction |
| 368 | step-one-instruction and then update the other window | 427 | and then update the source window with the current file and position. |
| 369 | with the current file and position. \\[gud-cont] continues | 428 | \\[gud-cont] continues execution. |
| 370 | execution. | ||
| 371 | 429 | ||
| 372 | The above commands are common to all supported debuggers. If you are | 430 | \\[gud-print] tries to find the largest C lvalue or function-call expression |
| 373 | using gdb or dbx, the following additional commands will be available: | 431 | around point, and sends it to the debugger for value display. |
| 374 | 432 | ||
| 375 | \\[gud-up] pops up through an enclosing stack frame. \\[gud-down] drops | 433 | The above commands are common to all supported debuggers. |
| 376 | back down through one. | ||
| 377 | 434 | ||
| 378 | If you are using gdb, \\[gdb-finish] runs execution to the return from | 435 | Under gdb and sdb, \\[gud-tbreak] behaves exactly like \\[gud-break], |
| 379 | the current function and stops. | 436 | except that the breakpoint is temporary; that is, it is removed when |
| 437 | execution stops on it. | ||
| 380 | 438 | ||
| 381 | These functions repeat themselves the appropriate number of times if you give a | 439 | Under gdb and dbx, \\[gud-up] pops up through an enclosing stack |
| 382 | prefix argument. | 440 | frame. \\[gud-down] drops back down through one. |
| 383 | 441 | ||
| 384 | If you are in a source file, you may do the following: | 442 | If you are using gdb, \\[gdb-finish] runs execution to the return from |
| 443 | the current function and stops. | ||
| 385 | 444 | ||
| 386 | Set a breakpoint at the current line by doing \\[gud-break]. This causes | 445 | All pre-defined functions for which the concept make sense repeat |
| 387 | an appropriate set-break to be send to the debugger; of course, if the file | 446 | themselves the appropriate number of times if you give a prefix |
| 388 | you're visiting doesn't correspond to any code in the executable this will | 447 | argument. |
| 389 | have no effect or raise an error. | ||
| 390 | 448 | ||
| 391 | Execute a user-defined command at point with \\[send-gud-command]; the | 449 | You may use the gud-def macro in the initialization hook to define other |
| 392 | prefix argument is taken as an index into the list of strings gud-commands. | 450 | commands. |
| 393 | A %s in a gud-commands string is substituted with a number or address picked | ||
| 394 | up from point. | ||
| 395 | 451 | ||
| 396 | Other commands for interacting with the debugger process are inherited from | 452 | Other commands for interacting with the debugger process are inherited from |
| 397 | comint mode, which see." | 453 | comint mode, which see." |
| 398 | (interactive) | 454 | (interactive) |
| 399 | (comint-mode) | 455 | (comint-mode) |
| 400 | ; (kill-all-local-variables) | ||
| 401 | (setq major-mode 'gud-mode) | 456 | (setq major-mode 'gud-mode) |
| 402 | (setq mode-name "Debugger") | 457 | (setq mode-name "Debugger") |
| 403 | (setq mode-line-process '(": %s")) | 458 | (setq mode-line-process '(": %s")) |
| 404 | (use-local-map gud-mode-map) | 459 | (use-local-map (copy-keymap comint-mode-map)) |
| 460 | (define-key (current-local-map) | ||
| 461 | gud-key-prefix (lookup-key gud-mode-map gud-key-prefix)) | ||
| 405 | (make-local-variable 'gud-last-frame) | 462 | (make-local-variable 'gud-last-frame) |
| 406 | (setq gud-last-frame nil) | 463 | (setq gud-last-frame nil) |
| 407 | (make-local-variable 'comint-prompt-regexp) | 464 | (make-local-variable 'comint-prompt-regexp) |
| @@ -410,78 +467,87 @@ comint mode, which see." | |||
| 410 | (run-hooks 'gud-mode-hook) | 467 | (run-hooks 'gud-mode-hook) |
| 411 | ) | 468 | ) |
| 412 | 469 | ||
| 413 | (defvar current-gud-buffer nil) | 470 | (defvar gud-comint-buffer nil) |
| 414 | 471 | ||
| 415 | (defun gud-common-init (path) | 472 | (defun gud-common-init (args) |
| 416 | ;; perform initializations common to all debuggers | 473 | ;; Perform initializations common to all debuggers |
| 417 | (setq path (expand-file-name path)) | 474 | ;; There *must* be a cleaner way to lex the arglist... |
| 418 | (let ((file (file-name-nondirectory path))) | 475 | (let (file i) |
| 419 | (switch-to-buffer (concat "*gud-" file "*")) | 476 | (if (string= args "") |
| 420 | (setq default-directory (file-name-directory path)) | 477 | (setq args nil) |
| 421 | (or (bolp) (newline)) | 478 | (set-buffer (get-buffer-create "*gud-scratch*")) |
| 422 | (insert "Current directory is " default-directory "\n") | 479 | (erase-buffer) |
| 423 | (gud-debugger-startup file default-directory)) | 480 | (insert args) |
| 481 | (goto-char (point-max)) | ||
| 482 | (insert "\")") | ||
| 483 | (goto-char (point-min)) | ||
| 484 | (insert "(\"") | ||
| 485 | (while (re-search-forward " +" nil t) | ||
| 486 | (replace-match "\" \"" nil nil)) | ||
| 487 | (goto-char (point-min)) | ||
| 488 | (while (re-search-forward "\"\"" nil t) | ||
| 489 | (replace-match "" nil nil)) | ||
| 490 | (setq args (read (buffer-string))) | ||
| 491 | (kill-buffer (current-buffer))) | ||
| 492 | (setq i (1- (length args))) | ||
| 493 | (while (and (>= i 0) (not (= (aref (nth i args) 0) ?-))) | ||
| 494 | (setq file (nth i args)) (setq i (1- i))) | ||
| 495 | (let* ((path (expand-file-name file)) | ||
| 496 | (filepart (file-name-nondirectory path))) | ||
| 497 | (switch-to-buffer (concat "*gud-" filepart "*")) | ||
| 498 | (setq default-directory (file-name-directory path)) | ||
| 499 | (or (bolp) (newline)) | ||
| 500 | (insert "Current directory is " default-directory "\n") | ||
| 501 | (gud-debugger-startup filepart args))) | ||
| 424 | (gud-mode) | 502 | (gud-mode) |
| 425 | (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) | 503 | (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) |
| 426 | (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel) | 504 | (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel) |
| 427 | (setq gud-command-queue nil) | ||
| 428 | (gud-set-buffer) | 505 | (gud-set-buffer) |
| 429 | ) | 506 | ) |
| 430 | 507 | ||
| 431 | (defun gud-set-buffer () | 508 | (defun gud-set-buffer () |
| 432 | (cond ((eq major-mode 'gud-mode) | 509 | (cond ((eq major-mode 'gud-mode) |
| 433 | (setq current-gud-buffer (current-buffer))))) | 510 | (setq gud-comint-buffer (current-buffer))))) |
| 434 | 511 | ||
| 435 | (defun gud-filter (proc string) | 512 | ;; These functions are responsible for inserting output from your debugger |
| 436 | ;; This function is responsible for inserting output from your debugger | 513 | ;; into the buffer. The hard work is done by the method that is |
| 437 | ;; into the buffer. The hard work is done by the method that is | 514 | ;; the value of gud-marker-filter. |
| 438 | ;; the value of gud-marker-filter. | ||
| 439 | (let ((inhibit-quit t)) | ||
| 440 | (gud-filter-insert proc (gud-marker-filter proc string)) | ||
| 441 | ;; If we've got queued commands and we see a prompt, pop one and send it. | ||
| 442 | ;; In theory we should check that a prompt has been issued before sending | ||
| 443 | ;; queued commands. In practice, command responses from the first through | ||
| 444 | ;; penultimate elements of a command sequence are short enough that we | ||
| 445 | ;; don't really have to bother. | ||
| 446 | (if gud-command-queue | ||
| 447 | (progn | ||
| 448 | (gud-call (car gud-command-queue)) | ||
| 449 | (setq gud-command-queue (cdr gud-command-queue)) | ||
| 450 | ) | ||
| 451 | ))) | ||
| 452 | 515 | ||
| 453 | (defun gud-filter-insert (proc string) | 516 | (defun gud-filter (proc string) |
| 454 | ;; Here's where the actual buffer insertion is done | 517 | ;; Here's where the actual buffer insertion is done |
| 455 | (save-excursion | 518 | (let ((inhibit-quit t)) |
| 456 | (set-buffer (process-buffer proc)) | 519 | (save-excursion |
| 457 | (let ((moving (= (point) (process-mark proc))) | 520 | (set-buffer (process-buffer proc)) |
| 458 | (output-after-point (< (point) (process-mark proc)))) | 521 | (let ((moving (= (point) (process-mark proc))) |
| 459 | (save-excursion | 522 | (output-after-point (< (point) (process-mark proc)))) |
| 460 | (goto-char (process-mark proc)) | 523 | (save-excursion |
| 461 | ;; If we have been so requested, delete the debugger prompt. | 524 | (goto-char (process-mark proc)) |
| 462 | (if (marker-buffer gud-delete-prompt-marker) | 525 | ;; If we have been so requested, delete the debugger prompt. |
| 463 | (progn | 526 | (if (marker-buffer gud-delete-prompt-marker) |
| 464 | (delete-region (point) gud-delete-prompt-marker) | 527 | (progn |
| 465 | (set-marker gud-delete-prompt-marker nil))) | 528 | (delete-region (point) gud-delete-prompt-marker) |
| 466 | (insert-before-markers string) | 529 | (set-marker gud-delete-prompt-marker nil))) |
| 467 | ;; Check for a filename-and-line number. | 530 | (insert-before-markers (gud-marker-filter string)) |
| 468 | ;; Don't display the specified file | 531 | ;; Check for a filename-and-line number. |
| 469 | ;; unless (1) point is at or after the position where output appears | 532 | ;; Don't display the specified file |
| 470 | ;; and (2) this buffer is on the screen. | 533 | ;; unless (1) point is at or after the position where output appears |
| 471 | (if (and gud-last-frame | 534 | ;; and (2) this buffer is on the screen. |
| 472 | (not output-after-point) | 535 | (if (and gud-last-frame |
| 473 | (get-buffer-window (current-buffer))) | 536 | (not output-after-point) |
| 474 | (gud-display-frame))) | 537 | (get-buffer-window (current-buffer))) |
| 475 | (if moving (goto-char (process-mark proc)))))) | 538 | (gud-display-frame))) |
| 539 | (if moving (goto-char (process-mark proc))))))) | ||
| 476 | 540 | ||
| 477 | (defun gud-sentinel (proc msg) | 541 | (defun gud-sentinel (proc msg) |
| 478 | (cond ((null (buffer-name (process-buffer proc))) | 542 | (cond ((null (buffer-name (process-buffer proc))) |
| 479 | ;; buffer killed | 543 | ;; buffer killed |
| 480 | ;; Stop displaying an arrow in a source file. | 544 | ;; Stop displaying an arrow in a source file. |
| 481 | (setq overlay-arrow-position nil) | 545 | (setq overlay-arrow-position nil) |
| 546 | (setq gud-minor-mode nil) | ||
| 482 | (set-process-buffer proc nil)) | 547 | (set-process-buffer proc nil)) |
| 483 | ((memq (process-status proc) '(signal exit)) | 548 | ((memq (process-status proc) '(signal exit)) |
| 484 | ;; Stop displaying an arrow in a source file. | 549 | ;; Stop displaying an arrow in a source file. |
| 550 | (setq gud-minor-mode nil) | ||
| 485 | (setq overlay-arrow-position nil) | 551 | (setq overlay-arrow-position nil) |
| 486 | ;; Fix the mode line. | 552 | ;; Fix the mode line. |
| 487 | (setq mode-line-process | 553 | (setq mode-line-process |
| @@ -509,19 +575,12 @@ comint mode, which see." | |||
| 509 | ;; if obuf is the gud buffer. | 575 | ;; if obuf is the gud buffer. |
| 510 | (set-buffer obuf)))))) | 576 | (set-buffer obuf)))))) |
| 511 | 577 | ||
| 512 | |||
| 513 | (defun gud-refresh (&optional arg) | ||
| 514 | "Fix up a possibly garbled display, and redraw the arrow." | ||
| 515 | (interactive "P") | ||
| 516 | (recenter arg) | ||
| 517 | (gud-display-frame)) | ||
| 518 | |||
| 519 | (defun gud-display-frame () | 578 | (defun gud-display-frame () |
| 520 | "Find and obey the last filename-and-line marker from the debugger. | 579 | "Find and obey the last filename-and-line marker from the debugger. |
| 521 | Obeying it means displaying in another window the specified file and line." | 580 | Obeying it means displaying in another window the specified file and line." |
| 522 | (interactive) | 581 | (interactive) |
| 523 | (if gud-last-frame | 582 | (if gud-last-frame |
| 524 | (progn | 583 | (progn |
| 525 | (gud-set-buffer) | 584 | (gud-set-buffer) |
| 526 | (gud-display-line (car gud-last-frame) (cdr gud-last-frame)) | 585 | (gud-display-line (car gud-last-frame) (cdr gud-last-frame)) |
| 527 | (setq gud-last-frame nil)))) | 586 | (setq gud-last-frame nil)))) |
| @@ -529,13 +588,18 @@ Obeying it means displaying in another window the specified file and line." | |||
| 529 | ;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen | 588 | ;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen |
| 530 | ;; and that its line LINE is visible. | 589 | ;; and that its line LINE is visible. |
| 531 | ;; Put the overlay-arrow on the line LINE in that buffer. | 590 | ;; Put the overlay-arrow on the line LINE in that buffer. |
| 591 | ;; Most of the trickiness in here comes from wanting to preserve the current | ||
| 592 | ;; region-restriction if that's possible. We use an explicit display-buffer | ||
| 593 | ;; to get around the fact that this is called inside a save-excursion. | ||
| 532 | 594 | ||
| 533 | (defun gud-display-line (true-file line) | 595 | (defun gud-display-line (true-file line) |
| 534 | (let* ((buffer (gud-visit-file true-file)) | 596 | (let* ((buffer (gud-find-file true-file)) |
| 535 | (window (display-buffer buffer t)) | 597 | (window (display-buffer buffer)) |
| 536 | (pos)) | 598 | (pos)) |
| 537 | (save-excursion | 599 | (save-excursion |
| 538 | (set-buffer buffer) | 600 | (set-buffer buffer) |
| 601 | (make-local-variable 'gud-minor-mode) | ||
| 602 | (setq gud-minor-mode t) | ||
| 539 | (save-restriction | 603 | (save-restriction |
| 540 | (widen) | 604 | (widen) |
| 541 | (goto-line line) | 605 | (goto-line line) |
| @@ -548,62 +612,60 @@ Obeying it means displaying in another window the specified file and line." | |||
| 548 | (widen) | 612 | (widen) |
| 549 | (goto-char pos)))) | 613 | (goto-char pos)))) |
| 550 | (set-window-point window overlay-arrow-position))) | 614 | (set-window-point window overlay-arrow-position))) |
| 551 | |||
| 552 | (defun gud-call (command &rest args) | ||
| 553 | "Invoke the debugger COMMAND displaying source in other window." | ||
| 554 | (interactive) | ||
| 555 | (gud-set-buffer) | ||
| 556 | (let ((command (concat (apply 'format command args) "\n")) | ||
| 557 | (proc (get-buffer-process current-gud-buffer))) | ||
| 558 | |||
| 559 | ;; Arrange for the current prompt to get deleted. | ||
| 560 | (save-excursion | ||
| 561 | (set-buffer current-gud-buffer) | ||
| 562 | (goto-char (process-mark proc)) | ||
| 563 | (beginning-of-line) | ||
| 564 | (if (looking-at comint-prompt-regexp) | ||
| 565 | (set-marker gud-delete-prompt-marker (point)))) | ||
| 566 | 615 | ||
| 567 | (goto-char (point-max)) | 616 | ;;; The gud-call function must do the right thing whether its invoking |
| 568 | (process-send-string proc command))) | 617 | ;;; keystroke is from the GUD buffer itself (via major-mode binding) |
| 618 | ;;; or a C buffer in GUD minor mode. In the former case, we want to | ||
| 619 | ;;; supply data from gud-last-frame. Here's how we do it: | ||
| 569 | 620 | ||
| 570 | (defun gud-queue-send (&rest cmdlist) | 621 | (defun gud-format-command (str arg) |
| 571 | ;; Send the first command, queue the rest for send after successive | 622 | (let ((minor (not (eq (current-buffer) gud-comint-buffer)))) |
| 572 | ;; send on subsequent prompts | 623 | (if (string-match "\\(.*\\)%f\\(.*\\)" str) |
| 573 | (interactive) | 624 | (progn |
| 574 | (gud-call (car cmdlist)) | 625 | (setq str (concat |
| 575 | (setq gud-command-queue (append gud-command-queue (cdr cmdlist)))) | 626 | (substring str (match-beginning 1) (match-end 1)) |
| 576 | 627 | (if minor | |
| 577 | (defun gud-apply-from-source (func &rest args) | 628 | (buffer-file-name) |
| 578 | ;; Apply a method from the gud buffer environment, passing it file | 629 | (car gud-last-frame)) |
| 579 | ;; and line, then ARGS. This is intended to be used for gud | 630 | (substring str (match-beginning 2) (match-end 2)))))) |
| 580 | ;; commands called from a source file. | 631 | (if (string-match "\\(.*\\)%l\\(.*\\)" str) |
| 581 | (if (not buffer-file-name) | 632 | (progn |
| 582 | (error "There is no file associated with this buffer")) | 633 | (setq str (concat |
| 583 | (let ((file (file-name-nondirectory buffer-file-name)) | 634 | (substring str (match-beginning 1) (match-end 1)) |
| 584 | (line (save-restriction (widen) (1+ (count-lines 1 (point)))))) | 635 | (if minor |
| 585 | (save-excursion | 636 | (save-excursion |
| 586 | (gud-set-buffer) | 637 | (beginning-of-line) |
| 587 | (apply func | 638 | (save-restriction (widen) |
| 588 | (get-buffer-process current-gud-buffer) | 639 | (1+ (count-lines 1 (point))))) |
| 589 | file | 640 | (cdr gud-last-frame)) |
| 590 | line | 641 | (substring str (match-beginning 2) (match-end 2)))))) |
| 591 | args) | 642 | (if (string-match "\\(.*\\)%e\\(.*\\)" str) |
| 592 | ))) | 643 | (progn |
| 593 | 644 | (setq str (concat | |
| 594 | (defun gud-break (arg) | 645 | (substring str (match-beginning 1) (match-end 1)) |
| 595 | "Set breakpoint at this source line. | 646 | (find-c-expr) |
| 596 | With prefix argument, set a temporary breakpoint, if the debugger in | 647 | (substring str (match-beginning 2) (match-end 2)))))) |
| 597 | use supports such things. (A temporary breakpoint is one which will | 648 | (if (string-match "\\(.*\\)%a\\(.*\\)" str) |
| 598 | be deleted when it is reached.)" | 649 | (progn |
| 599 | (interactive "P") | 650 | (setq str (concat |
| 600 | (gud-apply-from-source 'gud-set-break arg)) | 651 | (substring str (match-beginning 1) (match-end 1)) |
| 652 | (gud-read-address) | ||
| 653 | (substring str (match-beginning 2) (match-end 2)))))) | ||
| 654 | (if (string-match "\\(.*\\)%p\\(.*\\)" str) | ||
| 655 | (progn | ||
| 656 | (setq str (concat | ||
| 657 | (substring str (match-beginning 1) (match-end 1)) | ||
| 658 | (if arg (int-to-string arg) "") | ||
| 659 | (substring str (match-beginning 2) (match-end 2)))))) | ||
| 660 | ) | ||
| 661 | str | ||
| 662 | ) | ||
| 601 | 663 | ||
| 602 | (defun gud-read-address () | 664 | (defun gud-read-address () |
| 603 | "Return a string containing the core-address found in the buffer at point." | 665 | "Return a string containing the core-address found in the buffer at point." |
| 604 | (save-excursion | 666 | (save-excursion |
| 605 | (let ((pt (point)) found begin) | 667 | (let ((pt (point)) found begin) |
| 606 | (setq found (if (search-backward "0x" (- pt 7) t)(point))) | 668 | (setq found (if (search-backward "0x" (- pt 7) t) (point))) |
| 607 | (cond | 669 | (cond |
| 608 | (found (forward-char 2) | 670 | (found (forward-char 2) |
| 609 | (buffer-substring found | 671 | (buffer-substring found |
| @@ -618,26 +680,183 @@ be deleted when it is reached.)" | |||
| 618 | (forward-char -1) | 680 | (forward-char -1) |
| 619 | (buffer-substring begin (point))))))) | 681 | (buffer-substring begin (point))))))) |
| 620 | 682 | ||
| 683 | (defun gud-call (fmt &optional arg) | ||
| 684 | (let ((msg (gud-format-command fmt arg))) | ||
| 685 | (message "Command: %s" msg) | ||
| 686 | (sit-for 0) | ||
| 687 | (gud-basic-call msg))) | ||
| 621 | 688 | ||
| 622 | (defun send-gud-command (arg) | 689 | (defun gud-basic-call (command) |
| 623 | "This command reads the number where the cursor is positioned. A numeric arg | 690 | "Invoke the debugger COMMAND displaying source in other window." |
| 624 | selects the ARG'th member COMMAND of the list gud-commands. If COMMAND is a | 691 | (interactive) |
| 625 | string, (format COMMAND ADDR) is inserted at the end of the debugger buffer, | 692 | (gud-set-buffer) |
| 626 | otherwise (funcall COMMAND ADDR) is inserted. | 693 | (let ((command (concat command "\n")) |
| 627 | For example, \"p (rtx)%s->fld[0].rtint\" is a possible string to be a | 694 | (proc (get-buffer-process gud-comint-buffer))) |
| 628 | member of gud-commands." | 695 | |
| 696 | ;; Arrange for the current prompt to get deleted. | ||
| 697 | (save-excursion | ||
| 698 | (set-buffer gud-comint-buffer) | ||
| 699 | (goto-char (process-mark proc)) | ||
| 700 | (beginning-of-line) | ||
| 701 | (if (looking-at comint-prompt-regexp) | ||
| 702 | (set-marker gud-delete-prompt-marker (point)))) | ||
| 703 | (process-send-string proc command))) | ||
| 704 | |||
| 705 | (defun gud-refresh (&optional arg) | ||
| 706 | "Fix up a possibly garbled display, and redraw the arrow." | ||
| 629 | (interactive "P") | 707 | (interactive "P") |
| 630 | (let (comm addr) | 708 | (recenter arg) |
| 631 | (if arg (setq comm (nth arg gud-commands))) | 709 | (gud-display-frame)) |
| 632 | (setq addr (gud-read-address)) | 710 | |
| 633 | (if (eq (current-buffer) current-gud-buffer) | 711 | ;;; Code for parsing expressions out of C code. The single entry point is |
| 634 | (set-mark (point))) | 712 | ;;; find-c-expr, which tries to return an lvalue expression from around point. |
| 635 | (cond (comm | 713 | ;;; |
| 636 | (setq comm | 714 | ;;; The rest of this file is a hacked version of gdbsrc.el by |
| 637 | (if (stringp comm) (format comm addr) (funcall comm addr)))) | 715 | ;;; Debby Ayers <ayers@asc.slb.com>, |
| 638 | (t (setq comm addr))) | 716 | ;;; Rich Schaefer <schaefer@asc.slb.com> Schlumberger, Austin, Tx. |
| 639 | (switch-to-buffer current-gud-buffer) | 717 | ;;; ??? We're waiting on papers from these people |
| 640 | (goto-char (point-max)) | 718 | |
| 641 | (insert-string comm))) | 719 | (defun find-c-expr () |
| 720 | "Returns the C expr that surrounds point." | ||
| 721 | (interactive) | ||
| 722 | (save-excursion | ||
| 723 | (let ((p) (expr) (test-expr)) | ||
| 724 | (setq p (point)) | ||
| 725 | (setq expr (expr-cur)) | ||
| 726 | (setq test-expr (expr-prev)) | ||
| 727 | (while (expr-compound test-expr expr) | ||
| 728 | (setq expr (cons (car test-expr) (cdr expr))) | ||
| 729 | (goto-char (car expr)) | ||
| 730 | (setq test-expr (expr-prev)) | ||
| 731 | ) | ||
| 732 | (goto-char p) | ||
| 733 | (setq test-expr (expr-next)) | ||
| 734 | (while (expr-compound expr test-expr) | ||
| 735 | (setq expr (cons (car expr) (cdr test-expr))) | ||
| 736 | (setq test-expr (expr-next)) | ||
| 737 | ) | ||
| 738 | (buffer-substring (car expr) (cdr expr)) | ||
| 739 | ) | ||
| 740 | ) | ||
| 741 | ) | ||
| 742 | |||
| 743 | (defun expr-cur () | ||
| 744 | "Returns the expr that point is in; point is set to beginning of expr. | ||
| 745 | The expr is represented as a cons cell, where the car specifies the point in | ||
| 746 | the current buffer that marks the beginning of the expr and the cdr specifies | ||
| 747 | the character after the end of the expr" | ||
| 748 | (let ((p (point)) (begin) (end)) | ||
| 749 | (back-expr) | ||
| 750 | (setq begin (point)) | ||
| 751 | (forw-expr) | ||
| 752 | (setq end (point)) | ||
| 753 | (if (>= p end) | ||
| 754 | (progn | ||
| 755 | (setq begin p) | ||
| 756 | (goto-char p) | ||
| 757 | (forw-expr) | ||
| 758 | (setq end (point)) | ||
| 759 | ) | ||
| 760 | ) | ||
| 761 | (goto-char begin) | ||
| 762 | (cons begin end) | ||
| 763 | ) | ||
| 764 | ) | ||
| 765 | |||
| 766 | (defun back-expr () | ||
| 767 | "Version of backward-sexp that catches errors" | ||
| 768 | (condition-case nil | ||
| 769 | (backward-sexp) | ||
| 770 | (error t))) | ||
| 771 | |||
| 772 | (defun forw-expr () | ||
| 773 | "Version of forward-sexp that catches errors" | ||
| 774 | (condition-case nil | ||
| 775 | (forward-sexp) | ||
| 776 | (error t))) | ||
| 777 | |||
| 778 | (defun expr-prev () | ||
| 779 | "Returns the previous expr, point is set to beginning of that expr. | ||
| 780 | The expr is represented as a cons cell, where the car specifies the point in | ||
| 781 | the current buffer that marks the beginning of the expr and the cdr specifies | ||
| 782 | the character after the end of the expr" | ||
| 783 | (let ((begin) (end)) | ||
| 784 | (back-expr) | ||
| 785 | (setq begin (point)) | ||
| 786 | (forw-expr) | ||
| 787 | (setq end (point)) | ||
| 788 | (goto-char begin) | ||
| 789 | (cons begin end))) | ||
| 790 | |||
| 791 | (defun expr-next () | ||
| 792 | "Returns the following expr, point is set to beginning of that expr. | ||
| 793 | The expr is represented as a cons cell, where the car specifies the point in | ||
| 794 | the current buffer that marks the beginning of the expr and the cdr specifies | ||
| 795 | the character after the end of the expr" | ||
| 796 | (let ((begin) (end)) | ||
| 797 | (forw-expr) | ||
| 798 | (forw-expr) | ||
| 799 | (setq end (point)) | ||
| 800 | (back-expr) | ||
| 801 | (setq begin (point)) | ||
| 802 | (cons begin end) | ||
| 803 | ) | ||
| 804 | ) | ||
| 805 | |||
| 806 | (defun expr-compound-sep (span-start span-end) | ||
| 807 | "Returns '.' for '->' & '.', returns ' ' for white space, | ||
| 808 | returns '?' for other puctuation." | ||
| 809 | (let ((result ? ) | ||
| 810 | (syntax)) | ||
| 811 | (while (< span-start span-end) | ||
| 812 | (setq syntax (char-syntax (char-after span-start))) | ||
| 813 | (cond | ||
| 814 | ((= syntax ? ) t) | ||
| 815 | ((= syntax ?.) (setq syntax (char-after span-start)) | ||
| 816 | (cond | ||
| 817 | ((= syntax ?.) (setq result ?.)) | ||
| 818 | ((and (= syntax ?-) (= (char-after (+ span-start 1)) ?>)) | ||
| 819 | (setq result ?.) | ||
| 820 | (setq span-start (+ span-start 1))) | ||
| 821 | (t (setq span-start span-end) | ||
| 822 | (setq result ??))))) | ||
| 823 | (setq span-start (+ span-start 1))) | ||
| 824 | result | ||
| 825 | ) | ||
| 826 | ) | ||
| 827 | |||
| 828 | (defun expr-compound (first second) | ||
| 829 | "Returns non-nil if the concatenation of two exprs results in a single C | ||
| 830 | token. The two exprs are represented as a cons cells, where the car | ||
| 831 | specifies the point in the current buffer that marks the beginning of the | ||
| 832 | expr and the cdr specifies the character after the end of the expr | ||
| 833 | Link exprs of the form: | ||
| 834 | Expr -> Expr | ||
| 835 | Expr . Expr | ||
| 836 | Expr (Expr) | ||
| 837 | Expr [Expr] | ||
| 838 | (Expr) Expr | ||
| 839 | [Expr] Expr" | ||
| 840 | (let ((span-start (cdr first)) | ||
| 841 | (span-end (car second)) | ||
| 842 | (syntax)) | ||
| 843 | (setq syntax (expr-compound-sep span-start span-end)) | ||
| 844 | (cond | ||
| 845 | ((= (car first) (car second)) nil) | ||
| 846 | ((= (cdr first) (cdr second)) nil) | ||
| 847 | ((= syntax ?.) t) | ||
| 848 | ((= syntax ? ) | ||
| 849 | (setq span-start (char-after (- span-start 1))) | ||
| 850 | (setq span-end (char-after span-end)) | ||
| 851 | (cond | ||
| 852 | ((= span-start ?) ) t ) | ||
| 853 | ((= span-start ?] ) t ) | ||
| 854 | ((= span-end ?( ) t ) | ||
| 855 | ((= span-end ?[ ) t ) | ||
| 856 | (t nil)) | ||
| 857 | ) | ||
| 858 | (t nil)) | ||
| 859 | ) | ||
| 860 | ) | ||
| 642 | 861 | ||
| 643 | ;;; gud.el ends here | 862 | ;;; gud.el ends here |