gud.el 61.4 KB
Newer Older
1
;;; gud.el --- Grand Unified Debugger mode for gdb, dbx, etc. under Emacs
Eric S. Raymond's avatar
Eric S. Raymond committed
2

3
;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
Richard M. Stallman's avatar
Richard M. Stallman committed
4
;; Maintainer: FSF
Eric S. Raymond's avatar
Eric S. Raymond committed
5 6
;; Keywords: unix, tools

Karl Heuer's avatar
Karl Heuer committed
7
;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
8 9 10 11 12

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Eric S. Raymond's avatar
Eric S. Raymond committed
13
;; the Free Software Foundation; either version 2, or (at your option)
Eric S. Raymond's avatar
Eric S. Raymond committed
14 15 16 17 18 19 20 21
;; any later version.

;; GNU Emacs 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
Erik Naggum's avatar
Erik Naggum committed
22 23 24
;; 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.
Eric S. Raymond's avatar
Eric S. Raymond committed
25

Eric S. Raymond's avatar
Eric S. Raymond committed
26 27
;;; Commentary:

Eric S. Raymond's avatar
Eric S. Raymond committed
28
;; The ancestral gdb.el was by W. Schelter <wfs@rascal.ics.utexas.edu>
Eric S. Raymond's avatar
Eric S. Raymond committed
29
;; It was later rewritten by rms.  Some ideas were due to Masanobu. 
Eric S. Raymond's avatar
Eric S. Raymond committed
30
;; Grand Unification (sdb/dbx support) by Eric S. Raymond <esr@thyrsus.com>
Eric S. Raymond's avatar
Eric S. Raymond committed
31
;; The overloading code was then rewritten by Barry Warsaw <bwarsaw@cen.com>,
32
;; who also hacked the mode to use comint.el.  Shane Hartman <shane@spr.com>
33
;; added support for xdb (HPUX debugger).  Rick Sladkey <jrs@world.std.com>
34
;; wrote the GDB command completion code.  Dave Love <d.love@dl.ac.uk>
35
;; added the IRIX kluge, re-implemented the Mips-ish variant and added
36 37
;; a menu. Brian D. Carlstrom <bdc@ai.mit.edu> combined the IRIX kluge with 
;; the gud-xdb-directories hack producing gud-dbx-directories.
Eric S. Raymond's avatar
Eric S. Raymond committed
38

Eric S. Raymond's avatar
Eric S. Raymond committed
39 40
;;; Code:

