]> git.eshelyaron.com Git - emacs.git/commitdiff
Add support for jdb (Java debugger).
authorRichard M. Stallman <rms@gnu.org>
Thu, 2 Apr 1998 05:04:20 +0000 (05:04 +0000)
committerRichard M. Stallman <rms@gnu.org>
Thu, 2 Apr 1998 05:04:20 +0000 (05:04 +0000)
(jdb): New function.
(gud-jdb-history): New variable.
(gud-jdb-directories): New variable.
(gud-jdb-source-files): New variable.
(gud-jdb-build-source-files-list): New function.
(gud-jdb-package-of-file): New function.
(gud-jdb-class-source-alist): New variable.
(gud-jdb-build-class-source-alist): New function.
(gud-jdb-massage-args): New function.
(gud-jdb-find-source-file): New function.
(gud-jdb-marker-filter): New function.
(gud-jdb-find-file): New function.
(gud-jdb-command-name): New variable.
(gud-perldb-command-name): Variable renamed from perldb-command-name.

lisp/gud.el

index bc42af53da945f7f90b9e6dfbea942ee0b709e47..47e111bcfe2cf89293930596ed5e7f4d02dc5d8e 100644 (file)
@@ -1,10 +1,10 @@
-;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, dbx, xdb or perldb
+;;; gud.el --- Grand Unified Debugger mode for running GDB and other debuggers
 
 ;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
 ;; Maintainer: FSF
 ;; Keywords: unix, tools
 
-;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -34,7 +34,8 @@
 ;; wrote the GDB command completion code.  Dave Love <d.love@dl.ac.uk>
 ;; added the IRIX kluge, re-implemented the Mips-ish variant and added
 ;; a menu. Brian D. Carlstrom <bdc@ai.mit.edu> combined the IRIX kluge with 
-;; the gud-xdb-directories hack producing gud-dbx-directories.
+;; the gud-xdb-directories hack producing gud-dbx-directories.  Derek L. Davies
+;; <ddavies@world.std.com> added support for jdb (Java debugger.)
 
 ;;; Code:
 
@@ -1228,7 +1229,7 @@ directories if your program contains sources from more than one directory."
       (gud-make-debug-menu)
       buf)))
 
