|
|
1.1 root 1: ;; Run gdb under Emacs
2: ;; Author: W. Schelter, University of Texas
3: ;; [email protected]
4: ;; Rewritten by rms.
5:
6: ;; Some ideas are due to Masanobu.
7:
8: ;; This file is part of GNU Emacs.
9: ;; Copyright (C) 1988 Free Software Foundation, Inc.
10:
11: ;; GNU Emacs is distributed in the hope that it will be useful, but
12: ;; WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
13: ;; to anyone for the consequences of using it or for whether it serves
14: ;; any particular purpose or works at all, unless he says so in writing.
15: ;; Refer to the GNU Emacs General Public License for full details.
16:
17: ;; Everyone is granted permission to copy, modify and redistribute GNU
18: ;; Emacs, but only under the conditions described in the GNU Emacs
19: ;; General Public License. A copy of this license is supposed to have
20: ;; been given to you along with GNU Emacs so you can know your rights and
21: ;; responsibilities. It should be in a file named COPYING. Among other
22: ;; things, the copyright notice and this notice must be preserved on all
23: ;; copies.
24:
25: ;; Description of GDB interface:
26:
27: ;; A facility is provided for the simultaneous display of the source code
28: ;; in one window, while using gdb to step through a function in the
29: ;; other. A small arrow in the source window, indicates the current
30: ;; line.
31:
32: ;; Starting up:
33:
34: ;; In order to use this facility, invoke the command GDB to obtain a
35: ;; shell window with the appropriate command bindings. You will be asked
36: ;; for the name of a file to run. Gdb will be invoked on this file, in a
37: ;; window named *gdb-foo* if the file is foo.
38:
39: ;; M-s steps by one line, and redisplays the source file and line.
40:
41: ;; You may easily create additional commands and bindings to interact
42: ;; with the display. For example to put the gdb command next on \M-n
43: ;; (def-gdb next "\M-n")
44:
45: ;; This causes the emacs command gdb-next to be defined, and runs
46: ;; gdb-display-frame after the command.
47:
48: ;; gdb-display-frame is the basic display function. It tries to display
49: ;; in the other window, the file and line corresponding to the current
50: ;; position in the gdb window. For example after a gdb-step, it would
51: ;; display the line corresponding to the position for the last step. Or
52: ;; if you have done a backtrace in the gdb buffer, and move the cursor
53: ;; into one of the frames, it would display the position corresponding to
54: ;; that frame.
55:
56: ;; gdb-display-frame is invoked automatically when a filename-and-line-number
57: ;; appears in the output.
58:
59:
60: (require 'shell)
61:
62: (defvar gdb-prompt-pattern "^(.*gdb[+]?) *"
63: "A regexp to recognize the prompt for gdb or gdb+.")
64:
65: (defvar gdb-mode-map nil
66: "Keymap for gdb-mode.")
67:
68: (if gdb-mode-map
69: nil
70: (setq gdb-mode-map (copy-keymap shell-mode-map))
71: (define-key gdb-mode-map "\C-l" 'gdb-refresh))
72:
73: (define-key ctl-x-map " " 'gdb-break)
74: (define-key ctl-x-map "&" 'send-gdb-command)
75:
76: ;;Of course you may use `def-gdb' with any other gdb command, including
77: ;;user defined ones.
78:
79: (defmacro def-gdb (name key &optional doc)
80: (let* ((fun (intern (format "gdb-%s" name)))
81: (cstr (list 'if '(not (= 1 arg))
82: (list 'format "%s %s" name 'arg)
83: name)))
84: (list 'progn
85: (list 'defun fun '(arg)
86: (or doc "")
87: '(interactive "p")
88: (list 'gdb-call cstr))
89: (list 'define-key 'gdb-mode-map key (list 'quote fun)))))
90:
91: (def-gdb "step" "\M-s" "Step one source line with display")
92: (def-gdb "stepi" "\M-i" "Step one instruction with display")
93: (def-gdb "next" "\M-n" "Step one source line (skip functions)")
94: (def-gdb "cont" "\M-c" "Continue with display")
95:
96: (def-gdb "finish" "\C-c\C-f" "Finish executing current function")
97: (def-gdb "up" "\M-u" "Go up N stack frames (numeric arg) with display")
98: (def-gdb "down" "\M-d" "Go down N stack frames (numeric arg) with display")
99:
100: (defun gdb-mode ()
101: "Major mode for interacting with an inferior Gdb process.
102: The following commands are available:
103:
104: \\{gdb-mode-map}
105:
106: \\[gdb-display-frame] displays in the other window
107: the last line referred to in the gdb buffer.
108:
109: \\[gdb-step],\\[gdb-next], and \\[gdb-nexti] in the gdb window,
110: call gdb to step,next or nexti and then update the other window
111: with the current file and position.
112:
113: If you are in a source file, you may select a point to break
114: at, by doing \\[gdb-break].
115:
116: Commands:
117: Many commands are inherited from shell mode.
118: Additionally we have:
119:
120: \\[gdb-display-frame] display frames file in other window
121: \\[gdb-step] advance one line in program
122: \\[gdb-next] advance one line in program (skip over calls).
123: \\[send-gdb-command] used for special printing of an arg at the current point.
124: C-x SPACE sets break point at current line."
125: (interactive)
126: (kill-all-local-variables)
127: (setq major-mode 'gdb-mode)
128: (setq mode-name "Inferior Gdb")
129: (setq mode-line-process '(": %s"))
130: (use-local-map gdb-mode-map)
131: (make-local-variable 'last-input-start)
132: (setq last-input-start (make-marker))
133: (make-local-variable 'last-input-end)
134: (setq last-input-end (make-marker))
135: (make-local-variable 'gdb-last-frame)
136: (setq gdb-last-frame nil)
137: (make-local-variable 'gdb-last-frame-displayed-p)
138: (setq gdb-last-frame-displayed-p t)
139: (make-local-variable 'gdb-delete-prompt-marker)
140: (setq gdb-delete-prompt-marker nil)
141: (make-local-variable 'gdb-filter-accumulator)
142: (setq gdb-filter-accumulator nil)
143: (make-local-variable 'shell-prompt-pattern)
144: (setq shell-prompt-pattern gdb-prompt-pattern)
145: (run-hooks 'shell-mode-hook 'gdb-mode-hook))
146:
147: (defvar current-gdb-buffer nil)
148:
149: (defvar gdb-command-name "gdb"
150: "Pathname for executing gdb.")
151:
152: (defun gdb (path)
153: "Run gdb on program FILE in buffer *gdb-FILE*.
154: The directory containing FILE becomes the initial working directory
155: and source-file directory for GDB. If you wish to change this, use
156: the GDB commands `cd DIR' and `directory'."
157: (interactive "FRun gdb on file: ")
158: (setq path (expand-file-name path))
159: (let ((file (file-name-nondirectory path)))
160: (switch-to-buffer (concat "*gdb-" file "*"))
161: (setq default-directory (file-name-directory path))
162: (or (bolp) (newline))
163: (insert "Current directory is " default-directory "\n")
164: (make-shell (concat "gdb-" file) gdb-command-name nil "-fullname"
165: "-cd" default-directory file)
166: (gdb-mode)
167: (set-process-filter (get-buffer-process (current-buffer)) 'gdb-filter)
168: (set-process-sentinel (get-buffer-process (current-buffer)) 'gdb-sentinel)
169: (gdb-set-buffer)))
170:
171: (defun gdb-set-buffer ()
172: (cond ((eq major-mode 'gdb-mode)
173: (setq current-gdb-buffer (current-buffer)))))
174:
175: ;; This function is responsible for inserting output from GDB
176: ;; into the buffer.
177: ;; Aside from inserting the text, it notices and deletes
178: ;; each filename-and-line-number;
179: ;; that GDB prints to identify the selected frame.
180: ;; It records the filename and line number, and maybe displays that file.
181: (defun gdb-filter (proc string)
182: (let ((inhibit-quit t))
183: (if gdb-filter-accumulator
184: (gdb-filter-accumulate-marker proc
185: (concat gdb-filter-accumulator string))
186: (gdb-filter-scan-input proc string))))
187:
188: (defun gdb-filter-accumulate-marker (proc string)
189: (setq gdb-filter-accumulator nil)
190: (if (> (length string) 1)
191: (if (= (aref string 1) ?\032)
192: (let ((end (string-match "\n" string)))
193: (if end
194: (progn
195: (let* ((first-colon (string-match ":" string 2))
196: (second-colon
197: (string-match ":" string (1+ first-colon))))
198: (setq gdb-last-frame
199: (cons (substring string 2 first-colon)
200: (string-to-int
201: (substring string (1+ first-colon)
202: second-colon)))))
203: (setq gdb-last-frame-displayed-p nil)
204: (gdb-filter-scan-input proc
205: (substring string (1+ end))))
206: (setq gdb-filter-accumulator string)))
207: (gdb-filter-insert proc "\032")
208: (gdb-filter-scan-input proc (substring string 1)))
209: (setq gdb-filter-accumulator string)))
210:
211: (defun gdb-filter-scan-input (proc string)
212: (if (equal string "")
213: (setq gdb-filter-accumulator nil)
214: (let ((start (string-match "\032" string)))
215: (if start
216: (progn (gdb-filter-insert proc (substring string 0 start))
217: (gdb-filter-accumulate-marker proc
218: (substring string start)))
219: (gdb-filter-insert proc string)))))
220:
221: (defun gdb-filter-insert (proc string)
222: (let ((moving (= (point) (process-mark proc)))
223: (output-after-point (< (point) (process-mark proc)))
224: (old-buffer (current-buffer))
225: start)
226: (set-buffer (process-buffer proc))
227: (unwind-protect
228: (save-excursion
229: ;; Insert the text, moving the process-marker.
230: (goto-char (process-mark proc))
231: (setq start (point))
232: (insert string)
233: (set-marker (process-mark proc) (point))
234: (gdb-maybe-delete-prompt)
235: ;; Check for a filename-and-line number.
236: (gdb-display-frame
237: ;; Don't display the specified file
238: ;; unless (1) point is at or after the position where output appears
239: ;; and (2) this buffer is on the screen.
240: (or output-after-point
241: (not (get-buffer-window (current-buffer))))
242: ;; Display a file only when a new filename-and-line-number appears.
243: t))
244: (set-buffer old-buffer))
245: (if moving (goto-char (process-mark proc)))))
246:
247: (defun gdb-sentinel (proc msg)
248: (cond ((null (buffer-name (process-buffer proc)))
249: ;; buffer killed
250: ;; Stop displaying an arrow in a source file.
251: (setq overlay-arrow-position nil)
252: (set-process-buffer proc nil))
253: ((memq (process-status proc) '(signal exit))
254: ;; Stop displaying an arrow in a source file.
255: (setq overlay-arrow-position nil)
256: ;; Fix the mode line.
257: (setq mode-line-process
258: (concat ": "
259: (symbol-name (process-status proc))))
260: (let* ((obuf (current-buffer)))
261: ;; save-excursion isn't the right thing if
262: ;; process-buffer is current-buffer
263: (unwind-protect
264: (progn
265: ;; Write something in *compilation* and hack its mode line,
266: (set-buffer (process-buffer proc))
267: ;; Force mode line redisplay soon
268: (set-buffer-modified-p (buffer-modified-p))
269: (if (eobp)
270: (insert ?\n mode-name " " msg)
271: (save-excursion
272: (goto-char (point-max))
273: (insert ?\n mode-name " " msg)))
274: ;; If buffer and mode line will show that the process
275: ;; is dead, we can delete it now. Otherwise it
276: ;; will stay around until M-x list-processes.
277: (delete-process proc))
278: ;; Restore old buffer, but don't restore old point
279: ;; if obuf is the gdb buffer.
280: (set-buffer obuf))))))
281:
282:
283: (defun gdb-refresh ()
284: "Fix up a possibly garbled display, and redraw the arrow."
285: (interactive)
286: (redraw-display)
287: (gdb-display-frame))
288:
289: (defun gdb-display-frame (&optional nodisplay noauto)
290: "Find, obey and delete the last filename-and-line marker from GDB.
291: The marker looks like \\032\\032FILENAME:LINE:CHARPOS\\n.
292: Obeying it means displaying in another window the specified file and line."
293: (interactive)
294: (gdb-set-buffer)
295: (and gdb-last-frame (not nodisplay)
296: (or (not gdb-last-frame-displayed-p) (not noauto))
297: (progn (gdb-display-line (car gdb-last-frame) (cdr gdb-last-frame))
298: (setq gdb-last-frame-displayed-p t))))
299:
300: ;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen
301: ;; and that its line LINE is visible.
302: ;; Put the overlay-arrow on the line LINE in that buffer.
303:
304: (defun gdb-display-line (true-file line)
305: (let* ((buffer (find-file-noselect true-file))
306: (window (display-buffer buffer t))
307: (pos))
308: (save-excursion
309: (set-buffer buffer)
310: (save-restriction
311: (widen)
312: (goto-line line)
313: (setq pos (point))
314: (setq overlay-arrow-string "=>")
315: (or overlay-arrow-position
316: (setq overlay-arrow-position (make-marker)))
317: (set-marker overlay-arrow-position (point) (current-buffer)))
318: (cond ((or (< pos (point-min)) (> pos (point-max)))
319: (widen)
320: (goto-char pos))))
321: (set-window-point window overlay-arrow-position)))
322:
323: (defun gdb-call (command)
324: "Invoke gdb COMMAND displaying source in other window."
325: (interactive)
326: (goto-char (point-max))
327: (setq gdb-delete-prompt-marker (point-marker))
328: (gdb-set-buffer)
329: (send-string (get-buffer-process current-gdb-buffer)
330: (concat command "\n")))
331:
332: (defun gdb-maybe-delete-prompt ()
333: (if (and gdb-delete-prompt-marker
334: (> (point-max) (marker-position gdb-delete-prompt-marker)))
335: (let (start)
336: (goto-char gdb-delete-prompt-marker)
337: (setq start (point))
338: (beginning-of-line)
339: (delete-region (point) start)
340: (setq gdb-delete-prompt-marker nil))))
341:
342: (defun gdb-break ()
343: "Set GDB breakpoint at this source line."
344: (interactive)
345: (let ((file-name (file-name-nondirectory buffer-file-name))
346: (line (save-restriction
347: (widen)
348: (1+ (count-lines 1 (point))))))
349: (send-string (get-buffer-process current-gdb-buffer)
350: (concat "break " file-name ":" line "\n"))))
351:
352: (defun gdb-read-address()
353: "Return a string containing the core-address found in the buffer at point."
354: (save-excursion
355: (let ((pt (dot)) found begin)
356: (setq found (if (search-backward "0x" (- pt 7) t)(dot)))
357: (cond (found (forward-char 2)(setq result
358: (buffer-substring found
359: (progn (re-search-forward "[^0-9a-f]")
360: (forward-char -1)
361: (dot)))))
362: (t (setq begin (progn (re-search-backward "[^0-9]") (forward-char 1)
363: (dot)))
364: (forward-char 1)
365: (re-search-forward "[^0-9]")
366: (forward-char -1)
367: (buffer-substring begin (dot)))))))
368:
369:
370: (defvar gdb-commands nil
371: "List of strings or functions used by send-gdb-command.
372: It is for customization by you.")
373:
374: (defun send-gdb-command (arg)
375:
376: "This command reads the number where the cursor is positioned. It
377: then inserts this ADDR at the end of the gdb buffer. A numeric arg
378: selects the ARG'th member COMMAND of the list gdb-print-command. If
379: COMMAND is a string, (format COMMAND ADDR) is inserted, otherwise
380: (funcall COMMAND ADDR) is inserted. eg. \"p (rtx)%s->fld[0].rtint\"
381: is a possible string to be a member of gdb-commands. "
382:
383:
384: (interactive "P")
385: (let (comm addr)
386: (if arg (setq comm (nth arg gdb-commands)))
387: (setq addr (gdb-read-address))
388: (if (eq (current-buffer) current-gdb-buffer)
389: (set-mark (point)))
390: (cond (comm
391: (setq comm
392: (if (stringp comm) (format comm addr) (funcall comm addr))))
393: (t (setq comm addr)))
394: (switch-to-buffer current-gdb-buffer)
395: (goto-char (dot-max))
396: (insert-string comm)))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.