1 ;;; jde-dbo.el -- JDEbug output functions
2 ;; $Revision: 1.40 $ $Date: 2004/06/03 02:04:11 $
4 ;; Author: Paul Kinnucan <paulk@mathworks.com>
5 ;; Maintainer: Paul Kinnucan
6 ;; Keywords: java, tools
8 ;; Copyright (C) 1997, 1998, 1999, 2001, 2002, 2004 Paul Kinnucan.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
27 ;; This is one of a set of packages that make up the
28 ;; Java Development Environment (JDE) for Emacs. See the
29 ;; JDE User's Guide for more information.
31 ;; The latest version of the JDE is available at
32 ;; <URL:http://sunsite.auc.dk/jde/>.
34 ;; Please send any comments, bugs, or upgrade requests to
35 ;; Paul Kinnucan at paulk@mathworks.com.
40 (jde-require 'tree-widget)
41 (require 'jde-widgets)
43 (defclass jde-dbo-thread ()
46 (state :initarg :state)
47 (status :initarg :status))
50 (defun jde-dbo-make-thread-obj (thread-spec)
51 (jde-dbo-thread "thread"
52 :id (nth 1 thread-spec)
53 :name (nth 2 thread-spec)
54 :state (nth 3 thread-spec)
55 :status (nth 4 thread-spec)))
58 (defun jde-dbo-command-result (id &rest args)
59 "Returns the result of normally executing command specified by ID.
60 The result consists of a list whose first element is the command ID,
61 whose second element is the symbol `normal' to indicate a normal
62 result and whose remaining element is a list of optional result data."
63 (list id 'normal args))
65 (defun jde-dbo-command-error (id &rest args)
66 "Returns a command error result. The result consists of list whose first
67 element is the command's id, whose second element is the symbol `error'
68 to indicate that an error occured and whose third element is a list
69 of optional error data."
70 (list id 'error args))
72 (defun jde-dbo-command-result-id (result)
75 (defun jde-dbo-command-succeeded-p (result)
76 (equal (nth 1 result) 'normal))
78 (defun jde-dbo-command-result-data (result)
81 (defun jde-dbo-report-ids-in-use (id-count)
82 (message "%d object ids in use." id-count))
84 (defun jde-dbo-init-debug-session ()
85 (oset jde-dbs-the-debugger started-p t))
87 (defun jde-dbo-debug (debug-info)
88 (message "Debug message: %s" debug-info))
90 (defun jde-dbo-spec-resolved (proc-id spec-id)
91 "Notifies resolution of breakpoint, watchpoint, or
93 (let* ((proc (jde-dbs-get-process proc-id))
94 (bpspec (if proc (jde-dbs-proc-get-bpspec proc spec-id)))
95 (bp (if bpspec (oref bpspec breakpoint)))
96 (file (if bp (oref bp file)))
97 (line (if bp (jde-db-breakpoint-get-line bp))))
100 (oset bp status 'active)
101 (jde-db-mark-breakpoint-active file line)
102 (jde-dbs-proc-display-debug-message
104 (format "Resolved breakpoint set in %s at line %s." file line))))))
106 (defun jde-dbo-error (proc-id message)
107 (jde-dbs-display-debug-message proc-id message))
109 (defun jde-dbo-message (proc-id message)
110 (jde-dbs-display-debug-message proc-id message))
113 (defun jde-dbo-unknown-exception (exception)
114 (jde-dbs-proc-display-debug-message
115 (jde-dbs-get-target-process) exception))
117 (defun jde-dbo-vm-start-event (process-id process-status process-state)
118 (let* ((process (jde-dbs-get-process process-id))
119 (thread-id (nth 1 process-state))
120 (thread-name (nth 2 process-state))
121 (state (nth 3 process-state))
122 (reason (nth 4 process-state)))
124 (let ((state-info (oref process state-info)))
125 (jde-dbs-proc-state-info-set state-info state reason thread-id thread-name)
126 (oset process startupp t)
127 (jde-dbs-proc-display-debug-message process "vm started...")
129 ((string= process-status "all")
130 (jde-dbs-proc-display-debug-message process "All threads suspended...")))
131 ;; Sometimes the debugger is tardy responding to a launch command and thus the JDE thinks the
132 ;; process is dead. In this case, move the process back to the registry and
133 ;; make it the target process.
134 (when (jde-dbs-proc-set-contains-p jde-dbs-the-process-morgue process)
135 (jde-dbs-proc-move-to-registry process)
136 (oset jde-dbs-the-process-registry :target-process process)))
137 (message "Start Event Error: can't find process object for process id %d" process-id))))
139 (defun jde-dbo-break (process state-info state reason thread-id thread-name
140 message proc-id class file line-no)
141 (jde-dbs-proc-state-info-set state-info state reason
142 thread-id thread-name)
143 (setq jde-dbo-current-process process)
144 (setq jde-dbo-current-thread-id thread-id)
145 (if jde-bug-local-variables
146 (jde-dbo-update-locals-buf process
148 (if jde-bug-stack-info (jde-dbo-update-stack process thread-id))
149 (oset process steppablep t)
150 (jde-dbs-display-debug-message proc-id message)
151 (jde-db-set-debug-cursor class file line-no)
152 (when jde-bug-raise-frame-p (raise-frame)))
154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
156 ;; Breakpoint Event Handler ;;
158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
160 (defvar jde-dbo-locals-open-nodes nil
161 "List of name of tree nodes opened.")
163 (defun jde-dbo-locals-open-p (node-name)
164 "Return non-nil if NODE-NAME is the name of an open tree node."
165 (member node-name jde-dbo-locals-open-nodes))
167 (defun jde-dbo-locals-update-open-nodes (tree)
168 "Update the list of open nodes `jde-dbo-locals-open-nodes'.
169 Called after each folding/unfolding of the `tree-widget' TREE.
170 See also the hook `tree-widget-after-toggle-fucntions'."
171 (let ((node-name (widget-get tree :node-name))
172 (open (widget-get tree :open)))
174 (add-to-list 'jde-dbo-locals-open-nodes node-name)
175 (setq jde-dbo-locals-open-nodes
176 (delete node-name jde-dbo-locals-open-nodes)))))
179 (defun jde-dbo-update-locals-buf (process thread frame)
180 (let* ((cmd (jde-dbs-get-locals
184 :stack-frame-index frame))
185 (locals (jde-dbs-cmd-exec cmd))
189 (set-buffer (oref process locals-buf))
190 (kill-all-local-variables)
191 (let ((inhibit-read-only t))
195 (map-extents (lambda (extent ignore)
196 (delete-extent extent)
198 (let ((all (overlay-lists)))
199 (mapcar 'delete-overlay (car all))
200 (mapcar 'delete-overlay (cdr all))))
202 (make-local-hook 'tree-widget-after-toggle-functions)
203 (add-hook 'tree-widget-after-toggle-functions
204 'jde-dbo-locals-update-open-nodes nil t)
206 (goto-char (point-min))
208 ;; Insert the this object for this stack frame.
209 (let* ((cmd (jde-dbs-get-this
213 :stack-frame-index frame))
214 (this-obj (jde-dbs-cmd-exec cmd)))
215 (if (not (typep this-obj 'jde-dbs-java-null))
217 (let* ((id (oref this-obj :id))
218 (open (concat "this" (number-to-string id))))
219 (widget-create 'jde-widget-java-obj
222 :open (jde-dbo-locals-open-p open)
224 :object-id (oref this-obj :id))))))
226 ;; Insert the local variables for this stack frame.
227 (dolist (local-var locals)
228 (jde-dbo-view-var-in-buf (oref local-var value)
229 (oref local-var name) process
230 'jde-dbo-locals-open-p (current-buffer))))))
232 (defun jde-dbo-update-stack (process thread-id)
233 (let* ((cmd (jde-dbs-get-thread "get_thread"
235 :thread-id thread-id))
236 (thread-info (jde-dbs-cmd-exec cmd))
237 (stack (nth 5 thread-info)))
238 (oset process :stack stack)
239 (oset process :stack-ptr 0)))
241 (defvar jde-dbo-current-process nil "Used to keep track of the process
242 used in the last breakpoint hit event, and watch point hit event.")
244 (defvar jde-dbo-current-thread-id nil "Used to keep track of the thread id
245 used in the last breakpoint hit event, and watch point hit event.")
247 (defun jde-dbo-breakpoint-hit-event (process-id process-status process-state spec-id location a2 a3)
248 (let ((process (jde-dbs-get-process process-id)))
250 (let ((class (nth 0 location))
251 (file (nth 1 location))
252 (line-no (nth 2 location))
253 (thread-id (nth 1 process-state))
254 (thread-name (nth 2 process-state))
255 (state (nth 3 process-state))
256 (reason (nth 4 process-state))
257 (state-info (oref process state-info)))
259 (jde-dbo-break process state-info state reason thread-id
261 (format "Breakpoint hit at line %d in %s (%s) on thread %s. All threads suspended." line-no class file thread-name)
262 process-id class file line-no)
263 (message "Breakpoint hit event error: state info object missing for process %d." process-id)))
264 (message "Breakpoint hit event error: process object for process %d is missing." process-id))))
266 (defun jde-dbo-step-event (proc-id status process-state location)
267 "Handler for step events."
268 (let ((process (jde-dbs-get-process proc-id)))
270 (let ((class (nth 0 location))
271 (file (nth 1 location))
272 (line-no (nth 2 location))
273 (thread-id (nth 1 process-state))
274 (thread-name (nth 2 process-state))
275 (state (nth 3 process-state))
276 (reason (nth 4 process-state))
277 (state-info (oref process state-info)))
279 (jde-dbo-break process state-info state reason thread-id
281 (format "Stepped to line %d in %s (%s) on thread %s. All threads suspended."
282 line-no class file thread-name)
283 proc-id class file line-no)
284 (message "Step event error: state info missing for process %d" proc-id)))
285 (message "Step event error: could not find process %d." proc-id))))
288 (defun jde-dbo-exception-event (proc-id status process-state spec-id exception-spec a3)
289 (let ((process (jde-dbs-get-process proc-id)))
291 (let ((exception-class (nth 0 exception-spec))
292 (exception-object (nth 1 exception-spec))
293 (thread-id (nth 1 process-state))
294 (thread-name (nth 2 process-state))
295 (state (nth 3 process-state))
296 (reason (nth 4 process-state))
297 (location (nth 5 process-state))
298 (state-info (oref process state-info)))
299 (if (not (equal status "none"))
300 ;; Then it's a break, not a trace
301 (let ((class (nth 1 (car location)))
302 (file (nth 2 (car location)))
303 (line-no (nth 3 (car location))))
305 (jde-dbo-break process state-info state reason thread-id
307 (format "Exception encountered at line %d in %s (%s) on thread %s. All threads suspended."
308 line-no class file thread-name)
309 proc-id class file line-no)
310 (message "Exception event error: state info missing for process %d" proc-id)))
311 (jde-dbs-display-debug-message
313 (format "Exception of class %s occurred on thread %s"
314 exception-class thread-name)))))))
317 (defun jde-dbo-vm-disconnected-event (process-id process-status thread)
318 (let ((process (jde-dbs-get-process process-id)))
320 (jde-dbs-proc-display-debug-message process "vm disconnected...")
321 (setq overlay-arrow-position nil)
322 (jde-db-set-all-breakpoints-specified)
323 (jde-dbs-proc-set-state process "vm disconnected")
324 (when (jde-dbs-proc-set-contains-p jde-dbs-the-process-registry process)
325 (jde-dbs-proc-move-to-morgue process)
326 (slot-makeunbound jde-dbs-the-process-registry :target-process)))))
328 (defun jde-dbo-invalid-break (process-id arg2 reason)
329 (jde-dbs-proc-display-debug-message
330 (jde-dbs-get-process process-id)
331 (concat "Invalid break error.\n Reason: " reason)))
333 (defun jde-dbo-vm-death-event (process-id process-status thread)
334 (let* ((process (jde-dbs-get-process process-id))
335 (main-class (oref process main-class)))
336 (jde-dbs-proc-display-debug-message
338 (format "%s process ended." main-class))
339 (when (jde-dbs-proc-set-contains-p jde-dbs-the-process-registry process)
340 (jde-dbs-proc-move-to-morgue process)
341 (slot-makeunbound jde-dbs-the-process-registry :target-process))
342 (setq overlay-arrow-position nil)))
344 (defclass jde-dbo-method ()
345 ((class :initarg :class
349 (returns :initarg :returns
357 (defmethod jde-dbo-to-string ((this jde-dbo-method))
358 (format "<%s %s.%s(%s)>"
362 (mapconcat (lambda (x) x) (oref this :args) ",")))
364 (defun jde-dbo-make-method (spec)
366 (jde-dbo-method "method"
369 :returns (nth 2 spec)
370 :args (nth 3 spec))))
372 (oset m :kind (nth 4 spec)))
375 (defun jde-dbo-class-prepare-event (process-id process-status thread-spec class-name)
376 (let* ((thread (jde-dbo-make-thread-obj thread-spec))
377 (process (jde-dbs-get-process process-id)))
378 (jde-dbs-proc-display-debug-message
380 (format "Preparing class %s.\n Thread: %s. Status: %s.\n"
383 (oref thread status)))))
385 (defun jde-dbo-class-unload-event (process-id process-status thread-spec class-name)
386 (let* ((thread (jde-dbo-make-thread-obj thread-spec))
387 (process (jde-dbs-get-process process-id)))
388 (jde-dbs-proc-display-debug-message
390 (format "Unloading class %s.\n Thread: %s. Status: %s.\n"
393 (oref thread status)))))
395 (defun jde-dbo-method-entry-event (process-id process-status thread-spec method-spec)
396 (let* ((thread (jde-dbo-make-thread-obj thread-spec))
397 (method (jde-dbo-make-method method-spec))
398 (method-sig (jde-dbo-to-string method))
399 (process (jde-dbs-get-process process-id)))
400 (jde-dbs-proc-display-debug-message
402 (format "Entering %s.%s\n Thread: %s\n Signature: %s\n"
408 (defun jde-dbo-method-exit-event (process-id process-status thread-spec method-spec)
409 (let* ((thread (jde-dbo-make-thread-obj thread-spec))
410 (method (jde-dbo-make-method method-spec))
411 (method-sig (jde-dbo-to-string method))
412 (process (jde-dbs-get-process process-id)))
413 (jde-dbs-proc-display-debug-message
415 (format "Exiting %s.%s\n Thread: %s\n Signature: %s\n"
421 (defun jde-dbo-watchpoint-hit-event (process-id process-status thread-spec request-id &rest data)
422 (let ((process (jde-dbs-get-process process-id)))
424 (let* ((thread (jde-dbo-make-thread-obj thread-spec))
425 (thread-id (oref thread id))
426 (thread-name (oref thread name))
427 (thread-state (oref thread state))
428 (thread-status (oref thread status))
430 ;; Object whose field was accessed or modified.
431 (obj-spec (nth 0 data))
432 (obj-class (nth 0 obj-spec))
433 (obj-id (nth 1 obj-spec))
434 (obj-gc-flag (nth 2 obj-spec))
435 ;; Field that was accessed or modified.
436 (field-spec (nth 1 data))
437 (field-decl (nth 0 field-spec))
438 (field-name (nth 0 field-decl))
439 (field-type (nth 1 field-decl))
440 (field-qual (if (> (length field-decl) 3) (nth 2 field-decl)))
441 (field-value-type (nth 1 field-spec))
442 (field-value (nth 2 field-spec))
444 (breakpoint-spec (nth 2 data))
445 (breakpoint-class (nth 0 breakpoint-spec))
446 (breakpoint-file (nth 1 breakpoint-spec))
447 (breakpoint-line (nth 2 breakpoint-spec))
449 (obj-match (nth 3 data))
451 (thread-match (nth 4 data))
452 ;; Expression true data
453 (expression-true (nth 5 data)))
455 (jde-dbs-proc-display-debug-message
457 (format "<%s:%s> accessed or modified at line %s in %s.\n Watched field: %s %s %s = %s\n"
458 obj-class obj-id breakpoint-line breakpoint-file
459 (if field-qual field-qual "") field-type field-name field-value))
461 (if (string= thread-status "suspended by debugger")
462 (let ((state-info (oref process state-info)))
465 (jde-dbs-proc-state-info-set
466 state-info thread-state
467 thread-status thread-id thread-name)
468 (setq jde-dbo-current-process process)
469 (setq jde-dbo-current-thread-id thread-id)
470 (if jde-bug-local-variables
471 (jde-dbo-update-locals-buf process
473 (if jde-bug-stack-info (jde-dbo-update-stack process
475 (oset process steppablep t)
476 (jde-db-set-debug-cursor breakpoint-class breakpoint-file
478 (when jde-bug-raise-frame-p (raise-frame))
480 (jde-dbs-display-debug-message
482 (format "Stopping at line %d in %s (%s) on thread %s."
483 breakpoint-line breakpoint-class breakpoint-file thread-name)))
484 (message "Watchpoint event error: state info object missing for process %d."
486 (message "Watchpoint event error: process object for process %d is missing." process-id))))
489 (defun jde-dbo-event-set (process-id process-status thread &rest events)
490 "Invoked when a set of debugger events occurs. EVENTS is a list of
491 lists. The first element is the name of a function that handles the event.
492 The remaining elements are arguments to pass to the handler."
495 (let ((handler (car event))
498 (append (list process-id process-status thread) args))))
501 (defun jde-dbo-view-var-in-buf (var-value name process open buf
503 "Create a tree-widget representing variable VAR-VALUE (a
504 jde-dbs-java-null/primitive/udci type), whose name is NAME and in
505 process PROCESS, and place that tree-widget in buffer BUF. OPEN is
506 either a variable or a function. If it is a variable, then the
507 tree-widget is open if true. If it is a function, then the function
508 is called with name to return a true or false value (this is used
509 for caching the state). If CLEAR is true then the buffer is cleared
510 before creating the tree-widget."
515 (let* ((var-tag (format "%s %s [id: %s]" (oref var-value jtype) name
516 (if (or (typep var-value 'jde-dbs-java-primitive)
517 (typep var-value 'jde-dbs-java-null))
519 (oref var-value id))))
520 (openp (if (functionp open)
521 (funcall open var-tag)
524 ((typep var-value 'jde-dbs-java-udci)
525 (if (string= (oref var-value :jtype) "java.lang.String")
526 (let* ((cmd (jde-dbs-get-string
529 :object-id (oref var-value id)))
530 (str-val (jde-dbs-cmd-exec cmd)))
531 (widget-create 'tree-widget
536 (list 'tree-widget :tag str-val)))
537 (widget-create 'jde-widget-java-obj
542 :object-id (oref var-value :id))))
543 ((typep var-value 'jde-dbs-java-array)
544 (widget-create 'jde-widget-java-array
550 ((typep var-value 'jde-dbs-java-primitive)
551 (widget-create 'tree-widget
557 :tag (format "%s" (oref var-value value)))))
558 ((typep var-value 'jde-dbs-java-null)
559 (widget-create 'tree-widget :tag var-tag :value t
560 (list 'tree-widget :tag "null")))
562 (error "Unidentified type of variable: %s" var-tag))))
563 (use-local-map widget-keymap)
567 ;; $Log: jde-dbo.el,v $
568 ;; Revision 1.40 2004/06/03 02:04:11 paulk
569 ;; jde-require tree-widget.
571 ;; Revision 1.39 2003/09/27 05:34:36 ahyatt
572 ;; Exceptions should break when the user selects to suspend the thread as
573 ;; well (not just when the user selects to suspect all threads).
575 ;; Revision 1.38 2003/09/17 05:12:24 ahyatt
576 ;; Added exception breakpoints
578 ;; Revision 1.37 2002/12/19 22:19:06 ahyatt
579 ;; Fixed problem with nulls in the tree-view display
581 ;; Revision 1.36 2002/12/08 20:43:45 ahyatt
582 ;; Refactoring to support UI changes in jde-bug
584 ;; Revision 1.35 2002/02/04 05:47:17 paulk
585 ;; Added code to rehighlight breakpoints if the user kills a
586 ;; buffer for a source file that contains breakpoints and
587 ;; then reopens the file.
589 ;; Revision 1.34 2002/01/16 07:36:01 paulk
590 ;; Updated JDEbug to use most of the new generalized breakpoint functionality.
592 ;; Revision 1.33 2001/12/28 05:27:45 paulk
593 ;; Deleted jde-dbo-query-source-directory, jde-dbo-find-source-directory, and
594 ;; jde-dbo-show-line and replaced calls to these functions with calls to
595 ;; the equivalent functions in the jde-db package: jde-db-query-source-directory,
596 ;; jde-db-find-source-directory, and jde-db-set-debug-cursor.
598 ;; Revision 1.32 2001/12/04 06:14:29 paulk
599 ;; Replaced call to obsolete jde-bug-install-jdebug-menu with call to jde-bug-minor-mode.
601 ;; Revision 1.31 2001/11/27 21:06:49 jslopez
602 ;; Fixes some compilation messages.
603 ;; Adds code to be able to keep the state of
604 ;; the nodes in the JDEBug local variables tree.
606 ;; Revision 1.30 2001/11/23 15:58:47 jslopez
607 ;; Adds Log key word.