Eric S. Raymond's avatar
Eric S. Raymond committed
41
(require 'comint)
Jim Blandy's avatar
Jim Blandy committed
42
(require 'etags)
Eric S. Raymond's avatar
Eric S. Raymond committed
43

44
;; ======================================================================
45
;; GUD commands must be visible in C buffers visited by GUD
46

47
(defvar gud-key-prefix "\C-x\C-a"
48
  "Prefix of all GUD commands valid in C buffers.")
49

50
(global-set-key (concat gud-key-prefix "\C-l") 'gud-refresh)
51
(define-key ctl-x-map " " 'gud-break)	;; backward compatibility hack
52

53 54 55 56 57 58 59 60 61 62 63 64 65
(defvar gud-marker-filter nil)
(put 'gud-marker-filter 'permanent-local t)
(defvar gud-find-file nil)
(put 'gud-find-file 'permanent-local t)

(defun gud-marker-filter (&rest args)
  (apply gud-marker-filter args))

(defun gud-find-file (file)
  ;; Don't get confused by double slashes in the name that comes from GDB.
  (while (string-match "//+" file)
    (setq file (replace-match "/" t t file)))
  (funcall gud-find-file file))
66 67 68 69 70 71

;; Keymap definitions for menu bar entries common to all debuggers and
;; slots for debugger-dependent ones in sensible places.  (Defined here
;; before use.)
(defvar gud-menu-map (make-sparse-keymap "Gud") nil)
(define-key gud-menu-map [refresh] '("Refresh" . gud-refresh))
Karl Heuer's avatar
Karl Heuer committed
72
(define-key gud-menu-map [remove] '("Remove Breakpoint" . gud-remove))
73
(define-key gud-menu-map [tbreak] nil)	; gdb, sdb and xdb
Karl Heuer's avatar
Karl Heuer committed
74
(define-key gud-menu-map [break] '("Set Breakpoint" . gud-break))
75 76
(define-key gud-menu-map [up] nil)	; gdb, dbx, and xdb
(define-key gud-menu-map [down] nil)	; gdb, dbx, and xdb
Karl Heuer's avatar
Karl Heuer committed
77
(define-key gud-menu-map [print] '("Print Expression" . gud-print))
78
(define-key gud-menu-map [finish] nil)	; gdb or xdb
Karl Heuer's avatar
Karl Heuer committed
79 80 81
(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))
82
(define-key gud-menu-map [cont] '("Continue" . gud-cont))
83

84 85
;; ======================================================================
;; command definition
Eric S. Raymond's avatar
Eric S. Raymond committed
86 87

;; This macro is used below to define some basic debugger interface commands.
Eric S. Raymond's avatar
Eric S. Raymond committed
88
;; Of course you may use `gud-def' with any other debugger command, including
Jim Blandy's avatar
Jim Blandy committed
89 90 91 92
;; user defined ones.

;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form
;; which defines FUNC to send the command NAME to the debugger, gives
93
;; it the docstring DOC, and binds that function to KEY in the GUD
94 95
;; major mode.  The function is also bound in the global keymap with the
;; GUD prefix.
96 97 98 99 100 101

(defmacro gud-def (func cmd key &optional doc)
  "Define FUNC to be a command sending STR and bound to KEY, with
optional doc string DOC.  Certain %-escapes in the string arguments
are interpreted specially if present.  These are:

102 103
  %f	name (without directory) of current source file. 
  %d	directory of current source file. 
104 105 106 107 108
  %l	number of current source line
  %e	text of the C lvalue or function-call expression surrounding point.
  %a	text of the hexadecimal address surrounding point
  %p	prefix argument to the command (if any) as a number

109 110 111 112 113 114
  The `current' source file is the file of the current buffer (if
we're in a C file) or the source file current at the last break or
step (if we're in the GUD buffer).
  The `current' line is that of the current buffer (if we're in a
source file) or the source line number at the last break or step (if
we're in the GUD buffer)."
115 116 117 118 119 120
  (list 'progn
	(list 'defun func '(arg)
	      (or doc "")
	      '(interactive "p")
	      (list 'gud-call cmd 'arg))
	(if key
121 122 123 124 125 126
	    (list 'define-key
		  '(current-local-map)
		  (concat "\C-c" key)
		  (list 'quote func)))
	(if key
	    (list 'global-set-key
127
		  (list 'concat 'gud-key-prefix key)
128
		  (list 'quote func)))))
Eric S. Raymond's avatar
Eric S. Raymond committed
129

130 131
;; Where gud-display-frame should put the debugging arrow.  This is
;; set by the marker-filter, which scans the debugger's output for
132
;; indications of the current program counter.
133 134
(defvar gud-last-frame nil)

135 136 137
;; Used by gud-refresh, which should cause gud-display-frame to redisplay
;; the last frame, even if it's been called before and gud-last-frame has
;; been set to nil.
138
(defvar gud-last-last-frame nil)
139

140 141
;; All debugger-specific information is collected here.
;; Here's how it works, in case you ever need to add a debugger to the mode.
Eric S. Raymond's avatar
Eric S. Raymond committed
142 143 144 145 146
;;
;; Each entry must define the following at startup:
;;
;;<name>
;; comint-prompt-regexp
147
;; gud-<name>-massage-args
Eric S. Raymond's avatar
Eric S. Raymond committed
148
;; gud-<name>-marker-filter
149
;; gud-<name>-find-file
Eric S. Raymond's avatar
Eric S. Raymond committed
150
;;
151 152
;; The job of the massage-args method is to modify the given list of
;; debugger arguments before running the debugger.
Jim Blandy's avatar
Jim Blandy committed
153 154 155 156
;;
;; The job of the marker-filter method is to detect file/line markers in
;; strings and set the global gud-last-frame to indicate what display
;; action (if any) should be triggered by the marker.  Note that only
157
;; whatever the method *returns* is displayed in the buffer; thus, you
Jim Blandy's avatar
Jim Blandy committed
158 159 160
;; can filter the debugger's output, interpreting some and passing on
;; the rest.
;;
161
;; The job of the find-file method is to visit and return the buffer indicated
Jim Blandy's avatar
Jim Blandy committed
162
;; by the car of gud-tag-frame.  This may be a file name, a tag name, or
163
;; something else.  It would be good if it also copied the Gud menubar entry.
164

Eric S. Raymond's avatar
Eric S. Raymond committed
165 166 167
;; ======================================================================
;; gdb functions

168 169 170
;;; History of argument lists passed to gdb.
(defvar gud-gdb-history nil)

171
(defun gud-gdb-massage-args (file args)
172
  (cons "-fullname" args))
Eric S. Raymond's avatar
Eric S. Raymond committed
173

174 175 176 177
(defvar gud-gdb-marker-regexp
  (concat "\032\032\\([^" path-separator "\n]*\\)" path-separator
	  "\\([0-9]*\\)" path-separator ".*\n"))

178 179 180 181 182 183
;; There's no guarantee that Emacs will hand the filter the entire
;; marker at once; it could be broken up across several strings.  We
;; might even receive a big chunk with several markers in it.  If we
;; receive a chunk of text which looks like it might contain the
;; beginning of a marker, we save it here between calls to the
;; filter.
184
(defvar gud-marker-acc "")
185
(make-variable-buffer-local 'gud-marker-acc)
186

187
(defun gud-gdb-marker-filter (string)
188 189 190 191
  (setq gud-marker-acc (concat gud-marker-acc string))
  (let ((output ""))

    ;; Process all the complete markers in this chunk.
192
    (while (string-match gud-gdb-marker-regexp gud-marker-acc)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
      (setq

       ;; Extract the frame position from the marker.
       gud-last-frame
       (cons (substring gud-marker-acc (match-beginning 1) (match-end 1))
	     (string-to-int (substring gud-marker-acc
				       (match-beginning 2)
				       (match-end 2))))

       ;; Append any text before the marker to the output we're going
       ;; to return - we don't include the marker in this text.
       output (concat output
		      (substring gud-marker-acc 0 (match-beginning 0)))

       ;; Set the accumulator to the remaining text.
       gud-marker-acc (substring gud-marker-acc (match-end 0))))

    ;; Does the remaining text look like it might end with the
    ;; beginning of another marker?  If it does, then keep it in
    ;; gud-marker-acc until we receive the rest of it.  Since we
    ;; know the full marker regexp above failed, it's pretty simple to
    ;; test for marker starts.
    (if (string-match "\032.*\\'" gud-marker-acc)
	(progn
	  ;; Everything before the potential marker start can be output.
	  (setq output (concat output (substring gud-marker-acc
						 0 (match-beginning 0))))

	  ;; Everything after, we save, to combine with later input.
	  (setq gud-marker-acc
		(substring gud-marker-acc (match-beginning 0))))

      (setq output (concat output gud-marker-acc)
	    gud-marker-acc ""))

    output))
Eric S. Raymond's avatar
Eric S. Raymond committed
229

230
(defun gud-gdb-find-file (f)
231 232 233
  (save-excursion
    (let ((buf (find-file-noselect f)))
      (set-buffer buf)
234
      (gud-make-debug-menu)
235
      (local-set-key [menu-bar debug tbreak]
Karl Heuer's avatar
Karl Heuer committed
236 237 238 239
		     '("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))
240
      buf)))
Eric S. Raymond's avatar
Eric S. Raymond committed
241

242 243 244 245 246 247 248 249
(defvar gdb-minibuffer-local-map nil
  "Keymap for minibuffer prompting of gdb startup command.")
(if gdb-minibuffer-local-map
    ()
  (setq gdb-minibuffer-local-map (copy-keymap minibuffer-local-map))
  (define-key
    gdb-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename))

Jim Blandy's avatar
Jim Blandy committed
250
;;;###autoload
251
(defun gdb (command-line)
Eric S. Raymond's avatar
Eric S. Raymond committed
252 253 254
  "Run gdb on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
255
  (interactive
256 257 258 259 260 261
   (list (read-from-minibuffer "Run gdb (like this): "
			       (if (consp gud-gdb-history)
				   (car gud-gdb-history)
				 "gdb ")
			       gdb-minibuffer-local-map nil
			       '(gud-gdb-history . 1))))
262

263 264
  (gud-common-init command-line 'gud-gdb-massage-args
		   'gud-gdb-marker-filter 'gud-gdb-find-file)
265

266
  (gud-def gud-break  "break %f:%l"  "\C-b" "Set breakpoint at current line.")
267
  (gud-def gud-tbreak "tbreak %f:%l" "\C-t" "Set temporary breakpoint at current line.")
268
  (gud-def gud-remove "clear %f:%l"  "\C-d" "Remove breakpoint at current line")
269 270 271 272 273
  (gud-def gud-step   "step %p"      "\C-s" "Step one source line with display.")
  (gud-def gud-stepi  "stepi %p"     "\C-i" "Step one instruction with display.")
  (gud-def gud-next   "next %p"      "\C-n" "Step one line (skip functions).")
  (gud-def gud-cont   "cont"         "\C-r" "Continue with display.")
  (gud-def gud-finish "finish"       "\C-f" "Finish executing current function.")
274 275
  (gud-def gud-up     "up %p"        "<" "Up N stack frames (numeric arg).")
  (gud-def gud-down   "down %p"      ">" "Down N stack frames (numeric arg).")
276
  (gud-def gud-print  "print %e"     "\C-p" "Evaluate C expression at point.")
277

278
  (local-set-key "\C-i" 'gud-gdb-complete-command)
Karl Heuer's avatar
Karl Heuer committed
279 280 281 282
  (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))
Eric S. Raymond's avatar
Eric S. Raymond committed
283
  (setq comint-prompt-regexp "^(.*gdb[+]?) *")
284
  (setq paragraph-start comint-prompt-regexp)
Eric S. Raymond's avatar
Eric S. Raymond committed
285 286 287
  (run-hooks 'gdb-mode-hook)
  )

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
;; One of the nice features of GDB is its impressive support for
;; context-sensitive command completion.  We preserve that feature
;; in the GUD buffer by using a GDB command designed just for Emacs.

;; The completion process filter indicates when it is finished.
(defvar gud-gdb-complete-in-progress)

;; Since output may arrive in fragments we accumulate partials strings here.
(defvar gud-gdb-complete-string)

;; We need to know how much of the completion to chop off.
(defvar gud-gdb-complete-break)

;; The completion list is constructed by the process filter.
(defvar gud-gdb-complete-list)

304 305
(defvar gud-comint-buffer nil)

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
(defun gud-gdb-complete-command ()
  "Perform completion on the GDB command preceding point.
This is implemented using the GDB `complete' command which isn't
available with older versions of GDB."
  (interactive)
  (let* ((end (point))
	 (command (save-excursion
		    (beginning-of-line)
		    (and (looking-at comint-prompt-regexp)
			 (goto-char (match-end 0)))
		    (buffer-substring (point) end)))
	 command-word)
    ;; Find the word break.  This match will always succeed.
    (string-match "\\(\\`\\| \\)\\([^ ]*\\)\\'" command)
    (setq gud-gdb-complete-break (match-beginning 2)
	  command-word (substring command gud-gdb-complete-break))
322 323 324 325 326 327 328 329 330 331
    ;; Temporarily install our filter function.
    (let ((gud-marker-filter 'gud-gdb-complete-filter))
      ;; Issue the command to GDB.
      (gud-basic-call (concat "complete " command))
      (setq gud-gdb-complete-in-progress t
	    gud-gdb-complete-string nil
	    gud-gdb-complete-list nil)
      ;; Slurp the output.
      (while gud-gdb-complete-in-progress
	(accept-process-output (get-buffer-process gud-comint-buffer))))
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    ;; Protect against old versions of GDB.
    (and gud-gdb-complete-list
	 (string-match "^Undefined command: \"complete\""
		       (car gud-gdb-complete-list))
	 (error "This version of GDB doesn't support the `complete' command."))
    ;; Sort the list like readline.
    (setq gud-gdb-complete-list
	  (sort gud-gdb-complete-list (function string-lessp)))
    ;; Remove duplicates.
    (let ((first gud-gdb-complete-list)
	  (second (cdr gud-gdb-complete-list)))
      (while second
	(if (string-equal (car first) (car second))
	    (setcdr first (setq second (cdr second)))
	  (setq first second
		second (cdr second)))))
348 349 350 351 352 353 354 355 356 357 358
    ;; Add a trailing single quote if there is a unique completion
    ;; and it contains an odd number of unquoted single quotes.
    (and (= (length gud-gdb-complete-list) 1)
	 (let ((str (car gud-gdb-complete-list))
	       (pos 0)
	       (count 0))
	   (while (string-match "\\([^'\\]\\|\\\\'\\)*'" str pos)
	     (setq count (1+ count)
		   pos (match-end 0)))
	   (and (= (mod count 2) 1)
		(setq gud-gdb-complete-list (list (concat str "'"))))))
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    ;; Let comint handle the rest.
    (comint-dynamic-simple-complete command-word gud-gdb-complete-list)))
    
;; The completion process filter is installed temporarily to slurp the
;; output of GDB up to the next prompt and build the completion list.
(defun gud-gdb-complete-filter (string)
  (setq string (concat gud-gdb-complete-string string))
  (while (string-match "\n" string)
    (setq gud-gdb-complete-list
	  (cons (substring string gud-gdb-complete-break (match-beginning 0))
		gud-gdb-complete-list))
    (setq string (substring string (match-end 0))))
  (if (string-match comint-prompt-regexp string)
      (progn
	(setq gud-gdb-complete-in-progress nil)
	string)
    (progn
      (setq gud-gdb-complete-string string)
      "")))

379

Eric S. Raymond's avatar
Eric S. Raymond committed
380 381 382
;; ======================================================================
;; sdb functions

383 384 385
;;; History of argument lists passed to sdb.
(defvar gud-sdb-history nil)

386 387 388 389 390
(defvar gud-sdb-needs-tags (not (file-exists-p "/var"))
  "If nil, we're on a System V Release 4 and don't need the tags hack.")

(defvar gud-sdb-lastfile nil)

391
(defun gud-sdb-massage-args (file args) args)
Eric S. Raymond's avatar
Eric S. Raymond committed
392

393
(defun gud-sdb-marker-filter (string)
394 395 396 397 398 399 400
  (setq gud-marker-acc
	(if gud-marker-acc (concat gud-marker-acc string) string))
  (let (start)
    ;; Process all complete markers in this chunk
    (while 
	(cond 
	 ;; System V Release 3.2 uses this format
401
	 ((string-match "\\(^\\|\n\\)\\*?\\(0x\\w* in \\)?\\([^:\n]*\\):\\([0-9]*\\):.*\n"
402 403 404
			gud-marker-acc start)
	  (setq gud-last-frame
		(cons
405
		 (substring gud-marker-acc (match-beginning 3) (match-end 3))
406
		 (string-to-int 
407
		  (substring gud-marker-acc (match-beginning 4) (match-end 4))))))
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
	 ;; 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 gud-sdb-lastfile
		(substring gud-marker-acc (match-beginning 2) (match-end 2)))
	  (setq gud-last-frame
		(cons
		 gud-sdb-lastfile
		 (string-to-int 
		  (substring gud-marker-acc (match-beginning 3) (match-end 3))))))
	 ;; System V Release 4.0 
	 ((string-match "^\\(BREAKPOINT\\|STEPPED\\) process [0-9]+ function [^ ]+ in \\(.+\\)\n"
			gud-marker-acc start)
	  (setq gud-sdb-lastfile
		(substring gud-marker-acc (match-beginning 2) (match-end 2))))
	 ((and gud-sdb-lastfile (string-match "^\\([0-9]+\\):"
					      gud-marker-acc start))
	       (setq gud-last-frame
		     (cons
		      gud-sdb-lastfile
		      (string-to-int 
		       (substring gud-marker-acc (match-beginning 1) (match-end 1))))))
	 (t 
	  (setq gud-sdb-lastfile nil)))
      (setq start (match-end 0)))

    ;; Search for the last incomplete line in this chunk
    (while (string-match "\n" gud-marker-acc start)
      (setq start (match-end 0)))

    ;; If we have an incomplete line, store it in gud-marker-acc.
439
    (setq gud-marker-acc (substring gud-marker-acc (or start 0))))
Eric S. Raymond's avatar
Eric S. Raymond committed
440 441
  string)

442
(defun gud-sdb-find-file (f)
443 444 445 446 447
  (save-excursion
    (let ((buf (if gud-sdb-needs-tags
		   (find-tag-noselect f)
		 (find-file-noselect f))))
      (set-buffer buf)
448
      (gud-make-debug-menu)
Karl Heuer's avatar
Karl Heuer committed
449
      (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
450
      buf)))
Eric S. Raymond's avatar
Eric S. Raymond committed
451

Jim Blandy's avatar
Jim Blandy committed
452
;;;###autoload
453
(defun sdb (command-line)
Eric S. Raymond's avatar
Eric S. Raymond committed
454 455 456
  "Run sdb on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
457
  (interactive
458
   (list (read-from-minibuffer "Run sdb (like this): "
459 460
			       (if (consp gud-sdb-history)
				   (car gud-sdb-history)
461
				 "sdb ")
462 463
			       nil nil
			       '(gud-sdb-history . 1))))
464
  (if (and gud-sdb-needs-tags
465 466 467
	   (not (and (boundp 'tags-file-name)
		     (stringp tags-file-name)
		     (file-exists-p tags-file-name))))
Eric S. Raymond's avatar
Eric S. Raymond committed
468 469
      (error "The sdb support requires a valid tags table to work."))

470 471
  (gud-common-init command-line 'gud-sdb-massage-args
		   'gud-sdb-marker-filter 'gud-sdb-find-file)
472

473 474 475 476 477 478 479 480
  (gud-def gud-break  "%l b" "\C-b"   "Set breakpoint at current line.")
  (gud-def gud-tbreak "%l c" "\C-t"   "Set temporary breakpoint at current line.")
  (gud-def gud-remove "%l d" "\C-d"   "Remove breakpoint at current line")
  (gud-def gud-step   "s %p" "\C-s"   "Step one source line with display.")
  (gud-def gud-stepi  "i %p" "\C-i"   "Step one instruction with display.")
  (gud-def gud-next   "S %p" "\C-n"   "Step one line (skip functions).")
  (gud-def gud-cont   "c"    "\C-r"   "Continue with display.")
  (gud-def gud-print  "%e/"  "\C-p"   "Evaluate C expression at point.")
Eric S. Raymond's avatar
Eric S. Raymond committed
481

Jim Blandy's avatar
Jim Blandy committed
482
  (setq comint-prompt-regexp  "\\(^\\|\n\\)\\*")
483
  (setq paragraph-start comint-prompt-regexp)
484
  (local-set-key [menu-bar debug tbreak]
Karl Heuer's avatar
Karl Heuer committed
485
    '("Temporary Breakpoint" . gud-tbreak))
Eric S. Raymond's avatar
Eric S. Raymond committed
486 487
  (run-hooks 'sdb-mode-hook)
  )
488

Eric S. Raymond's avatar
Eric S. Raymond committed
489 490 491
;; ======================================================================
;; dbx functions

492 493 494
;;; History of argument lists passed to dbx.
(defvar gud-dbx-history nil)

495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
(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))
Eric S. Raymond's avatar
Eric S. Raymond committed
525

526
(defun gud-dbx-marker-filter (string)
527 528 529 530 531 532 533 534 535 536
  (setq gud-marker-acc (if gud-marker-acc (concat gud-marker-acc string) string))

  (let (start)
    ;; Process all complete markers in this chunk.
    (while (or (string-match
		"stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\""
		gud-marker-acc start)
	       (string-match
		"signal .* in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\""
		gud-marker-acc start))
Eric S. Raymond's avatar
Eric S. Raymond committed
537 538
      (setq gud-last-frame
	    (cons
539
	     (substring gud-marker-acc (match-beginning 2) (match-end 2))
Eric S. Raymond's avatar
Eric S. Raymond committed
540
	     (string-to-int 
541 542 543 544 545 546 547 548 549 550 551 552 553 554
	      (substring gud-marker-acc (match-beginning 1) (match-end 1))))
	    start (match-end 0)))

    ;; Search for the last incomplete line in this chunk
    (while (string-match "\n" gud-marker-acc start)
      (setq start (match-end 0)))

    ;; If the incomplete line APPEARS to begin with another marker, keep it
    ;; in the accumulator.  Otherwise, clear the accumulator to avoid an
    ;; unnecessary concat during the next call.
    (setq gud-marker-acc 
	  (if (string-match "\\(stopped\\|signal\\)" gud-marker-acc start)
	      (substring gud-marker-acc (match-beginning 0))
	    nil)))
Eric S. Raymond's avatar
Eric S. Raymond committed
555 556
  string)

557 558 559 560 561 562 563
;; Functions for Mips-style dbx.  Given the option `-emacs', documented in
;; OSF1, not necessarily elsewhere, it produces markers similar to gdb's.
(defvar gud-mips-p
  (or (string-match "^mips-[^-]*-ultrix" system-configuration)
      ;; We haven't tested gud on this system:
      (string-match "^mips-[^-]*-riscos" system-configuration)
      ;; It's documented on OSF/1.3
564 565
      (string-match "^mips-[^-]*-osf1" system-configuration)
      (string-match "^alpha-[^-]*-osf" system-configuration))
566
  "Non-nil to assume the MIPS/OSF dbx conventions (argument `-emacs').")
567 568

(defun gud-mipsdbx-massage-args (file args)
569
  (cons "-emacs" args))
570

571 572
;; This is just like the gdb one except for the regexps since we need to cope
;; with an optional breakpoint number in [] before the ^Z^Z
573
(defun gud-mipsdbx-marker-filter (string)
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
  (setq gud-marker-acc (concat gud-marker-acc string))
  (let ((output ""))

    ;; Process all the complete markers in this chunk.
    (while (string-match
	    ;; This is like th gdb marker but with an optional
	    ;; leading break point number like `[1] '
	    "[][ 0-9]*\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n"
	    gud-marker-acc)
      (setq

       ;; Extract the frame position from the marker.
       gud-last-frame
       (cons (substring gud-marker-acc (match-beginning 1) (match-end 1))
	     (string-to-int (substring gud-marker-acc
				       (match-beginning 2)
				       (match-end 2))))

       ;; Append any text before the marker to the output we're going
       ;; to return - we don't include the marker in this text.
       output (concat output
		      (substring gud-marker-acc 0 (match-beginning 0)))

       ;; Set the accumulator to the remaining text.
       gud-marker-acc (substring gud-marker-acc (match-end 0))))

    ;; Does the remaining text look like it might end with the
    ;; beginning of another marker?  If it does, then keep it in
    ;; gud-marker-acc until we receive the rest of it.  Since we
    ;; know the full marker regexp above failed, it's pretty simple to
    ;; test for marker starts.
    (if (string-match "[][ 0-9]*\032.*\\'" gud-marker-acc)
	(progn
	  ;; Everything before the potential marker start can be output.
	  (setq output (concat output (substring gud-marker-acc
						 0 (match-beginning 0))))

	  ;; Everything after, we save, to combine with later input.
	  (setq gud-marker-acc
		(substring gud-marker-acc (match-beginning 0))))

      (setq output (concat output gud-marker-acc)
	    gud-marker-acc ""))

    output))
619

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
;; The dbx in IRIX is a pain.  It doesn't print the file name when
;; stopping at a breakpoint (but you do get it from the `up' and
;; `down' commands...).  The only way to extract the information seems
;; to be with a `file' command, although the current line number is
;; available in $curline.  Thus we have to look for output which
;; appears to indicate a breakpoint.  Then we prod the dbx sub-process
;; to output the information we want with a combination of the
;; `printf' and `file' commands as a pseudo marker which we can
;; recognise next time through the marker-filter.  This would be like
;; the gdb marker but you can't get the file name without a newline...
;; Note that gud-remove won't work since Irix dbx expects a breakpoint
;; number rather than a line number etc.  Maybe this could be made to
;; work by listing all the breakpoints and picking the one(s) with the
;; correct line number, but life's too short.
;;   d.love@dl.ac.uk (Dave Love) can be blamed for this

Karl Heuer's avatar
Karl Heuer committed
636 637 638
(defvar gud-irix-p
  (and (string-match "^mips-[^-]*-irix" system-configuration)
       (not (string-match "irix[6-9]\\.[1-9]" system-configuration)))
639
  "Non-nil to assume the interface appropriate for IRIX dbx.
Karl Heuer's avatar
Karl Heuer committed
640 641 642 643 644 645 646
This works in IRIX 4, 5 and 6, but `gud-dbx-use-stopformat-p' provides
a better solution in 6.1 upwards.")
(defvar gud-dbx-use-stopformat-p
  (string-match "irix[6-9]\\.[1-9]" system-configuration)
  "Non-nil to use the dbx feature present at least from Irix 6.1
  whereby $stopformat=1 produces an output format compatiable with
  `gud-dbx-marker-filter'.")
647 648 649 650 651 652
;; [Irix dbx seems to be a moving target.  The dbx output changed
;; subtly sometime between OS v4.0.5 and v5.2 so that, for instance,
;; the output from `up' is no longer spotted by gud (and it's probably
;; not distinctive enough to try to match it -- use C-<, C->
;; exclusively) .  For 5.3 and 6.0, the $curline variable changed to
;; `long long'(why?!), so the printf stuff needed changing.  The line
Karl Heuer's avatar
Karl Heuer committed
653 654 655 656 657 658 659 660
;; number was cast to `long' as a compromise between the new `long
;; long' and the original `int'.  This is reported not to work in 6.2,
;; so it's changed back to int -- don't make your sources too long.
;; From Irix6.1 (but not 6.0?) dbx supports an undocumented feature
;; whereby `set $stopformat=1' reportedly produces output compatible
;; with `gud-dbx-marker-filter', which we prefer.

;; The process filter is also somewhat
661 662 663 664 665
;; unreliable, sometimes not spotting the markers; I don't know
;; whether there's anything that can be done about that.  It would be
;; much better if SGI could be persuaded to (re?)instate the MIPS
;; -emacs flag for gdb-like output (which ought to be possible as most
;; of the communication I've had over it has been from sgi.com).]
666 667 668

;; this filter is influenced by the xdb one rather than the gdb one
(defun gud-irixdbx-marker-filter (string)
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
  (let (result (case-fold-search nil))
    (if (or (string-match comint-prompt-regexp string)
	    (string-match ".*\012" string))
	(setq result (concat gud-marker-acc string)
	      gud-marker-acc "")
      (setq gud-marker-acc (concat gud-marker-acc string)))
    (if result
	(cond
	 ;; look for breakpoint or signal indication e.g.:
	 ;; [2] Process  1267 (pplot) stopped at [params:338 ,0x400ec0]
	 ;; Process  1281 (pplot) stopped at [params:339 ,0x400ec8]
	 ;; Process  1270 (pplot) Floating point exception [._read._read:16 ,0x452188]
	 ((string-match
	   "^\\(\\[[0-9]+] \\)?Process +[0-9]+ ([^)]*) [^[]+\\[[^]\n]*]\n" 
	   result)
	  ;; prod dbx into printing out the line number and file
	  ;; name in a form we can grok as below
	  (process-send-string (get-buffer-process gud-comint-buffer)
Karl Heuer's avatar
Karl Heuer committed
687
			       "printf \"\032\032%1d:\",(int)$curline;file\n"))
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
	 ;; look for result of, say, "up" e.g.:
	 ;; .pplot.pplot(0x800) ["src/pplot.f":261, 0x400c7c]
	 ;; (this will also catch one of the lines printed by "where")
	 ((string-match
	   "^[^ ][^[]*\\[\"\\([^\"]+\\)\":\\([0-9]+\\), [^]]+]\n"
	   result)
	  (let ((file (substring result (match-beginning 1)
				 (match-end 1))))
	    (if (file-exists-p file)
		(setq gud-last-frame
		      (cons
		       (substring
			result (match-beginning 1) (match-end 1))
		       (string-to-int 
			(substring
			 result (match-beginning 2) (match-end 2)))))))
	  result)
	 ((string-match			; kluged-up marker as above
	   "\032\032\\([0-9]*\\):\\(.*\\)\n" result)
707 708 709
	  (let ((file (gud-dbx-file-name
		       (substring result (match-beginning 2) (match-end 2)))))
	    (if (and file (file-exists-p file))
710 711 712 713 714 715 716 717
		(setq gud-last-frame
		      (cons
		       file
		       (string-to-int 
			(substring
			 result (match-beginning 1) (match-end 1)))))))
	  (setq result (substring result 0 (match-beginning 0))))))
    (or result "")))
718

719
(defun gud-dbx-find-file (f)
720
  (save-excursion
721 722
    (let ((realf (gud-dbx-file-name f)))
      (if realf
723
	  (let ((buf (find-file-noselect realf)))
724 725 726 727 728 729
	    (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))))
Eric S. Raymond's avatar
Eric S. Raymond committed
730

Jim Blandy's avatar
Jim Blandy committed
731
;;;###autoload
732
(defun dbx (command-line)
Eric S. Raymond's avatar
Eric S. Raymond committed
733 734 735
  "Run dbx on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
736
  (interactive
737
   (list (read-from-minibuffer "Run dbx (like this): "
738 739
			       (if (consp gud-dbx-history)
				   (car gud-dbx-history)
740
				 "dbx ")
741 742
			       nil nil
			       '(gud-dbx-history . 1))))
743

744 745 746 747 748 749 750 751 752 753
  (cond
   (gud-mips-p
    (gud-common-init command-line 'gud-mipsdbx-massage-args
		     'gud-mipsdbx-marker-filter 'gud-dbx-find-file))
   (gud-irix-p
    (gud-common-init command-line 'gud-dbx-massage-args
		     'gud-irixdbx-marker-filter 'gud-dbx-find-file))
   (t
    (gud-common-init command-line 'gud-dbx-massage-args
		     'gud-dbx-marker-filter 'gud-dbx-find-file)))
754

755
  (cond
756
   (gud-mips-p
757 758
    (gud-def gud-up     "up %p"         "<" "Up (numeric arg) stack frames.")
    (gud-def gud-down   "down %p" ">" "Down (numeric arg) stack frames.")
759 760 761
    (gud-def gud-break "stop at \"%f\":%l"
				  "\C-b" "Set breakpoint at current line.")
    (gud-def gud-finish "return"  "\C-f" "Finish executing current function."))
762 763 764 765
   (gud-irix-p
    (gud-def gud-break "stop at \"%d%f\":%l"
				  "\C-b" "Set breakpoint at current line.")
    (gud-def gud-finish "return"  "\C-f" "Finish executing current function.")
Karl Heuer's avatar
Karl Heuer committed
766
    (gud-def gud-up     "up %p; printf \"\032\032%1d:\",(int)$curline;file\n"
767
	     "<" "Up (numeric arg) stack frames.")
Karl Heuer's avatar
Karl Heuer committed
768
    (gud-def gud-down "down %p; printf \"\032\032%1d:\",(int)$curline;file\n"
769
	     ">" "Down (numeric arg) stack frames.")
770 771
    ;; Make dbx give out the source location info that we need.
    (process-send-string (get-buffer-process gud-comint-buffer)
Karl Heuer's avatar
Karl Heuer committed
772 773 774 775
			 "printf \"\032\032%1d:\",(int)$curline;file\n"))
   (gud-dbx-use-stopformat-p
    (process-send-string (get-buffer-process gud-comint-buffer) 
			 "set $stopformat=1\n"))
776
   (t
777 778
    (gud-def gud-up     "up %p"         "<" "Up (numeric arg) stack frames.")
    (gud-def gud-down   "down %p" ">" "Down (numeric arg) stack frames.")
779 780 781
    (gud-def gud-break "file \"%d%f\"\nstop at %l"
				  "\C-b" "Set breakpoint at current line.")))

782 783 784 785 786 787
  (gud-def gud-remove "clear %l"  "\C-d" "Remove breakpoint at current line")
  (gud-def gud-step   "step %p"	  "\C-s" "Step one line with display.")
  (gud-def gud-stepi  "stepi %p"  "\C-i" "Step one instruction with display.")
  (gud-def gud-next   "next %p"	  "\C-n" "Step one line (skip functions).")
  (gud-def gud-cont   "cont"	  "\C-r" "Continue with display.")
  (gud-def gud-print  "print %e"  "\C-p" "Evaluate C expression at point.")
788

789
  (setq comint-prompt-regexp  "^[^)\n]*dbx) *")
790
  (setq paragraph-start comint-prompt-regexp)
Karl Heuer's avatar
Karl Heuer committed
791 792
  (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
  (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
Eric S. Raymond's avatar
Eric S. Raymond committed
793 794
  (run-hooks 'dbx-mode-hook)
  )
795

796 797 798
;; ======================================================================
;; xdb (HP PARISC debugger) functions

799 800 801
;;; History of argument lists passed to xdb.
(defvar gud-xdb-history nil)

802 803 804 805 806 807 808 809
(defvar gud-xdb-directories nil
  "*A list of directories that xdb should search for source code.
If nil, only source files in the program directory
will be known to xdb.

The file names should be absolute, or relative to the directory
containing the executable being debugged.")

810 811 812 813 814 815
(defun gud-xdb-massage-args (file args)
  (nconc (let ((directories gud-xdb-directories)
	       (result nil))
	   (while directories
	     (setq result (cons (car directories) (cons "-d" result)))
	     (setq directories (cdr directories)))
816
	   (nreverse result))
817
	 args))
818 819 820 821 822 823

(defun gud-xdb-file-name (f)
  "Transform a relative pathname to a full pathname in xdb mode"
  (let ((result nil))
    (if (file-exists-p f)
        (setq result (expand-file-name f))
824 825 826
      (let ((directories gud-xdb-directories))
        (while directories
          (let ((path (concat (car directories) "/" f)))
827 828
            (if (file-exists-p path)
                (setq result (expand-file-name path)
829 830
                      directories nil)))
          (setq directories (cdr directories)))))
831 832 833 834 835 836 837
    result))

;; xdb does not print the lines all at once, so we have to accumulate them
(defun gud-xdb-marker-filter (string)
  (let (result)
    (if (or (string-match comint-prompt-regexp string)
            (string-match ".*\012" string))
838 839 840
        (setq result (concat gud-marker-acc string)
              gud-marker-acc "")
      (setq gud-marker-acc (concat gud-marker-acc string)))
841
    (if result
842 843
        (if (or (string-match "\\([^\n \t:]+\\): [^:]+: \\([0-9]+\\)[: ]"
			      result)
844 845
                (string-match "[^: \t]+:[ \t]+\\([^:]+\\): [^:]+: \\([0-9]+\\):"
                              result))
846
            (let ((line (string-to-int
847 848 849 850 851 852 853 854
                         (substring result (match-beginning 2) (match-end 2))))
                  (file (gud-xdb-file-name
                         (substring result (match-beginning 1) (match-end 1)))))
              (if file
                  (setq gud-last-frame (cons file line))))))
    (or result "")))    
               
(defun gud-xdb-find-file (f)
855 856 857 858 859
  (save-excursion
    (let ((realf (gud-xdb-file-name f)))
      (if realf
	  (let ((buf (find-file-noselect realf)))
	    (set-buffer buf)
860
	    (gud-make-debug-menu)
861
	    (local-set-key [menu-bar debug tbreak]
Karl Heuer's avatar
Karl Heuer committed
862
			   '("Temporary Breakpoint" . gud-tbreak))
863
	    (local-set-key [menu-bar debug finish]
Karl Heuer's avatar
Karl Heuer committed
864 865 866
			   '("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))
867 868
	    buf)
	nil))))
869 870

;;;###autoload
871
(defun xdb (command-line)
872 873 874 875
  "Run xdb on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger.

876
You can set the variable 'gud-xdb-directories' to a list of program source
877
directories if your program contains sources from more than one directory."
878
  (interactive
879
   (list (read-from-minibuffer "Run xdb (like this): "
880 881
			       (if (consp gud-xdb-history)
				   (car gud-xdb-history)
882
				 "xdb ")
883 884
			       nil nil
			       '(gud-xdb-history . 1))))
885

886 887
  (gud-common-init command-line 'gud-xdb-massage-args
		   'gud-xdb-marker-filter 'gud-xdb-find-file)
888 889 890 891 892 893 894 895 896 897 898 899 900 901

  (gud-def gud-break  "b %f:%l"    "\C-b" "Set breakpoint at current line.")
  (gud-def gud-tbreak "b %f:%l\\t" "\C-t"
           "Set temporary breakpoint at current line.")
  (gud-def gud-remove "db"         "\C-d" "Remove breakpoint at current line")
  (gud-def gud-step   "s %p"	   "\C-s" "Step one line with display.")
  (gud-def gud-next   "S %p"	   "\C-n" "Step one line (skip functions).")
  (gud-def gud-cont   "c"	   "\C-r" "Continue with display.")
  (gud-def gud-up     "up %p"	   "<"    "Up (numeric arg) stack frames.")
  (gud-def gud-down   "down %p"	   ">"    "Down (numeric arg) stack frames.")
  (gud-def gud-finish "bu\\t"      "\C-f" "Finish executing current function.")
  (gud-def gud-print  "p %e"       "\C-p" "Evaluate C expression at point.")

  (setq comint-prompt-regexp  "^>")
902
  (setq paragraph-start comint-prompt-regexp)
Karl Heuer's avatar
Karl Heuer committed
903 904 905 906
  (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))
907
  (run-hooks 'xdb-mode-hook))
908 909 910 911 912 913 914 915

;; ======================================================================
;; perldb functions

;;; History of argument lists passed to perldb.
(defvar gud-perldb-history nil)

(defun gud-perldb-massage-args (file args)
916 917 918 919 920 921 922
  (cond ((equal (car args) "-e") 
	 (cons "-d" 
	       (cons (car args) 
		     (cons (nth 1 args) 
			   (cons "--" (cons "-emacs" (cdr (cdr args))))))))
	(t
	 (cons "-d" (cons (car args) (cons "-emacs" (cdr args)))))))
923 924 925 926 927 928 929 930 931 932

;; There's no guarantee that Emacs will hand the filter the entire
;; marker at once; it could be broken up across several strings.  We
;; might even receive a big chunk with several markers in it.  If we
;; receive a chunk of text which looks like it might contain the
;; beginning of a marker, we save it here between calls to the
;; filter.
(defvar gud-perldb-marker-acc "")

(defun gud-perldb-marker-filter (string)
933 934 935 936
  (setq gud-marker-acc (concat gud-marker-acc string))
  (let ((output ""))

    ;; Process all the complete markers in this chunk.
937
    (while (string-match "\032\032\\(\\([a-zA-Z]:\\)?[^:\n]*\\):\\([0-9]*\\):.*\n"
938 939 940 941 942 943 944
			 gud-marker-acc)
      (setq

       ;; Extract the frame position from the marker.
       gud-last-frame
       (cons (substring gud-marker-acc (match-beginning 1) (match-end 1))
	     (string-to-int (substring gud-marker-acc
945 946
				       (match-beginning 3)
				       (match-end 3))))
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974

       ;; Append any text before the marker to the output we're going
       ;; to return - we don't include the marker in this text.
       output (concat output
		      (substring gud-marker-acc 0 (match-beginning 0)))

       ;; Set the accumulator to the remaining text.
       gud-marker-acc (substring gud-marker-acc (match-end 0))))

    ;; Does the remaining text look like it might end with the
    ;; beginning of another marker?  If it does, then keep it in
    ;; gud-marker-acc until we receive the rest of it.  Since we
    ;; know the full marker regexp above failed, it's pretty simple to
    ;; test for marker starts.
    (if (string-match "\032.*\\'" gud-marker-acc)
	(progn
	  ;; Everything before the potential marker start can be output.
	  (setq output (concat output (substring gud-marker-acc
						 0 (match-beginning 0))))

	  ;; Everything after, we save, to combine with later input.
	  (setq gud-marker-acc
		(substring gud-marker-acc (match-beginning 0))))

      (setq output (concat output gud-marker-acc)
	    gud-marker-acc ""))

    output))
975 976

(defun gud-perldb-find-file (f)
977 978 979
  (save-excursion
    (let ((buf (find-file-noselect f)))
      (set-buffer buf)
980
      (gud-make-debug-menu)
981
      buf)))
982

983 984 985
(defvar perldb-command-name "perl"
  "File name for executing Perl.")

986 987 988 989 990 991 992 993 994
;;;###autoload
(defun perldb (command-line)
  "Run perldb on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
  (interactive
   (list (read-from-minibuffer "Run perldb (like this): "
			       (if (consp gud-perldb-history)
				   (car gud-perldb-history)
995 996 997 998 999
				 (concat perldb-command-name
					 " "
					 (or (buffer-file-name)
					     "-e 0"))
					 " ")
1000 1001 1002
			       nil nil
			       '(gud-perldb-history . 1))))

1003 1004
  (gud-common-init command-line 'gud-perldb-massage-args
		   'gud-perldb-marker-filter 'gud-perldb-find-file)
1005

Richard M. Stallman's avatar
Richard M. Stallman committed
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
  (gud-def gud-break  "b %l"         "\C-b" "Set breakpoint at current line.")
  (gud-def gud-remove "d %l"         "\C-d" "Remove breakpoint at current line")
  (gud-def gud-step   "s"            "\C-s" "Step one source line with display.")
  (gud-def gud-next   "n"            "\C-n" "Step one line (skip functions).")
  (gud-def gud-cont   "c"            "\C-r" "Continue with display.")
;  (gud-def gud-finish "finish"       "\C-f" "Finish executing current function.")
;  (gud-def gud-up     "up %p"        "<" "Up N stack frames (numeric arg).")
;  (gud-def gud-down   "down %p"      ">" "Down N stack frames (numeric arg).")
  (gud-def gud-print  "%e"           "\C-p" "Evaluate perl expression at point.")

1016
  (setq comint-prompt-regexp "^  DB<+[0-9]+>+ ")
1017
  (setq paragraph-start comint-prompt-regexp)
Richard M. Stallman's avatar
Richard M. Stallman committed
1018
  (run-hooks 'perldb-mode-hook)
1019
  )
1020

Eric S. Raymond's avatar
Eric S. Raymond committed
1021 1022
;;
;; End of debugger-specific information
Jim Blandy's avatar
Jim Blandy committed
1023
;;
Eric S. Raymond's avatar
Eric S. Raymond committed
1024

1025

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
;;; When we send a command to the debugger via gud-call, it's annoying
;;; to see the command and the new prompt inserted into the debugger's
;;; buffer; we have other ways of knowing the command has completed.
;;;
;;; If the buffer looks like this:
;;; --------------------
;;; (gdb) set args foo bar
;;; (gdb) -!-
;;; --------------------
;;; (the -!- marks the location of point), and we type `C-x SPC' in a
;;; source file to set a breakpoint, we want the buffer to end up like
;;; this:
;;; --------------------
;;; (gdb) set args foo bar
;;; Breakpoint 1 at 0x92: file make-docfile.c, line 49.
;;; (gdb) -!-
;;; --------------------
;;; Essentially, the old prompt is deleted, and the command's output
;;; and the new prompt take its place.
;;;
;;; Not echoing the command is easy enough; you send it directly using
;;; process-send-string, and it never enters the buffer.  However,
;;; getting rid of the old prompt is trickier; you don't want to do it
;;; when you send the command, since that will result in an annoying
;;; flicker as the prompt is deleted, redisplay occurs while Emacs
;;; waits for a response from the debugger, and the new prompt is
;;; inserted.  Instead, we'll wait until we actually get some output
;;; from the subprocess before we delete the prompt.  If the command
;;; produced no output other than a new prompt, that prompt will most
;;; likely be in the first chunk of output received, so we will delete
;;; the prompt and then replace it with an identical one.  If the
;;; command produces output, the prompt is moving anyway, so the
;;; flicker won't be annoying.
;;;
;;; So - when we want to delete the prompt upon receipt of the next
;;; chunk of debugger output, we position gud-delete-prompt-marker at
;;; the start of the prompt; the process filter will notice this, and
;;; delete all text between it and the process output marker.  If
;;; gud-delete-prompt-marker points nowhere, we leave the current
;;; prompt alone.
(defvar gud-delete-prompt-marker nil)

Eric S. Raymond's avatar
Eric S. Raymond committed
1068 1069 1070

(defun gud-mode ()
  "Major mode for interacting with an inferior debugger process.
Eric S. Raymond's avatar
Eric S. Raymond committed
1071

1072
   You start it up with one of the commands M-x gdb, M-x sdb, M-x dbx,
Richard M. Stallman's avatar
Richard M. Stallman committed
1073 1074 1075
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.
Eric S. Raymond's avatar
Eric S. Raymond committed
1076

1077 1078 1079
After startup, the following commands are available in both the GUD
interaction buffer and any source buffer GUD visits due to a breakpoint stop
or step operation:
Eric S. Raymond's avatar
Eric S. Raymond committed
1080

1081 1082 1083 1084
\\[gud-break] sets a breakpoint at the current file and line.  In the
GUD buffer, the current file and line are those of the last breakpoint or
step.  In a source buffer, they are the buffer's file and current line.

1085 1086
\\[gud-remove] removes breakpoints on the current file and line.

1087
\\[gud-refresh] displays in the source window the last line referred to