(defgroup gud nil
"Grand Unified Debugger mode for gdb and other debuggers under Emacs.
-Supported debuggers include gdb, sdb, dbx, xdb, perldb, pdb (Python), and jdb."
+Supported debuggers include gdb, sdb, dbx, xdb, perldb, pdb (Python), jdb, and bash."
:group 'unix
:group 'tools)
([remove] menu-item "Remove Breakpoint" gud-remove
:enable (not gud-running))
([tbreak] menu-item "Temporary Breakpoint" gud-tbreak
- :enable (memq gud-minor-mode '(gdba gdb sdb xdb)))
+ :enable (memq gud-minor-mode '(gdba gdb sdb xdb bashdb)))
([break] menu-item "Set Breakpoint" gud-break
:enable (not gud-running))
([up] menu-item "Up Stack" gud-up
- :enable (and (not gud-running)
- (memq gud-minor-mode '(gdba gdb dbx xdb jdb))))
+ :enable (and (not gdb-running)
+ (memq gud-minor-mode
+ '(gdba gdb dbx xdb jdb bashdb))))
([down] menu-item "Down Stack" gud-down
- :enable (and (not gud-running)
- (memq gud-minor-mode '(gdba gdb dbx xdb jdb))))
+ :enable (and (not gdb-running)
+ (memq gud-minor-mode
+ '(gdba gdb dbx xdb jdb bashdb))))
([print] menu-item "Print Expression" gud-print
:enable (not gud-running))
([display] menu-item "Display Expression" gud-display
:enable (and (not gud-running)
(eq gud-minor-mode 'gdba)))
([finish] menu-item "Finish Function" gud-finish
- :enable (and (not gud-running)
- (memq gud-minor-mode '(gdba gdb xdb jdb))))
+ :enable (and (not gdb-running)
+ (memq gud-minor-mode
+ '(gdba gdb xdb jdb bashdb))))
([stepi] "Step Instruction" . gud-stepi)
([step] menu-item "Step Line" gud-step
:enable (not gud-running))
; (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
(gud-def gud-print "%e" "\C-p" "Evaluate perl expression at point.")
- (setq comint-prompt-regexp "^ DB<+[0-9]+>+ ")
+ (setq comint-prompt-regexp "^ DB<+(*[0-9])*+>+ ")
(setq paragraph-start comint-prompt-regexp)
(run-hooks 'perldb-mode-hook))
\f
(fset 'gud-jdb-find-source 'gud-jdb-find-source-file)))
\f
+;; ======================================================================
+;;
+;; BASHDB support. See http://bashdb.sourceforge.net
+;;
+;; AUTHOR: Rocky Bernstein <rocky@panix.com>
+;;
+;; CREATED: Sun Nov 10 10:46:38 2002 Rocky Bernstein.
+;;
+;; INVOCATION NOTES:
+;;
+;; You invoke bashdb-mode with:
+;;
+;; M-x bashdb <enter>
+;;
+;; It responds with:
+;;
+;; Run bashdb (like this): bash
+;;
+
+;;; History of argument lists passed to bashdb.
+(defvar gud-bashdb-history nil)
+
+;; Convert a command line as would be typed normally to run a script
+;; into one that invokes an Emacs-enabled debugging session.
+;; "--debugger" in inserted as the first switch.
+
+(defun gud-bashdb-massage-args (file args)
+ (let* ((new-args (list "--debugger"))
+ (seen-e nil)
+ (shift (lambda ()
+ (setq new-args (cons (car args) new-args))
+ (setq args (cdr args)))))
+
+ ;; Pass all switches and -e scripts through.
+ (while (and args
+ (string-match "^-" (car args))
+ (not (equal "-" (car args)))
+ (not (equal "--" (car args))))
+ (funcall shift))
+
+ (if (or (not args)
+ (string-match "^-" (car args)))
+ (error "Can't use stdin as the script to debug"))
+ ;; This is the program name.
+ (funcall shift)
+
+ (while args
+ (funcall shift))
+
+ (nreverse new-args)))
+
+;; 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.
+(defun gud-bashdb-marker-filter (string)
+ (setq gud-marker-acc (concat gud-marker-acc string))
+ (let ((output ""))
+
+ ;; Process all the complete markers in this chunk.
+ ;; Format of line looks like this:
+ ;; (/etc/init.d/ntp.init:16):
+ ;; but we also allow DOS drive letters
+ ;; (d:/etc/init.d/ntp.init:16):
+ (while (string-match "\\(^\\|\n\\)(\\(\\([a-zA-Z]:\\)?[^:\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 2) (match-end 2))
+ (string-to-int (substring gud-marker-acc
+ (match-beginning 4)
+ (match-end 4))))
+
+ ;; 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))
+
+(defun gud-bashdb-find-file (f)
+ (save-excursion
+ (let ((buf (find-file-noselect f 'nowarn)))
+ (set-buffer buf)
+ buf)))
+
+(defcustom gud-bashdb-command-name "bash"
+ "File name for executing bash debugger."
+ :type 'string
+ :group 'gud)
+
+;;;###autoload
+(defun bashdb (command-line)
+ "Run bashdb 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 bashdb (like this): "
+ (if (consp gud-bashdb-history)
+ (car gud-bashdb-history)
+ (concat gud-bashdb-command-name
+ " "))
+ gud-minibuffer-local-map nil
+ '(gud-bashdb-history . 1))))
+
+ (gud-common-init command-line 'gud-bashdb-massage-args
+ 'gud-bashdb-marker-filter 'gud-bashdb-find-file)
+
+ (set (make-local-variable 'gud-minor-mode) 'bashdb)
+
+ (gud-def gud-break "break %l" "\C-b" "Set breakpoint at current line.")
+ (gud-def gud-tbreak "tbreak %l" "\C-t" "Set temporary breakpoint at current line.")
+ (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
+ (gud-def gud-step "step" "\C-s" "Step one source line with display.")
+ (gud-def gud-next "next" "\C-n" "Step one line (skip functions).")
+ (gud-def gud-cont "continue" "\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 "pe %e" "\C-p" "Evaluate bash expression at point.")
+
+ ;; Is this right?
+ (gud-def gud-statement "eval %e" "\C-e" "Execute Python statement at point.")
+
+ (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
+ (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
+ (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
+ (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
+
+ (setq comint-prompt-regexp "^bashdb<+[0-9]*>+ ")
+ (setq paragraph-start comint-prompt-regexp)
+ (run-hooks 'bashdb-mode-hook)
+ )
+
+(provide 'bashdb)
+
;;
;; End of debugger-specific information
;;