-(defcustom perldb-command-name "perl"
+(defcustom gud-perldb-command-name "perl"
   "File name for executing Perl."
   :type 'string
   :group 'gud)
@@ -1242,7 +1243,7 @@ and source-file directory for your debugger."
    (list (read-from-minibuffer "Run perldb (like this): "
                               (if (consp gud-perldb-history)
                                   (car gud-perldb-history)
-                                (concat perldb-command-name
+                                (concat gud-perldb-command-name
                                         " "
                                         (or (buffer-file-name)
                                             "-e 0")
@@ -1267,6 +1268,290 @@ and source-file directory for your debugger."
   (setq paragraph-start comint-prompt-regexp)
   (run-hooks 'perldb-mode-hook)
   )
+\f
+;; ======================================================================
+;;
+;; JDB support.
+;;
+;; AUTHOR:     Derek Davies <ddavies@world.std.com>
+;;
+;; CREATED:    Sun Feb 22 10:46:38 1998 Derek Davies.
+;;
+;; INVOCATION NOTES:
+;;
+;; You invoke jdb-mode with:
+;;
+;;    M-x jdb <enter>
+;;
+;; It responds with:
+;;
+;;    Run jdb (like this): jdb 
+;;
+;; type any jdb switches followed by the name of the class you'd like to debug.
+;; Supply a fully qualfied classname (these do not have the ".class" extension)
+;; for the name of the class to debug (e.g. "COM.the-kind.ddavies.CoolClass").
+;; See the known problems section below for restrictions when specifying jdb
+;; command line switches (search forward for '-classpath').
+;;
+;; You should see something like the following:
+;;
+;;    Current directory is ~/src/java/hello/
+;;    Initializing jdb...
+;;    0xed2f6628:class(hello)
+;;    >
+;;
+;; To set an initial breakpoint try:
+;;
+;;    > stop in hello.main
+;;    Breakpoint set in hello.main
+;;    >
+;;
+;; To execute the program type:
+;;
+;;    > run
+;;    run hello 
+;;
+;;    Breakpoint hit: running ...
+;;    hello.main (hello:12)
+;;
+;; Type M-n to step over the current line and M-s to step into it.  That,
+;; along with the JDB 'help' command should get you started.  The 'quit'
+;; JDB command will get out out of the debugger.
+;;
+;; KNOWN PROBLEMS AND FIXME's:
+;;
+;; Each source file must contain one and only one class or interface
+;; definition.
+;;
+;; Does not grok UNICODE id's.  Only ASCII id's are supported.
+;;
+;; Loses when valid package statements are embedded in certain kinds of
+;; comments and/or string literals, but this should be rare.
+;;
+;; You must not put whitespace between "-classpath" and the path to
+;; search for java classes even though it is required when invoking jdb
+;; from the command line.  See gud-jdb-massage-args for details.
+;;
+;; ======================================================================
+;; gud jdb variables and functions
+
+;; History of argument lists passed to jdb.
+(defvar gud-jdb-history nil)
+
+;; List of Java source file directories.
+(defvar gud-jdb-directories (list ".")
+  "*A list of directories that gud jdb should search for source code.  
+The file names should be absolute, or relative to the current directory.")
+
+;; List of the java source files for this debugging session.
+(defvar gud-jdb-source-files nil)
+
+;; Return a list of java source files.  PATH gives the directories in
+;; which to search for files with extension EXTN.  Normally EXTN is
+;; given as the regular expression "\\.java$" .
+(defun gud-jdb-build-source-files-list (path extn)
+  (apply 'nconc (mapcar (lambda (d) (directory-files d t extn nil)) path)))
+
+;; Return the package (with trailing period) to which FILE belongs.
+;; Returns "" if FILE is in the default package.  BUF is the name of a
+;; buffer into which FILE is read so that it can be searched in order
+;; to determine it's package.  As a consequence, the contents of BUF
+;; are erased by this function.
+(defun gud-jdb-package-of-file (buf file)
+  (set-buffer buf)
+  (insert-file-contents file nil nil nil t)
+  ;; FIXME: Java IDs are UNICODE strings - this code does not
+  ;; do the right thing!
+  ;; FIXME: Does not always ignore contents of comments or string literals.
+  (if (re-search-forward
+                 "^[ \t]*package[ \t]+\\([a-zA-Z0-9$_\.]+\\)[ \t]*;" nil t)
+         (concat (match-string 1) ".")
+       ""))
+
+;; Association list of fully qualified class names (package + class name) and
+;; their source files.
+(defvar gud-jdb-class-source-alist nil)
+
+;; Return an alist of fully qualified classes and the source files
+;; holding their definitions.  SOURCES holds a list of all the source
+;; files to examine.
+(defun gud-jdb-build-class-source-alist (sources)
+  (let ((tmpbuf (get-buffer-create "*gud-jdb-scratch*")))
+       (prog1
+               (mapcar
+                (lambda (s)
+                  (cons
+                       (concat
+                        (gud-jdb-package-of-file tmpbuf s)
+                        (file-name-sans-versions
+                                  (file-name-sans-extension
+                                                (file-name-nondirectory s))))
+                       s)) sources)
+         (kill-buffer tmpbuf))))
+
+;; Change what was given in the minibuffer to something that can be used to
+;; invoke the debugger.
+(defun gud-jdb-massage-args (file args)
+  ;; The jdb executable must have whitespace between "-classpath" and
+  ;; it's value while gud-common-init expects all switch values to
+  ;; follow the switch keyword without intervening whitespace.  We
+  ;; require that when the user enters the "-classpath" switch in the
+  ;; EMACS minibuffer that they do so without the intervening
+  ;; whitespace.  This function adds it back (it's called after
+  ;; gud-common-init).  There are more switches like this (for
+  ;; instance "-host" and "-password") but I don't care about them
+  ;; yet.
+  (if args
+         (let (massaged-args user-error)
+       
+               (while
+                       (and args
+                                (not (string-match "-classpath\\(.+\\)" (car args)))
+                                (not (setq user-error
+                                                       (string-match "-classpath$" (car args)))))
+                 (setq massaged-args (append massaged-args (list (car args))))
+                 (setq args (cdr args)))
+
+               ;; By this point the current directory is all screwed up.  Maybe we
+               ;; could fix things and re-invoke gud-common-init, but for now I think
+               ;; issueing the error is good enough.
+               (if user-error
+                       (progn
+                         (kill-buffer (current-buffer))
+                         (error "Error: Omit whitespace between '-classpath' and it's value")))
+               
+               (if args
+                       (setq massaged-args
+                                 (append
+                                  massaged-args
+                                  (list "-classpath")
+                                  (list
+                                       (substring
+                                        (car args)
+                                        (match-beginning 1) (match-end 1)))
+                                  (cdr args)))
+                 massaged-args))))
+
+;; Search for an association with P, a fully qualified class name, in
+;; gud-jdb-class-source-alist.  The asssociation gives the fully
+;; qualified file name of the source file which produced the class.
+(defun gud-jdb-find-source-file (p)
+  (cdr (assoc p gud-jdb-class-source-alist)))
+
+;; See comentary for other debugger's marker filters - there you will find
+;; important notes about STRING.
+(defun gud-jdb-marker-filter (string)
+
+  ;; Build up the accumulator.
+  (setq gud-marker-acc
+               (if gud-marker-acc
+                       (concat gud-marker-acc string)
+                       string))
+
+  ;; We process STRING from left to right.  Each time through the following
+  ;; loop we process at most one marker.  The start variable keeps track of
+  ;; where we are in the input string through the iterations of this loop.
+  (let (start file-found)
+
+       ;; Process each complete marker in the input.  There may be an incomplete
+       ;; marker at the end of the input string.  Incomplete markers are left
+       ;; in the accumulator for processing the next time the function is called.
+       (while
+               
+               ;; Do we see a marker?
+               (string-match
+                               ;; jdb puts out a string of the following form when it
+                               ;; hits a breakpoint:
+                               ;;
+                               ;;     <fully-qualified-class><method> (<class>:<line-number>)
+                               ;;
+                               ;; <fully-qualified-class>'s are composed of Java ID's
+                               ;; separated by periods.  <method> and <class> are
+                               ;; also Java ID's.  <method> begins with a period and
+                               ;; may contain less-than and greater-than (constructors,
+                               ;; for instance, are called <init> in the symbol table.)
+                               ;; Java ID's begin with a letter followed by letters
+                               ;; and/or digits.  The set of letters includes underscore
+                               ;; and dollar sign.
+                               ;;
+                               ;; The first group matches <fully-qualified-class>,
+                               ;; the second group matches <class> and the third group
+                               ;; matches <line-number>.  We don't care about using
+                               ;; <method> so we don't "group" it.
+                               ;;
+                               ;; FIXME: Java ID's are UNICODE strings, this matches ASCII
+                               ;; ID's only.
+                               "\\([a-zA-Z0-9.$_]+\\)\\.[a-zA-Z0-9$_<>]+ (\\([a-zA-Z0-9$_]+\\):\\([0-9]+\\))"
+                               gud-marker-acc start)
+         
+         ;; Figure out the line on which to position the debugging arrow.
+         ;; Return the info as a cons of the form:
+         ;;
+         ;;     (<file-name> . <line-number>) .
+         (if (setq
+                  file-found
+                  (gud-jdb-find-source-file
+                               (substring gud-marker-acc
+                                                  (match-beginning 1)
+                                                  (match-end 1))))
+                 (setq gud-last-frame
+                               (cons
+                                file-found
+                                (string-to-int
+                                                (substring gud-marker-acc
+                                                                       (match-beginning 3)
+                                                                       (match-end 3)))))
+               (message "Could not find source file."))
+
+               ;; Set start after the last character of STRING that we've looked at
+               ;; and loop to look for another marker.
+               (setq start (match-end 0))))
+
+  ;; We don't filter any debugger output so just return what we were given.
+  string)
+
+(defun gud-jdb-find-file (f)
+  (and (file-readable-p f)
+          (find-file-noselect f)))
+
+(defvar gud-jdb-command-name "jdb" "Command that executes the Java debugger.")
+
+;;;###autoload
+(defun jdb (command-line)
+  "Run jdb with command line COMMAND-LINE in a buffer.  The buffer is named 
+\"*gud*\" if no initial class is given or \"*gud-<initial-class-basename>*\" 
+if there is.  If the \"-classpath\" switch is given, omit all whitespace 
+between it and it's value."
+  (interactive
+   (list (read-from-minibuffer "Run jdb (like this): "
+                          (if (consp gud-jdb-history)
+                                  (car gud-jdb-history)
+                                (concat gud-jdb-command-name " "))
+                          nil nil
+                          '(gud-jdb-history . 1))))
+
+  (gud-common-init command-line 'gud-jdb-massage-args
+          'gud-jdb-marker-filter 'gud-jdb-find-file)
+
+  (gud-def gud-break  "stop at %l" "\C-b" "Set 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   "cont"    "\C-r" "Continue with display.")
+
+  (setq comint-prompt-regexp "^> \|^.+\[[0-9]+\] ")
+  (setq paragraph-start comint-prompt-regexp)
+  (run-hooks 'jdb-mode-hook)
+
+  ;; Create and bind the class/source association list as well as the source
+  ;; file list.
+  (setq
+   gud-jdb-class-source-alist
+   (gud-jdb-build-class-source-alist
+               (setq
+                gud-jdb-source-files
+                (gud-jdb-build-source-files-list gud-jdb-directories "\\.java$")))))  
+\f
 
 ;;
 ;; End of debugger-specific information