xref: /openbsd-src/gnu/usr.bin/binutils/gdb/mi/gdb-mi.el (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1*11efff7fSkettenis;;; gdb-mi.el (internally gdbmi6.el) - (24th May 2004)
2*11efff7fSkettenis
3*11efff7fSkettenis;; Run gdb with GDB/MI (-interp=mi) and access CLI using "cli-command"
4*11efff7fSkettenis;; (could use "-interpreter-exec console cli-command")
5*11efff7fSkettenis
6*11efff7fSkettenis;; Author: Nick Roberts <nickrob@gnu.org>
7*11efff7fSkettenis;; Maintainer: Nick Roberts <nickrob@gnu.org>
8*11efff7fSkettenis;; Keywords: unix, tools
9*11efff7fSkettenis
10*11efff7fSkettenis;; Copyright (C) 2004  Free Software Foundation, Inc.
11*11efff7fSkettenis
12*11efff7fSkettenis;; This file is part of GNU GDB.
13*11efff7fSkettenis
14*11efff7fSkettenis;; GNU GDB is free software; you can redistribute it and/or modify
15*11efff7fSkettenis;; it under the terms of the GNU General Public License as published by
16*11efff7fSkettenis;; the Free Software Foundation; either version 2, or (at your option)
17*11efff7fSkettenis;; any later version.
18*11efff7fSkettenis
19*11efff7fSkettenis;; This program is distributed in the hope that it will be useful,
20*11efff7fSkettenis;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21*11efff7fSkettenis;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22*11efff7fSkettenis;; GNU General Public License for more details.
23*11efff7fSkettenis
24*11efff7fSkettenis;;; Commentary:
25*11efff7fSkettenis
26*11efff7fSkettenis;; This mode acts as a graphical user interface to GDB and requires GDB 6.1
27*11efff7fSkettenis;; onwards. You can interact with GDB through the GUD buffer in the usual way,
28*11efff7fSkettenis;; but there are also buffers which control the execution and describe the
29*11efff7fSkettenis;; state of your program. It separates the input/output of your program from
30*11efff7fSkettenis;; that of GDB and displays expressions and their current values in their own
31*11efff7fSkettenis;; buffers. It also uses features of Emacs 21 such as the fringe/display
32*11efff7fSkettenis;; margin for breakpoints, and the toolbar (see the GDB Graphical Interface
33*11efff7fSkettenis;; section in the Emacs info manual).
34*11efff7fSkettenis
35*11efff7fSkettenis;; Start the debugger with M-x gdbmi.
36*11efff7fSkettenis
37*11efff7fSkettenis;; This file uses GDB/MI as the primary interface to GDB. It is still under
38*11efff7fSkettenis;; development and is part of a process to migrate Emacs from annotations
39*11efff7fSkettenis;; (as used in gdb-ui.el) to GDB/MI.
40*11efff7fSkettenis
41*11efff7fSkettenis;; Known Bugs:
42*11efff7fSkettenis;;
43*11efff7fSkettenis
44*11efff7fSkettenis;;; Code:
45*11efff7fSkettenis
46*11efff7fSkettenis(require 'gud)
47*11efff7fSkettenis(require 'gdb-ui)
48*11efff7fSkettenis
49*11efff7fSkettenis
50*11efff7fSkettenis;;;###autoload
51*11efff7fSkettenis(defun gdbmi (command-line)
52*11efff7fSkettenis  "Run gdb on program FILE in buffer *gud-FILE*.
53*11efff7fSkettenisThe directory containing FILE becomes the initial working directory
54*11efff7fSkettenisand source-file directory for your debugger.
55*11efff7fSkettenis
56*11efff7fSkettenisIf `gdb-many-windows' is nil (the default value) then gdb just
57*11efff7fSkettenispops up the GUD buffer unless `gdb-show-main' is t. In this case
58*11efff7fSkettenisit starts with two windows: one displaying the GUD buffer and the
59*11efff7fSkettenisother with the source file with the main routine of the inferior.
60*11efff7fSkettenis
61*11efff7fSkettenisIf `gdb-many-windows' is t, regardless of the value of
62*11efff7fSkettenis`gdb-show-main', the layout below will appear. Keybindings are
63*11efff7fSkettenisgiven in relevant buffer.
64*11efff7fSkettenis
65*11efff7fSkettenisWatch expressions appear in the speedbar/slowbar.
66*11efff7fSkettenis
67*11efff7fSkettenisThe following interactive lisp functions help control operation :
68*11efff7fSkettenis
69*11efff7fSkettenis`gdb-many-windows'    - Toggle the number of windows gdb uses.
70*11efff7fSkettenis`gdb-restore-windows' - To restore the window layout.
71*11efff7fSkettenis
72*11efff7fSkettenisSee Info node `(emacs)GDB Graphical Interface' for a more
73*11efff7fSkettenisdetailed description of this mode.
74*11efff7fSkettenis
75*11efff7fSkettenis
76*11efff7fSkettenis---------------------------------------------------------------------
77*11efff7fSkettenis                               GDB Toolbar
78*11efff7fSkettenis---------------------------------------------------------------------
79*11efff7fSkettenisGUD buffer (I/O of GDB)           | Locals buffer
80*11efff7fSkettenis                                  |
81*11efff7fSkettenis                                  |
82*11efff7fSkettenis                                  |
83*11efff7fSkettenis---------------------------------------------------------------------
84*11efff7fSkettenis Source buffer                    | Input/Output (of inferior) buffer
85*11efff7fSkettenis                                  | (comint-mode)
86*11efff7fSkettenis                                  |
87*11efff7fSkettenis                                  |
88*11efff7fSkettenis                                  |
89*11efff7fSkettenis                                  |
90*11efff7fSkettenis                                  |
91*11efff7fSkettenis                                  |
92*11efff7fSkettenis---------------------------------------------------------------------
93*11efff7fSkettenis Stack buffer                     | Breakpoints buffer
94*11efff7fSkettenis RET      gdb-frames-select       | SPC    gdb-toggle-breakpoint
95*11efff7fSkettenis                                  | RET    gdb-goto-breakpoint
96*11efff7fSkettenis                                  |   d    gdb-delete-breakpoint
97*11efff7fSkettenis---------------------------------------------------------------------
98*11efff7fSkettenis"
99*11efff7fSkettenis  ;;
100*11efff7fSkettenis  (interactive (list (gud-query-cmdline 'gdbmi)))
101*11efff7fSkettenis  ;;
102*11efff7fSkettenis  ;; Let's start with a basic gud-gdb buffer and then modify it a bit.
103*11efff7fSkettenis  (gdb command-line)
104*11efff7fSkettenis  ;;
105*11efff7fSkettenis  (setq gdb-debug-log nil)
106*11efff7fSkettenis  (set (make-local-variable 'gud-minor-mode) 'gdbmi)
107*11efff7fSkettenis  (set (make-local-variable 'gud-marker-filter) 'gud-gdbmi-marker-filter)
108*11efff7fSkettenis  ;;
109*11efff7fSkettenis  (gud-def gud-break (if (not (string-equal mode-name "Machine"))
110*11efff7fSkettenis			 (gud-call "-break-insert %f:%l" arg)
111*11efff7fSkettenis		       (save-excursion
112*11efff7fSkettenis			 (beginning-of-line)
113*11efff7fSkettenis			 (forward-char 2)
114*11efff7fSkettenis			 (gud-call "-break-insert *%a" arg)))
115*11efff7fSkettenis	   "\C-b" "Set breakpoint at current line or address.")
116*11efff7fSkettenis  ;;
117*11efff7fSkettenis  (gud-def gud-remove (if (not (string-equal mode-name "Machine"))
118*11efff7fSkettenis			  (gud-call "clear %f:%l" arg)
119*11efff7fSkettenis			(save-excursion
120*11efff7fSkettenis			  (beginning-of-line)
121*11efff7fSkettenis			  (forward-char 2)
122*11efff7fSkettenis			  (gud-call "clear *%a" arg)))
123*11efff7fSkettenis	   "\C-d" "Remove breakpoint at current line or address.")
124*11efff7fSkettenis  ;;
125*11efff7fSkettenis  (gud-def gud-until  (if (not (string-equal mode-name "Machine"))
126*11efff7fSkettenis			  (gud-call "until %f:%l" arg)
127*11efff7fSkettenis			(save-excursion
128*11efff7fSkettenis			  (beginning-of-line)
129*11efff7fSkettenis			  (forward-char 2)
130*11efff7fSkettenis			  (gud-call "until *%a" arg)))
131*11efff7fSkettenis	   "\C-u" "Continue to current line or address.")
132*11efff7fSkettenis
133*11efff7fSkettenis  (define-key gud-minor-mode-map [left-margin mouse-1]
134*11efff7fSkettenis    'gdb-mouse-toggle-breakpoint)
135*11efff7fSkettenis  (define-key gud-minor-mode-map [left-fringe mouse-1]
136*11efff7fSkettenis    'gdb-mouse-toggle-breakpoint)
137*11efff7fSkettenis
138*11efff7fSkettenis  (setq comint-input-sender 'gdbmi-send)
139*11efff7fSkettenis  ;;
140*11efff7fSkettenis  ;; (re-)initialise
141*11efff7fSkettenis  (setq gdb-main-file nil)
142*11efff7fSkettenis  (setq gdb-current-address "main")
143*11efff7fSkettenis  (setq gdb-previous-address nil)
144*11efff7fSkettenis  (setq gdb-previous-frame nil)
145*11efff7fSkettenis  (setq gdb-current-frame "main")
146*11efff7fSkettenis  (setq gdb-view-source t)
147*11efff7fSkettenis  (setq gdb-selected-view 'source)
148*11efff7fSkettenis  (setq gdb-var-list nil)
149*11efff7fSkettenis  (setq gdb-var-changed nil)
150*11efff7fSkettenis  (setq gdb-prompting nil)
151*11efff7fSkettenis  (setq gdb-current-item nil)
152*11efff7fSkettenis  (setq gdb-pending-triggers nil)
153*11efff7fSkettenis  (setq gdb-output-sink 'user)
154*11efff7fSkettenis  (setq gdb-server-prefix nil)
155*11efff7fSkettenis  ;;
156*11efff7fSkettenis  (setq gdb-buffer-type 'gdbmi)
157*11efff7fSkettenis  ;;
158*11efff7fSkettenis  ;; FIXME: use tty command to separate io.
159*11efff7fSkettenis  ;;(gdb-clear-inferior-io)
160*11efff7fSkettenis  ;;
161*11efff7fSkettenis  (if (eq window-system 'w32)
162*11efff7fSkettenis      (gdb-enqueue-input (list "-gdb-set new-console off\n" 'ignore)))
163*11efff7fSkettenis  ;; find source file and compilation directory here
164*11efff7fSkettenis  (gdb-enqueue-input (list "list main\n"   'ignore))   ; C program
165*11efff7fSkettenis  (gdb-enqueue-input (list "list MAIN__\n" 'ignore))   ; Fortran program
166*11efff7fSkettenis  (gdb-enqueue-input (list "info source\n" 'gdbmi-source-info))
167*11efff7fSkettenis  ;;
168*11efff7fSkettenis  (run-hooks 'gdbmi-mode-hook))
169*11efff7fSkettenis
170*11efff7fSkettenis; Force nil till fixed.
171*11efff7fSkettenis(defconst gdbmi-use-inferior-io-buffer nil)
172*11efff7fSkettenis
173*11efff7fSkettenis; uses --all-values Needs GDB 6.1 onwards.
174*11efff7fSkettenis(defun gdbmi-var-list-children (varnum)
175*11efff7fSkettenis  (gdb-enqueue-input
176*11efff7fSkettenis   (list (concat "-var-update " varnum "\n") 'ignore))
177*11efff7fSkettenis  (gdb-enqueue-input
178*11efff7fSkettenis   (list (concat "-var-list-children --all-values "
179*11efff7fSkettenis		 varnum "\n")
180*11efff7fSkettenis	     `(lambda () (gdbmi-var-list-children-handler ,varnum)))))
181*11efff7fSkettenis
182*11efff7fSkettenis(defconst gdbmi-var-list-children-regexp
183*11efff7fSkettenis"name=\"\\(.*?\\)\",exp=\"\\(.*?\\)\",numchild=\"\\(.*?\\)\",value=\"\\(.*?\\)\""
184*11efff7fSkettenis)
185*11efff7fSkettenis
186*11efff7fSkettenis(defun gdbmi-var-list-children-handler (varnum)
187*11efff7fSkettenis  (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
188*11efff7fSkettenis    (goto-char (point-min))
189*11efff7fSkettenis    (let ((var-list nil))
190*11efff7fSkettenis     (catch 'child-already-watched
191*11efff7fSkettenis       (dolist (var gdb-var-list)
192*11efff7fSkettenis	 (if (string-equal varnum (cadr var))
193*11efff7fSkettenis	     (progn
194*11efff7fSkettenis	       (push var var-list)
195*11efff7fSkettenis	       (while (re-search-forward gdbmi-var-list-children-regexp nil t)
196*11efff7fSkettenis		 (let ((varchild (list (match-string 2)
197*11efff7fSkettenis				       (match-string 1)
198*11efff7fSkettenis				       (match-string 3)
199*11efff7fSkettenis				       nil
200*11efff7fSkettenis				       (match-string 4)
201*11efff7fSkettenis				       nil)))
202*11efff7fSkettenis		   (if (looking-at ",type=\"\\(.*?\\)\"")
203*11efff7fSkettenis		       (setcar (nthcdr 3 varchild) (match-string 1)))
204*11efff7fSkettenis		   (dolist (var1 gdb-var-list)
205*11efff7fSkettenis		     (if (string-equal (cadr var1) (cadr varchild))
206*11efff7fSkettenis			 (throw 'child-already-watched nil)))
207*11efff7fSkettenis		   (push varchild var-list))))
208*11efff7fSkettenis	   (push var var-list)))
209*11efff7fSkettenis       (setq gdb-var-changed t)
210*11efff7fSkettenis       (setq gdb-var-list (nreverse var-list))))))
211*11efff7fSkettenis
212*11efff7fSkettenis;(defun gdbmi-send (proc string)
213*11efff7fSkettenis;  "A comint send filter for gdb."
214*11efff7fSkettenis;  (setq gdb-output-sink 'user)
215*11efff7fSkettenis;  (setq gdb-prompting nil)
216*11efff7fSkettenis;  (process-send-string proc (concat "-interpreter-exec console \"" string "\"")))
217*11efff7fSkettenis
218*11efff7fSkettenis(defun gdbmi-send (proc string)
219*11efff7fSkettenis  "A comint send filter for gdb."
220*11efff7fSkettenis  (setq gdb-output-sink 'user)
221*11efff7fSkettenis  (setq gdb-prompting nil)
222*11efff7fSkettenis  (process-send-string proc (concat string "\n")))
223*11efff7fSkettenis
224*11efff7fSkettenis(defcustom gud-gdbmi-command-name "~/gdb/gdb/gdb -interp=mi"
225*11efff7fSkettenis  "Default command to execute an executable under the GDB-UI debugger."
226*11efff7fSkettenis  :type 'string
227*11efff7fSkettenis  :group 'gud)
228*11efff7fSkettenis
229*11efff7fSkettenis(defconst gdb-stopped-regexp
230*11efff7fSkettenis  "\\((gdb) \n\\*stopped\\|^\\^done\\),reason=.*,file=\"\\(.*\\)\",line=\"\\(.*\\)\".*")
231*11efff7fSkettenis
232*11efff7fSkettenis(defconst gdb-console-regexp "~\"\\(.*\\)\\\\n\"")
233*11efff7fSkettenis
234*11efff7fSkettenis(defconst gdb-internals-regexp "&\".*\\n\"\n")
235*11efff7fSkettenis
236*11efff7fSkettenis(defconst gdb-gdb-regexp "(gdb) \n")
237*11efff7fSkettenis
238*11efff7fSkettenis(defconst gdb-running-regexp "^\\^running")
239*11efff7fSkettenis
240*11efff7fSkettenis(defun gdbmi-prompt ()
241*11efff7fSkettenis  "This handler terminates the any collection of output. It also
242*11efff7fSkettenis  sends the next command (if any) to gdb."
243*11efff7fSkettenis  (unless gdb-pending-triggers
244*11efff7fSkettenis	(gdb-get-current-frame)
245*11efff7fSkettenis	(gdbmi-invalidate-frames)
246*11efff7fSkettenis	(gdbmi-invalidate-breakpoints)
247*11efff7fSkettenis	(gdbmi-invalidate-locals)
248*11efff7fSkettenis	(dolist (frame (frame-list))
249*11efff7fSkettenis	  (when (string-equal (frame-parameter frame 'name) "Speedbar")
250*11efff7fSkettenis	    (setq gdb-var-changed t)    ; force update
251*11efff7fSkettenis	    (dolist (var gdb-var-list)
252*11efff7fSkettenis	      (setcar (nthcdr 5 var) nil))))
253*11efff7fSkettenis	(gdb-var-update))
254*11efff7fSkettenis  (let ((sink gdb-output-sink))
255*11efff7fSkettenis    (when (eq sink 'emacs)
256*11efff7fSkettenis      (let ((handler
257*11efff7fSkettenis	     (car (cdr gdb-current-item))))
258*11efff7fSkettenis	(with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
259*11efff7fSkettenis	  (funcall handler)))))
260*11efff7fSkettenis  (let ((input (gdb-dequeue-input)))
261*11efff7fSkettenis    (if input
262*11efff7fSkettenis	(gdb-send-item input)
263*11efff7fSkettenis      (progn
264*11efff7fSkettenis	(setq gud-running nil)
265*11efff7fSkettenis	(setq gdb-prompting t)
266*11efff7fSkettenis	(gud-display-frame)))))
267*11efff7fSkettenis
268*11efff7fSkettenis(defun gud-gdbmi-marker-filter (string)
269*11efff7fSkettenis  "Filter GDB/MI output."
270*11efff7fSkettenis  (if gdb-enable-debug-log (push (cons 'recv string) gdb-debug-log))
271*11efff7fSkettenis  ;; Recall the left over gud-marker-acc from last time
272*11efff7fSkettenis  (setq gud-marker-acc (concat gud-marker-acc string))
273*11efff7fSkettenis  ;; Start accumulating output for the GUD buffer
274*11efff7fSkettenis  (let ((output ""))
275*11efff7fSkettenis
276*11efff7fSkettenis    (if (string-match gdb-running-regexp gud-marker-acc)
277*11efff7fSkettenis       (setq gud-marker-acc (substring gud-marker-acc (match-end 0))
278*11efff7fSkettenis	     gud-running t))
279*11efff7fSkettenis
280*11efff7fSkettenis    ;; Remove the trimmings from the console stream.
281*11efff7fSkettenis    (while (string-match gdb-console-regexp gud-marker-acc)
282*11efff7fSkettenis       (setq
283*11efff7fSkettenis	gud-marker-acc (concat (substring gud-marker-acc 0 (match-beginning 0))
284*11efff7fSkettenis			       (match-string 1 gud-marker-acc)
285*11efff7fSkettenis			       (substring gud-marker-acc (match-end 0)))))
286*11efff7fSkettenis
287*11efff7fSkettenis    ;; Remove log stream containing debugging messages being produced by GDB's
288*11efff7fSkettenis    ;; internals.
289*11efff7fSkettenis    (while (string-match gdb-internals-regexp gud-marker-acc)
290*11efff7fSkettenis       (setq
291*11efff7fSkettenis	 gud-marker-acc (concat (substring gud-marker-acc 0 (match-beginning 0))
292*11efff7fSkettenis				(substring gud-marker-acc (match-end 0)))))
293*11efff7fSkettenis
294*11efff7fSkettenis    (if (string-match gdb-stopped-regexp gud-marker-acc)
295*11efff7fSkettenis      (setq
296*11efff7fSkettenis
297*11efff7fSkettenis       ;; Extract the frame position from the marker.
298*11efff7fSkettenis       gud-last-frame (cons (match-string 2 gud-marker-acc)
299*11efff7fSkettenis			    (string-to-int (match-string 3 gud-marker-acc)))
300*11efff7fSkettenis
301*11efff7fSkettenis       ;; Append any text before the marker to the output we're going
302*11efff7fSkettenis       ;; to return - we don't include the marker in this text.
303*11efff7fSkettenis       output (gdbmi-concat-output output
304*11efff7fSkettenis		      (substring gud-marker-acc 0 (match-beginning 0)))
305*11efff7fSkettenis
306*11efff7fSkettenis       ;; Set the accumulator to the remaining text.
307*11efff7fSkettenis       gud-marker-acc (substring gud-marker-acc (match-end 0))))
308*11efff7fSkettenis
309*11efff7fSkettenis    (while (string-match gdb-gdb-regexp gud-marker-acc)
310*11efff7fSkettenis      (setq
311*11efff7fSkettenis
312*11efff7fSkettenis       ;; Append any text up to and including prompt less \n to the output.
313*11efff7fSkettenis       output (gdbmi-concat-output output
314*11efff7fSkettenis		      (substring gud-marker-acc 0 (- (match-end 0) 1)))
315*11efff7fSkettenis
316*11efff7fSkettenis       ;; Set the accumulator to the remaining text.
317*11efff7fSkettenis       gud-marker-acc (substring gud-marker-acc (match-end 0)))
318*11efff7fSkettenis      (gdbmi-prompt))
319*11efff7fSkettenis
320*11efff7fSkettenis    (setq output (gdbmi-concat-output output gud-marker-acc))
321*11efff7fSkettenis    (setq gud-marker-acc "")
322*11efff7fSkettenis    output))
323*11efff7fSkettenis
324*11efff7fSkettenis(defun gdbmi-concat-output (so-far new)
325*11efff7fSkettenis  (let ((sink gdb-output-sink))
326*11efff7fSkettenis    (cond
327*11efff7fSkettenis     ((eq sink 'user) (concat so-far new))
328*11efff7fSkettenis     ((eq sink 'emacs)
329*11efff7fSkettenis      (gdb-append-to-partial-output new)
330*11efff7fSkettenis      so-far)
331*11efff7fSkettenis     ((eq sink 'inferior)
332*11efff7fSkettenis      (gdb-append-to-inferior-io new)
333*11efff7fSkettenis      so-far))))
334*11efff7fSkettenis
335*11efff7fSkettenis
336*11efff7fSkettenis;; Breakpoint buffer : This displays the output of `-break-list'.
337*11efff7fSkettenis;;
338*11efff7fSkettenis(def-gdb-auto-updated-buffer gdb-breakpoints-buffer
339*11efff7fSkettenis  ;; This defines the auto update rule for buffers of type
340*11efff7fSkettenis  ;; `gdb-breakpoints-buffer'.
341*11efff7fSkettenis  ;;
342*11efff7fSkettenis  ;; It defines a function that queues the command below.  That function is
343*11efff7fSkettenis  ;; called:
344*11efff7fSkettenis  gdbmi-invalidate-breakpoints
345*11efff7fSkettenis  ;;
346*11efff7fSkettenis  ;; To update the buffer, this command is sent to gdb.
347*11efff7fSkettenis  "-break-list\n"
348*11efff7fSkettenis  ;;
349*11efff7fSkettenis  ;; This also defines a function to be the handler for the output
350*11efff7fSkettenis  ;; from the command above.  That function will copy the output into
351*11efff7fSkettenis  ;; the appropriately typed buffer.  That function will be called:
352*11efff7fSkettenis  gdb-break-list-handler
353*11efff7fSkettenis  ;; buffer specific functions
354*11efff7fSkettenis  gdb-break-list-custom)
355*11efff7fSkettenis
356*11efff7fSkettenis(defconst gdb-break-list-regexp
357*11efff7fSkettenis"number=\"\\(.*?\\)\",type=\"\\(.*?\\)\",disp=\"\\(.*?\\)\",enabled=\"\\(.\\)\",addr=\"\\(.*?\\)\",func=\"\\(.*?\\)\",file=\"\\(.*?\\)\",line=\"\\(.*?\\)\"")
358*11efff7fSkettenis
359*11efff7fSkettenis(defun gdb-break-list-handler ()
360*11efff7fSkettenis  (setq gdb-pending-triggers (delq 'gdbmi-invalidate-breakpoints
361*11efff7fSkettenis				  gdb-pending-triggers))
362*11efff7fSkettenis  (let ((breakpoint nil)
363*11efff7fSkettenis	(breakpoints-list nil))
364*11efff7fSkettenis    (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
365*11efff7fSkettenis      (goto-char (point-min))
366*11efff7fSkettenis      (while (re-search-forward gdb-break-list-regexp nil t)
367*11efff7fSkettenis	(let ((breakpoint (list (match-string 1)
368*11efff7fSkettenis				(match-string 2)
369*11efff7fSkettenis				(match-string 3)
370*11efff7fSkettenis				(match-string 4)
371*11efff7fSkettenis				(match-string 5)
372*11efff7fSkettenis				(match-string 6)
373*11efff7fSkettenis				(match-string 7)
374*11efff7fSkettenis				(match-string 8))))
375*11efff7fSkettenis	  (push breakpoint breakpoints-list))))
376*11efff7fSkettenis    (let ((buf (gdb-get-buffer 'gdb-breakpoints-buffer)))
377*11efff7fSkettenis      (and buf (with-current-buffer buf
378*11efff7fSkettenis		 (let ((p (point))
379*11efff7fSkettenis		       (buffer-read-only nil))
380*11efff7fSkettenis		   (erase-buffer)
381*11efff7fSkettenis		   (insert "Num Type        Disp Enb Func\tFile:Line\tAddr\n")
382*11efff7fSkettenis		   (dolist (breakpoint breakpoints-list)
383*11efff7fSkettenis		     (insert (concat
384*11efff7fSkettenis			      (nth 0 breakpoint) "   "
385*11efff7fSkettenis			      (nth 1 breakpoint) "  "
386*11efff7fSkettenis			      (nth 2 breakpoint) "   "
387*11efff7fSkettenis			      (nth 3 breakpoint) " "
388*11efff7fSkettenis			      (nth 5 breakpoint) "\t"
389*11efff7fSkettenis			      (nth 6 breakpoint) ":" (nth 7 breakpoint) "\t"
390*11efff7fSkettenis			      (nth 4 breakpoint) "\n")))
391*11efff7fSkettenis		   (goto-char p))))))
392*11efff7fSkettenis  (gdb-break-list-custom))
393*11efff7fSkettenis
394*11efff7fSkettenis;;-put breakpoint icons in relevant margins (even those set in the GUD buffer)
395*11efff7fSkettenis(defun gdb-break-list-custom ()
396*11efff7fSkettenis  (let ((flag)(address))
397*11efff7fSkettenis    ;;
398*11efff7fSkettenis    ;; remove all breakpoint-icons in source buffers but not assembler buffer
399*11efff7fSkettenis    (dolist (buffer (buffer-list))
400*11efff7fSkettenis      (with-current-buffer buffer
401*11efff7fSkettenis	(if (and (eq gud-minor-mode 'gdbmi)
402*11efff7fSkettenis		 (not (string-match "\\`\\*.+\\*\\'" (buffer-name))))
403*11efff7fSkettenis	    (gdb-remove-breakpoint-icons (point-min) (point-max)))))
404*11efff7fSkettenis    (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
405*11efff7fSkettenis      (save-excursion
406*11efff7fSkettenis	(goto-char (point-min))
407*11efff7fSkettenis	(while (< (point) (- (point-max) 1))
408*11efff7fSkettenis	  (forward-line 1)
409*11efff7fSkettenis	  (if (looking-at "[0-9]*\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)\\s-*\\S-*\\s-*\\(\\S-*\\):\\([0-9]+\\)")
410*11efff7fSkettenis	      (progn
411*11efff7fSkettenis		(setq flag (char-after (match-beginning 1)))
412*11efff7fSkettenis		(let ((line (match-string 3)) (buffer-read-only nil)
413*11efff7fSkettenis		      (file (match-string 2)))
414*11efff7fSkettenis		  (add-text-properties (point-at-bol) (point-at-eol)
415*11efff7fSkettenis				       '(mouse-face highlight
416*11efff7fSkettenis						    help-echo "mouse-2, RET: visit breakpoint"))
417*11efff7fSkettenis		  (with-current-buffer
418*11efff7fSkettenis		      (find-file-noselect
419*11efff7fSkettenis		       (if (file-exists-p file) file
420*11efff7fSkettenis			 (expand-file-name file gdb-cdir)))
421*11efff7fSkettenis		    (save-current-buffer
422*11efff7fSkettenis		      (set (make-local-variable 'gud-minor-mode) 'gdbmi)
423*11efff7fSkettenis		      (set (make-local-variable 'tool-bar-map)
424*11efff7fSkettenis			   gud-tool-bar-map))
425*11efff7fSkettenis		    ;; only want one breakpoint icon at each location
426*11efff7fSkettenis		    (save-excursion
427*11efff7fSkettenis		      (goto-line (string-to-number line))
428*11efff7fSkettenis		      (gdb-put-breakpoint-icon (eq flag ?y)))))))))
429*11efff7fSkettenis	  (end-of-line)))
430*11efff7fSkettenis  (if (gdb-get-buffer 'gdb-assembler-buffer) (gdb-assembler-custom)))
431*11efff7fSkettenis
432*11efff7fSkettenis;; Frames buffer.  This displays a perpetually correct bactrack trace.
433*11efff7fSkettenis;;
434*11efff7fSkettenis(def-gdb-auto-updated-buffer gdb-stack-buffer
435*11efff7fSkettenis  gdbmi-invalidate-frames
436*11efff7fSkettenis  "-stack-list-frames\n"
437*11efff7fSkettenis  gdb-stack-list-frames-handler
438*11efff7fSkettenis  gdb-stack-list-frames-custom)
439*11efff7fSkettenis
440*11efff7fSkettenis(defconst gdb-stack-list-frames-regexp
441*11efff7fSkettenis"level=\"\\(.*?\\)\",addr=\"\\(.*?\\)\",func=\"\\(.*?\\)\",file=\"\\(.*?\\)\",line=\"\\(.*?\\)\"")
442*11efff7fSkettenis
443*11efff7fSkettenis(defun gdb-stack-list-frames-handler ()
444*11efff7fSkettenis  (setq gdb-pending-triggers (delq 'gdbmi-invalidate-frames
445*11efff7fSkettenis				  gdb-pending-triggers))
446*11efff7fSkettenis  (let ((frame nil)
447*11efff7fSkettenis	(call-stack nil))
448*11efff7fSkettenis    (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
449*11efff7fSkettenis      (goto-char (point-min))
450*11efff7fSkettenis      (while (re-search-forward gdb-stack-list-frames-regexp nil t)
451*11efff7fSkettenis	(let ((frame (list (match-string 1)
452*11efff7fSkettenis			   (match-string 2)
453*11efff7fSkettenis			   (match-string 3)
454*11efff7fSkettenis			   (match-string 4)
455*11efff7fSkettenis			   (match-string 5))))
456*11efff7fSkettenis	  (push frame call-stack))))
457*11efff7fSkettenis    (let ((buf (gdb-get-buffer 'gdb-stack-buffer)))
458*11efff7fSkettenis      (and buf (with-current-buffer buf
459*11efff7fSkettenis		 (let ((p (point))
460*11efff7fSkettenis		       (buffer-read-only nil))
461*11efff7fSkettenis		   (erase-buffer)
462*11efff7fSkettenis		   (insert "Level\tFunc\tFile:Line\tAddr\n")
463*11efff7fSkettenis		   (dolist (frame (nreverse call-stack))
464*11efff7fSkettenis		     (insert (concat
465*11efff7fSkettenis			      (nth 0 frame) "\t"
466*11efff7fSkettenis			      (nth 2 frame) "\t"
467*11efff7fSkettenis			      (nth 3 frame) ":" (nth 4 frame) "\t"
468*11efff7fSkettenis			      (nth 1 frame) "\n")))
469*11efff7fSkettenis		   (goto-char p))))))
470*11efff7fSkettenis  (gdb-stack-list-frames-custom))
471*11efff7fSkettenis
472*11efff7fSkettenis(defun gdb-stack-list-frames-custom ()
473*11efff7fSkettenis  (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
474*11efff7fSkettenis    (save-excursion
475*11efff7fSkettenis      (let ((buffer-read-only nil))
476*11efff7fSkettenis	(goto-char (point-min))
477*11efff7fSkettenis	(forward-line 1)
478*11efff7fSkettenis	(while (< (point) (point-max))
479*11efff7fSkettenis	  (add-text-properties (point-at-bol) (point-at-eol)
480*11efff7fSkettenis			     '(mouse-face highlight
481*11efff7fSkettenis			       help-echo "mouse-2, RET: Select frame"))
482*11efff7fSkettenis	  (beginning-of-line)
483*11efff7fSkettenis	  (when (and (or (looking-at "^#[0-9]*\\s-*\\S-* in \\(\\S-*\\)")
484*11efff7fSkettenis			 (looking-at "^#[0-9]*\\s-*\\(\\S-*\\)"))
485*11efff7fSkettenis		     (equal (match-string 1) gdb-current-frame))
486*11efff7fSkettenis	    (put-text-property (point-at-bol) (point-at-eol)
487*11efff7fSkettenis			       'face '(:inverse-video t)))
488*11efff7fSkettenis	  (forward-line 1))))))
489*11efff7fSkettenis
490*11efff7fSkettenis;; Locals buffer.
491*11efff7fSkettenis;; uses "-stack-list-locals 2". Needs GDB 6.1 onwards.
492*11efff7fSkettenis(def-gdb-auto-updated-buffer gdb-locals-buffer
493*11efff7fSkettenis  gdbmi-invalidate-locals
494*11efff7fSkettenis  "-stack-list-locals 2\n"
495*11efff7fSkettenis  gdb-stack-list-locals-handler
496*11efff7fSkettenis  gdb-stack-list-locals-custom)
497*11efff7fSkettenis
498*11efff7fSkettenis(defconst gdb-stack-list-locals-regexp
499*11efff7fSkettenis  (concat "name=\"\\(.*?\\)\",type=\"\\(.*?\\)\""))
500*11efff7fSkettenis
501*11efff7fSkettenis;; Dont display values of arrays or structures.
502*11efff7fSkettenis;; These can be expanded using gud-watch.
503*11efff7fSkettenis(defun gdb-stack-list-locals-handler nil
504*11efff7fSkettenis  (setq gdb-pending-triggers (delq 'gdbmi-invalidate-locals
505*11efff7fSkettenis				  gdb-pending-triggers))
506*11efff7fSkettenis  (let ((local nil)
507*11efff7fSkettenis	(locals-list nil))
508*11efff7fSkettenis    (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
509*11efff7fSkettenis      (goto-char (point-min))
510*11efff7fSkettenis      (while (re-search-forward gdb-stack-list-locals-regexp nil t)
511*11efff7fSkettenis	(let ((local (list (match-string 1)
512*11efff7fSkettenis			   (match-string 2)
513*11efff7fSkettenis			   nil)))
514*11efff7fSkettenis	  (if (looking-at ",value=\"\\(.*?\\)\"")
515*11efff7fSkettenis	      (setcar (nthcdr 2 local) (match-string 1)))
516*11efff7fSkettenis	(push local locals-list))))
517*11efff7fSkettenis    (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
518*11efff7fSkettenis      (and buf (with-current-buffer buf
519*11efff7fSkettenis		 (let ((p (point))
520*11efff7fSkettenis		       (buffer-read-only nil))
521*11efff7fSkettenis		   (erase-buffer)
522*11efff7fSkettenis		   (dolist (local locals-list)
523*11efff7fSkettenis		     (insert
524*11efff7fSkettenis		      (concat (car local) "\t" (nth 1 local) "\t"
525*11efff7fSkettenis			      (or (nth 2 local)
526*11efff7fSkettenis				  (if (string-match "struct" (nth 1 local))
527*11efff7fSkettenis				      "(structure)"
528*11efff7fSkettenis				    "(array)"))
529*11efff7fSkettenis			      "\n")))
530*11efff7fSkettenis		   (goto-char p)))))))
531*11efff7fSkettenis
532*11efff7fSkettenis(defun gdb-stack-list-locals-custom ()
533*11efff7fSkettenis  nil)
534*11efff7fSkettenis
535*11efff7fSkettenis(defun gdbmi-source-info ()
536*11efff7fSkettenis  "Find the source file where the program starts and displays it with related
537*11efff7fSkettenisbuffers."
538*11efff7fSkettenis  (goto-char (point-min))
539*11efff7fSkettenis  (if (search-forward "source file is " nil t)
540*11efff7fSkettenis      (if (looking-at "\\S-*")
541*11efff7fSkettenis	  (setq gdb-main-file (match-string 0)))
542*11efff7fSkettenis    (setq gdb-view-source nil))
543*11efff7fSkettenis  (if (search-forward "directory is " nil t)
544*11efff7fSkettenis      (if (looking-at "\\S-*:\\(\\S-*\\)")
545*11efff7fSkettenis	  (setq gdb-cdir (match-string 1))
546*11efff7fSkettenis	(looking-at "\\S-*")
547*11efff7fSkettenis	(setq gdb-cdir (match-string 0))))
548*11efff7fSkettenis
549*11efff7fSkettenis;temporary heuristic
550*11efff7fSkettenis  (if gdb-main-file
551*11efff7fSkettenis      (setq gdb-main-file (expand-file-name gdb-main-file gdb-cdir)))
552*11efff7fSkettenis
553*11efff7fSkettenis  (if gdb-many-windows
554*11efff7fSkettenis      (gdb-setup-windows)
555*11efff7fSkettenis    (gdb-get-create-buffer 'gdb-breakpoints-buffer)
556*11efff7fSkettenis    (when gdb-show-main
557*11efff7fSkettenis      (switch-to-buffer gud-comint-buffer)
558*11efff7fSkettenis      (delete-other-windows)
559*11efff7fSkettenis      (split-window)
560*11efff7fSkettenis      (other-window 1)
561*11efff7fSkettenis      (switch-to-buffer
562*11efff7fSkettenis       (if gdb-view-source
563*11efff7fSkettenis	   (gud-find-file gdb-main-file)
564*11efff7fSkettenis	 (gdb-get-create-buffer 'gdb-assembler-buffer)))
565*11efff7fSkettenis      (other-window 1))))
566*11efff7fSkettenis
567*11efff7fSkettenis(provide 'gdb-mi)
568*11efff7fSkettenis;;; gdbmi.el ends here
569