Discussion:
bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
(too old to reply)
Dov Grobgeld
2012-01-22 12:42:01 UTC
Permalink
This bug report will be sent to the Bug-GNU-Emacs mailing list
and the GNU bug tracker at debbugs.gnu.org. Please check that
the From: line contains a valid email address. After a delay of up
to one day, you should receive an acknowledgement at that address.

Please write in English if possible, as the Emacs maintainers
usually do not have translators for other languages.

Please describe exactly what actions triggered the bug, and
the precise symptoms of the bug. If you can, give a recipe
starting from `emacs -Q':

------------------------------

When trying to running gdb on my process, emacs gets stuck for more than
one minutes while the CPU load is at 100%.
gdb -i=mi SolarJet
=thread-group-added,id="i1"
~"GNU gdb (GDB) Fedora (7.2-52.fc14)\n"
~"Copyright (C) 2010 Free Software Foundation, Inc.\n"
~"License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>\nThis is free software: you are
free to change and redistribute it.\nThere is NO WARRANTY, to the
extent permitted by law. Type \"show copying\"\nand \"show warranty\"
for details.\n"
~"This GDB was configured as \"i686-redhat-linux-gnu\".\nFor bug
reporting instructions, please see:\n"
~"<http://www.gnu.org/software/gdb/bugs/>...\n"
~"Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet..."
~"done.\n"
(gdb)

But as I said, running it by Meta-x gdb SolarJet yields the following
message, and then emacs gets stuck for more than one minute:

Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet...done.

Note that in earlier versions of emacs (23.2.1), the gdb prompt was
received immediately after the done message has been shown.

---------------------------------


If Emacs crashed, and you have the Emacs process in the gdb debugger,
please include the output from the following gdb commands:
`bt full' and `xbacktrace'.
For information about debugging Emacs, please read the file
/usr/local/public-dev/share/emacs/24.0.92/etc/DEBUG.


In GNU Emacs 24.0.92.1 (i686-pc-linux-gnu, GTK+ Version 2.22.0)
of 2012-01-22 on dovg32
Windowing system distributor `Fedora Project', version 11.0.10905000
configured using `configure '--prefix=/usr/local/public-dev''

Important settings:
value of $LC_ALL: nil
value of $LC_COLLATE: nil
value of $LC_CTYPE: nil
value of $LC_MESSAGES: nil
value of $LC_MONETARY: nil
value of $LC_NUMERIC: nil
value of $LC_TIME: nil
value of $LANG: en_US.utf8
value of $XMODIFIERS: nil
locale-coding-system: utf-8-unix
default enable-multibyte-characters: t

Major mode: Dired by name

Minor modes in effect:
show-paren-mode: t
shell-dirtrack-mode: t
csv-field-index-mode: t
xmsi-mode: t
diff-auto-refine-mode: t
delete-selection-mode: t
tooltip-mode: t
mouse-wheel-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
column-number-mode: t
line-number-mode: t
transient-mark-mode: t

Recent input:

Recent messages:
No previous history command
The program is not being run.
Quit [2 times]
Mark set
Error during redisplay: (void-variable font-lock-shell-prompt-face)
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt
Error during redisplay: (void-variable font-lock-shell-prompt-face) [2 times]
Error during redisplay: (void-variable font-lock-shell-cmd-args-face) [14 times]
Error during redisplay: (void-variable font-lock-shell-prompt-face)
gud-query-cmdline: Command attempted to use minibuffer while in minibuffer

Load-path shadows:
/home/dov/.config/emacs/longlines hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/longlines
/home/dov/.config/emacs/cedet/common/ezimage hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/ezimage
/home/dov/.config/emacs/cedet/speedbar/sb-image hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/sb-image
/home/dov/.config/emacs/cedet/speedbar/dframe hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/dframe
/home/dov/.config/emacs/cedet/speedbar/speedbar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/speedbar
/home/dov/.config/emacs/octave-inf hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/octave-inf
/home/dov/.config/emacs/gdb-mi hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/gdb-mi
/home/dov/.config/emacs/octave-mod hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/octave-mod
/home/dov/.config/emacs/compile hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/compile
/home/dov/.config/emacs/org-mode/ob-org hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-org
/home/dov/.config/emacs/org-mode/org-attach hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-attach
/home/dov/.config/emacs/org-mode/ob-lilypond hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lilypond
/home/dov/.config/emacs/org-mode/org-remember hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-remember
/home/dov/.config/emacs/org-mode/org-bbdb hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-bbdb
/home/dov/.config/emacs/org-mode/org-mhe hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mhe
/home/dov/.config/emacs/org-mode/org-src hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-src
/home/dov/.config/emacs/org-mode/org-wl hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-wl
/home/dov/.config/emacs/org-mode/ob-table hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-table
/home/dov/.config/emacs/org-mode/ob-comint hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-comint
/home/dov/.config/emacs/org-mode/ob-mscgen hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-mscgen
/home/dov/.config/emacs/org-mode/org-ascii hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-ascii
/home/dov/.config/emacs/org-mode/org-freemind hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-freemind
/home/dov/.config/emacs/org-mode/org-w3m hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-w3m
/home/dov/.config/emacs/org-mode/org-compat hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-compat
/home/dov/.config/emacs/org-mode/ob-screen hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-screen
/home/dov/.config/emacs/org-mode/ob-matlab hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-matlab
/home/dov/.config/emacs/org-mode/ob-keys hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-keys
/home/dov/.config/emacs/org-mode/ob-asymptote hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-asymptote
/home/dov/.config/emacs/org-mode/ob-emacs-lisp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-emacs-lisp
/home/dov/.config/emacs/org-mode/org-archive hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-archive
/home/dov/.config/emacs/org-mode/org-docbook hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-docbook
/home/dov/.config/emacs/org-mode/org-list hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-list
/home/dov/.config/emacs/org-mode/ob-ditaa hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ditaa
/home/dov/.config/emacs/org-mode/ob-C hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-C
/home/dov/.config/emacs/org-mode/org-exp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-exp
/home/dov/.config/emacs/org-mode/ob-exp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-exp
/home/dov/.config/emacs/org-mode/ob-ocaml hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ocaml
/home/dov/.config/emacs/org-mode/org-faces hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-faces
/home/dov/.config/emacs/org-mode/org-entities hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-entities
/home/dov/.config/emacs/org-mode/ob-perl hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-perl
/home/dov/.config/emacs/org-mode/org-footnote hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-footnote
/home/dov/.config/emacs/org-mode/org-info hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-info
/home/dov/.config/emacs/org-mode/org-exp-blocks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-exp-blocks
/home/dov/.config/emacs/org-mode/org-inlinetask hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-inlinetask
/home/dov/.config/emacs/org-mode/ob-ruby hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ruby
/home/dov/.config/emacs/org-mode/ob-eval hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-eval
/home/dov/.config/emacs/org-mode/org-colview hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-colview
/home/dov/.config/emacs/org-mode/org-agenda hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-agenda
/home/dov/.config/emacs/org-mode/org-beamer hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-beamer
/home/dov/.config/emacs/org-mode/ob-lisp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lisp
/home/dov/.config/emacs/org-mode/org-mks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mks
/home/dov/.config/emacs/org-mode/ob-latex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-latex
/home/dov/.config/emacs/org-mode/org-html hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-html
/home/dov/.config/emacs/org-mode/org-jsinfo hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-jsinfo
/home/dov/.config/emacs/org-mode/ob-sh hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sh
/home/dov/.config/emacs/org-mode/org-timer hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-timer
/home/dov/.config/emacs/org-mode/ob-python hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-python
/home/dov/.config/emacs/org-mode/ob hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob
/home/dov/.config/emacs/org-mode/ob-octave hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-octave
/home/dov/.config/emacs/org-mode/org-xoxo hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-xoxo
/home/dov/.config/emacs/org-mode/org-crypt hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-crypt
/home/dov/.config/emacs/org-mode/ob-scheme hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-scheme
/home/dov/.config/emacs/org-mode/org-plot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-plot
/home/dov/.config/emacs/org-mode/org-icalendar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-icalendar
/home/dov/.config/emacs/org-mode/ob-gnuplot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-gnuplot
/home/dov/.config/emacs/org-mode/ob-dot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-dot
/home/dov/.config/emacs/org-mode/org-datetree hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-datetree
/home/dov/.config/emacs/org-mode/ob-css hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-css
/home/dov/.config/emacs/org-mode/ob-plantuml hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-plantuml
/home/dov/.config/emacs/org-mode/org-rmail hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-rmail
/home/dov/.config/emacs/org-mode/org-habit hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-habit
/home/dov/.config/emacs/org-mode/org-mouse hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mouse
/home/dov/.config/emacs/org-mode/org-latex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-latex
/home/dov/.config/emacs/org-mode/org-ctags hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-ctags
/home/dov/.config/emacs/org-mode/ob-sqlite hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sqlite
/home/dov/.config/emacs/org-mode/ob-clojure hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-clojure
/home/dov/.config/emacs/org-mode/org-taskjuggler hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-taskjuggler
/home/dov/.config/emacs/org-mode/org-capture hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-capture
/home/dov/.config/emacs/org-mode/org-mew hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mew
/home/dov/.config/emacs/org-mode/org-vm hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-vm
/home/dov/.config/emacs/org-mode/org-id hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-id
/home/dov/.config/emacs/org-mode/org-publish hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-publish
/home/dov/.config/emacs/org-mode/org-indent hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-indent
/home/dov/.config/emacs/org-mode/ob-sass hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sass
/home/dov/.config/emacs/org-mode/ob-ref hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ref
/home/dov/.config/emacs/org-mode/org-macs hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-macs
/home/dov/.config/emacs/org-mode/ob-ledger hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ledger
/home/dov/.config/emacs/org-mode/org-clock hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-clock
/home/dov/.config/emacs/org-mode/ob-calc hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-calc
/home/dov/.config/emacs/org-mode/org-special-blocks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-special-blocks
/home/dov/.config/emacs/org-mode/org-mobile hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mobile
/home/dov/.config/emacs/org-mode/ob-java hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-java
/home/dov/.config/emacs/org-mode/org-table hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-table
/home/dov/.config/emacs/org-mode/ob-awk hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-awk
/home/dov/.config/emacs/org-mode/ob-lob hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lob
/home/dov/.config/emacs/org-mode/ob-haskell hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-haskell
/home/dov/.config/emacs/org-mode/org-pcomplete hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-pcomplete
/home/dov/.config/emacs/org-mode/ob-maxima hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-maxima
/home/dov/.config/emacs/org-mode/ob-sql hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sql
/home/dov/.config/emacs/org-mode/ob-js hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-js
/home/dov/.config/emacs/org-mode/org-irc hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-irc
/home/dov/.config/emacs/org-mode/ob-R hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-R
/home/dov/.config/emacs/org-mode/org-feed hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-feed
/home/dov/.config/emacs/org-mode/org hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org
/home/dov/.config/emacs/org-mode/ob-tangle hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-tangle
/home/dov/.config/emacs/org-mode/org-docview hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-docview
/home/dov/.config/emacs/org-mode/org-gnus hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-gnus
/home/dov/.config/emacs/org-mode/org-mac-message hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mac-message
/home/dov/.config/emacs/org-mode/org-bibtex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-bibtex
/home/dov/.config/emacs/org-mode/org-protocol hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-protocol
/home/dov/.config/emacs/cedet/eieio/eieio-speedbar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-speedbar
/home/dov/.config/emacs/cedet/eieio/eieio-custom hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-custom
/home/dov/.config/emacs/cedet/eieio/eieio-opt hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-opt
/home/dov/.config/emacs/cedet/eieio/chart hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/chart
/home/dov/.config/emacs/cedet/eieio/eieio-base hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-base
/home/dov/.config/emacs/cedet/eieio/eieio hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio
/home/dov/.config/emacs/cedet/eieio/eieio-datadebug hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-datadebug
/home/dov/.config/emacs/cedet/common/cedet-files hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-files
/home/dov/.config/emacs/cedet/common/inversion hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/inversion
/home/dov/.config/emacs/cedet/common/data-debug hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/data-debug
/home/dov/.config/emacs/cedet/ede/ede hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/ede
/home/dov/.config/emacs/cedet/semantic/semantic hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/semantic
/home/dov/.config/emacs/cedet/common/cedet-global hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-global
/home/dov/.config/emacs/cedet/srecode/srecode hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/srecode
/home/dov/.config/emacs/cedet/common/pulse hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/pulse
/home/dov/.config/emacs/cedet/common/cedet-cscope hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-cscope
/home/dov/.config/emacs/cedet/common/mode-local hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/mode-local
/home/dov/.config/emacs/cedet/common/cedet-idutils hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-idutils
/home/dov/.config/emacs/cedet/common/cedet hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet

Features:
(shadow mail-extr emacsbug gdb-mi bindat json vc-git face-remap org-wl
org-w3m org-vm org-rmail org-mhe org-mew org-irc org-jsinfo org-infojs
org-html org-info org-gnus org-docview org-bibtex bibtex org-bbdb paren
zoom-frm qtdoc browse-url cedet ede-speedbar ede-files ede ede-base
data-debug ede-auto eieio-speedbar speedbar ange-ftp sb-image ezimage
dframe eieio-custom ede-source eieio-base mode-local find-func inversion
git-find-file org-mw ob-plantuml ob-asymptote ob-dot ob-ditaa ob-python
ob-perl ob-sh org-htmlslidy org-s5 persistent ipython executable
org-export iimage org-install screenshot dmacro tramp tramp-compat
tramp-loaddefs tex-mode shell color-moccur matlab-load sourcepair
csv-mode sort dired-details+ dired-details mediawiki url-cache mm-url
url-http tls url-auth url-gw python-mode ansi-color tempo url url-proxy
url-privacy url-expand url-methods url-history url-cookie url-util
url-parse auth-source eieio password-cache url-vars mailcap xml-parse
doxymacs ack epresent org-latex org-export-latex org-beamer footnote
org-exp ob-exp org-exp-blocks org-agenda org advice advice-preload
ob-emacs-lisp ob-tangle ob-ref ob-lob ob-table org-footnote org-src
ob-comint ob-keys ob ob-eval org-pcomplete pcomplete org-list org-faces
org-compat org-entities org-macs cal-menu calendar cal-loaddefs nnir
gnus-sum nnoo gnus-group gnus-undo nnmail mail-source gnus-start
gnus-spec gnus-int gnus-range gnus-win gnus gnus-ems nnheader gnus-util
xmsi-math-symbols-input mo-git-blame scroll-all markdown-mode noutline
outline magit-bisect magit-key-mode assoc magit esh-var esh-io esh-cmd
esh-ext esh-proc esh-arg eldoc esh-groups eshell esh-module esh-mode
esh-util help-fns ido iswitchb diff-mode log-edit pcvs-util add-log
vc-ediff octave-mod csharp-mode byte-opt bytecomp byte-compile cconv
macroexp cc-langs doc-mode derived sgml-mode gud message format-spec
rfc822 mml mml-sec mm-decode mm-bodies mm-encode mail-parse rfc2231
rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mailabbrev mail-utils
gmm-utils mailheader delsel warnings server javascript-mode newcomment
icicles icicles-mode icicles-cmd frame-cmds frame-fns avoid dired+
dired-x dired-aux dired cus-edit cus-start cus-load yow cookie1 etags
compile easy-mmode imenu comint ring bookmark pp dabbrev recentf
tree-widget icicles-mcmd help-mode view icicles-mac icicles-fn cl
icicles-face icicles-var icicles-opt ffap wid-edit edmacro kmacro
thingatpt gtk-look info-look info vc ediff-merg ediff-diff ediff-wind
ediff-help ediff-util ediff-mult ediff-init ediff vc-dispatcher cc-mode
cc-fonts easymenu cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine
cc-vars cc-defs regexp-opt time-date tooltip ediff-hook vc-hooks
lisp-float-type mwheel x-win x-dnd tool-bar dnd fontset image fringe
lisp-mode register page menu-bar rfn-eshadow timer select scroll-bar
mouse jit-lock font-lock syntax facemenu font-core frame cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese case-table epa-hook jka-cmpr-hook help simple abbrev
minibuffer loaddefs button faces cus-face files text-properties overlay
sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote make-network-process dynamic-setting
system-font-setting font-render-setting move-toolbar gtk x-toolkit x
multi-tty emacs)
Glenn Morris
2012-01-23 00:53:46 UTC
Permalink
Post by Dov Grobgeld
When trying to running gdb on my process, emacs gets stuck for more than
one minutes while the CPU load is at 100%.
Does this happen with `emacs -Q'? Because it looks like you may not be
Post by Dov Grobgeld
/home/dov/.config/emacs/gdb-mi hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/gdb-mi
Glenn Morris
2012-01-23 09:21:09 UTC
Permalink
Thanks for your reply Glenn. Is there a public bugzilla like site for
emacs bugs or are they managed in email only. I have additional
problems with gdb in emacs 24 and I would like to know if the problems
have been reported.
You should have received this email acknowledgement of your report:

http://debbugs.gnu.org/cgi/bugreport.cgi?msg=4;bug=10580

which contains a URL pointing to your report.
Glenn Morris
2012-01-25 00:37:14 UTC
Permalink
I tried again with emacs -Q and the same thing happens. To be more
precise the startup time is about 40s at 100% CPU.
Is this with everything you try to debug, or just certain things?

Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
during those 40 seconds and see if you get a backtrace?

Or try M-x edebug-defun on the `gdb' function, step through it, and see
what is taking the time.

Guesses: do you have a huge .gdb_history or ~/.gdbinit file?
Dov Grobgeld
2012-01-25 08:49:29 UTC
Permalink
Here are some more tests:

1. It doesn't get stuck when debugging a "hello-world.c" program. Thus it
depends on the executable.
2. Regarding toggle-debug-on-quit and C-g, it doesn't work. No backtrace is
produced and the CPU continues to be at 100%.
3. I tried running edebug on gdb, which wasn't easy. I had to manually
first do eval-buffer on gdb-mi.el and gud.el. But in the end I managed and
found that the CPU is spend during (run-hooks 'gdb-mode-hook) . I'll try to
investigate it further in the next few days.

Regards,
Dov
Post by Glenn Morris
I tried again with emacs -Q and the same thing happens. To be more
precise the startup time is about 40s at 100% CPU.
Is this with everything you try to debug, or just certain things?
Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
during those 40 seconds and see if you get a backtrace?
Or try M-x edebug-defun on the `gdb' function, step through it, and see
what is taking the time.
Guesses: do you have a huge .gdb_history or ~/.gdbinit file?
Dov Grobgeld
2012-01-25 09:39:25 UTC
Permalink
More tests.

1. I was mistaken in my previous email, the CPU spending was triggered
before gdb-mode-hook.
2. The following command in gdb-input starts the 40s 100% CPU:

(process-send-string (get-buffer-process gud-comint-buffer)
(concat command "\n")))

where command="1-inferior-tty-set /dev/pts/9". Note that the command
returns immediately, but some other thread apparently gets very busy.

Is this enough info, or do you want me to probe deeper?
Post by Dov Grobgeld
1. It doesn't get stuck when debugging a "hello-world.c" program. Thus it
depends on the executable.
2. Regarding toggle-debug-on-quit and C-g, it doesn't work. No backtrace
is produced and the CPU continues to be at 100%.
3. I tried running edebug on gdb, which wasn't easy. I had to manually
first do eval-buffer on gdb-mi.el and gud.el. But in the end I managed and
found that the CPU is spend during (run-hooks 'gdb-mode-hook) . I'll try to
investigate it further in the next few days.
Regards,
Dov
Post by Glenn Morris
I tried again with emacs -Q and the same thing happens. To be more
precise the startup time is about 40s at 100% CPU.
Is this with everything you try to debug, or just certain things?
Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
during those 40 seconds and see if you get a backtrace?
Or try M-x edebug-defun on the `gdb' function, step through it, and see
what is taking the time.
Guesses: do you have a huge .gdb_history or ~/.gdbinit file?
Glenn Morris
2012-01-25 19:05:35 UTC
Permalink
Post by Dov Grobgeld
(process-send-string (get-buffer-process gud-comint-buffer)
(concat command "\n")))
where command="1-inferior-tty-set /dev/pts/9". Note that the command
returns immediately, but some other thread apparently gets very busy.
Thanks for the detective work. I'm afraid I don't know what to do about
this. It looks like process handling is messed up somehow.

I hope someone else on this list can help you further.
Dov Grobgeld
2012-04-30 05:33:31 UTC
Permalink
I finally ran emacs-24 under debugger to figure out where it got
stuck. What I found was that it is stuck in keyboard.c where in
read_key_sequence() the control keeps jumping back to the
replay_sequence label. Does this ring a bell to someone?

Regards,
Dov
Post by Glenn Morris
  (process-send-string (get-buffer-process gud-comint-buffer)
               (concat command "\n")))
where command="1-inferior-tty-set /dev/pts/9". Note that the command
returns immediately, but some other thread apparently gets very busy.
Thanks for the detective work. I'm afraid I don't know what to do about
this. It looks like process handling is messed up somehow.
I hope someone else on this list can help you further.
Dov Grobgeld
2012-04-30 06:36:40 UTC
Permalink
Here is some more clarification. In keyboard.c:command_loop_1() the
line i=read_key_sequence() blocks during interactive work until a key
is pressed. But when the process is stuck in "gdb" read_key_sequence()
does not block but keeps returning. I still have no clue of what goes
on though.
Post by Dov Grobgeld
I finally ran emacs-24 under debugger to figure out where it got
stuck. What I found was that it is stuck in keyboard.c where in
read_key_sequence() the control keeps jumping back to the
replay_sequence label. Does this ring a bell to someone?
Regards,
Dov
Post by Glenn Morris
  (process-send-string (get-buffer-process gud-comint-buffer)
               (concat command "\n")))
where command="1-inferior-tty-set /dev/pts/9". Note that the command
returns immediately, but some other thread apparently gets very busy.
Thanks for the detective work. I'm afraid I don't know what to do about
this. It looks like process handling is messed up somehow.
I hope someone else on this list can help you further.
Chong Yidong
2012-05-06 04:13:46 UTC
Permalink
Post by Dov Grobgeld
Here is some more clarification. In keyboard.c:command_loop_1() the
line i=read_key_sequence() blocks during interactive work until a key
is pressed. But when the process is stuck in "gdb" read_key_sequence()
does not block but keeps returning. I still have no clue of what goes
on though.
Is this still with 24.0.92, or the latest pretest 24.0.96, or the
emacs-24 branch? I made some changes to the pty handling a few weeks
ago (which should be included in 24.0.96), which may impact this issue.
Dov Grobgeld
2012-05-06 04:55:29 UTC
Permalink
Thank you very much for looking into this. For me, this is currently, the
main show stopper for starting to emacs-24.

I have just tested the same scenario with the latest git HEAD version from
http://git.savannah.gnu.org/r/emacs.git/ :

823d681 Optionally include holidays in cal-html output

and unfortunately the exact same behavior as before still remains.

Please let me know if there are any tests or debug info that I can provide
you with that can help in resolving this issue. I tried debugging it
myself, but I found it to complex since I lack the knowledge of how
sub-processes are handled in emacs.

Regards,
Dov
Post by Chong Yidong
Post by Dov Grobgeld
Here is some more clarification. In keyboard.c:command_loop_1() the
line i=read_key_sequence() blocks during interactive work until a key
is pressed. But when the process is stuck in "gdb" read_key_sequence()
does not block but keeps returning. I still have no clue of what goes
on though.
Is this still with 24.0.92, or the latest pretest 24.0.96, or the
emacs-24 branch? I made some changes to the pty handling a few weeks
ago (which should be included in 24.0.96), which may impact this issue.
Chong Yidong
2012-05-06 05:39:56 UTC
Permalink
Post by Dov Grobgeld
Please let me know if there are any tests or debug info that I can
provide you with that can help in resolving this issue. I tried
debugging it myself, but I found it to complex since I lack the
knowledge of how sub-processes are handled in emacs.
If you look at the *input/output of a.out* buffer, does it contain any
text?

Also, when you say that read_key_sequence keeps returning, what is its
return value? Also, when read_key_sequence returns early, what is the
value returned by read_char at keyboard.c:9341?

Also, is it possible for you to provide a copy of the problematic
program, or is it not allowed?
Dov Grobgeld
2012-05-06 07:06:13 UTC
Permalink
The *input/output of a.out* is empty.

It seems that I was wrong about read_key_sequence(). It doesn't "return
early". Here is a stack trace during the timeout:

#0 0x00110424 in __kernel_vsyscall ()
#1 0x005f288d in ___newselect_nocancel () at
../sysdeps/unix/syscall-template.S:82
#2 0x08149691 in xg_select (max_fds=17, rfds=0xbfffe860, wfds=0xbfffe7e0,
efds=0x0, timeout=0xbfffe7d4) at xgselect.c:100
#3 0x0821ffb0 in wait_reading_process_output (time_limit=30, microsecs=0,
read_kbd=-1, do_display=1, wait_for_cell=138903722, wait_proc=0x0,
just_wait_proc=0) at process.c:4620
#4 0x080601c7 in sit_for (timeout=120, reading=1, do_display=1) at
dispnew.c:6068
#5 0x08159606 in read_char (commandflag=1, nmaps=3, maps=0xbfffec50,
prev_event=138903722, used_mouse_menu=0xbfffed18, end_time=0x0) at
keyboard.c:2698
#6 0x08163f12 in read_key_sequence (keybuf=0xbfffee94, bufsize=30,
prompt=138903722, dont_downcase_last=0, can_return_switch_frame=1,
fix_current_buffer=1) at keyboard.c:9341
#7 0x08157472 in command_loop_1 () at keyboard.c:1455
#8 0x081d629d in internal_condition_case (bfun=0x815711b <command_loop_1>,
handlers=138934706, hfun=0x8156ad5 <cmd_error>) at eval.c:1448
#9 0x08156e49 in command_loop_2 (ignore=138903722) at keyboard.c:1160
#10 0x081d5d6f in internal_catch (tag=138932706, func=0x8156e25
<command_loop_2>, arg=138903722) at eval.c:1205
#11 0x08156e05 in command_loop () at keyboard.c:1139
#12 0x0815670e in recursive_edit_1 () at keyboard.c:759
#13 0x0815685f in Frecursive_edit () at keyboard.c:823
#14 0x08154d65 in main (argc=1, argv=0xbffff5e4) at emacs.c:1711

read_char() returns 158534621.

Sorry, I can't redistribute the executable. If the problem can't be solved
by otherwise, I'll try to generate another executable that has this
problem. In any case, here is the output when running gdb from the command
line on the executable.
gdb -i=mi SolarJet
=thread-group-added,id="i1"
~"GNU gdb (GDB) Fedora (7.2-52.fc14)\n"
~"Copyright (C) 2010 Free Software Foundation, Inc.\n"
~"License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to
change and redistribute it.\nThere is NO WARRANTY, to the extent permitted
by law. Type \"show copying\"\nand \"show warranty\" for details.\n"
~"This GDB was configured as \"i686-redhat-linux-gnu\".\nFor bug reporting
instructions, please see:\n"
~"<http://www.gnu.org/software/gdb/bugs/>...\n"
~"Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet..."
~"done.\n"
(gdb)

Thanks,
Dov
Post by Dov Grobgeld
Please let me know if there are any tests or debug info that I can
provide you with that can help in resolving this issue. I tried
debugging it myself, but I found it to complex since I lack the
knowledge of how sub-processes are handled in emacs.
If you look at the *input/output of a.out* buffer, does it contain any
text?
Also, when you say that read_key_sequence keeps returning, what is its
return value? Also, when read_key_sequence returns early, what is the
value returned by read_char at keyboard.c:9341?
Also, is it possible for you to provide a copy of the problematic
program, or is it not allowed?
Chong Yidong
2012-05-07 02:53:52 UTC
Permalink
Post by Dov Grobgeld
The *input/output of a.out* is empty.
It seems that I was wrong about read_key_sequence(). It doesn't
"return early".
During this time, is Emacs responsive to user commands, i.e. does it
work normally apart from taking 100% CPU? Or is it just unresponsive?

Also, what is your gdb version?

Also, please set a breakpoint at process.c:4896, which should be the
line

struct Lisp_Process *p = XPROCESS (proc);

as well as the function exec_sentinel(). See if Emacs hits each
breakpoint, and step through it for the next several steps. In
exec_sentinel, please show the Lisp values of the `proc' and `reason'
variables (i.e. `pp proc' and `pp reason'.)

Basically, gdb-mi.el allocates a pty and passes it to the gdb process,
which hooks the pty up to the debugged process's input/output. That's
what the "1-inferior-tty-set /dev/pts/9" gdb command does. Emacs then
listens for input/output on the pty. Recently I fixed a bug in which
Emacs would use 100% CPU due to Emacs getting an EIO error on that pty
and then spinning; this fix involved setting up a sentinel that closes
the pty when Emacs gets EIO; it's possible the fix is not working for
you, though I don't know why. The other possibility is that the program
you are debugging does something strange with its input/output stream.

Thanks.
Dov Grobgeld
2012-05-07 05:07:44 UTC
Permalink
Hi Chong,

In response to your questions.

During the "100% CPU" time period, emacs still responds normally and files
can be opened, etc.

My gdb version is "GNU gdb (GDB) Fedora (7.2-52.fc14)". I have tried it at
home as well with a later version from Fedora 16 and the result is the same.

I put breakpoints at the lines that you indicated, but as you suspected,
the breakpoints are only reached when I exit gdb with the "quit" command.

What's next? Thanks again for looking into this.

Dov
Post by Chong Yidong
Post by Dov Grobgeld
The *input/output of a.out* is empty.
It seems that I was wrong about read_key_sequence(). It doesn't
"return early".
During this time, is Emacs responsive to user commands, i.e. does it
work normally apart from taking 100% CPU? Or is it just unresponsive?
Also, what is your gdb version?
Also, please set a breakpoint at process.c:4896, which should be the
line
struct Lisp_Process *p = XPROCESS (proc);
as well as the function exec_sentinel(). See if Emacs hits each
breakpoint, and step through it for the next several steps. In
exec_sentinel, please show the Lisp values of the `proc' and `reason'
variables (i.e. `pp proc' and `pp reason'.)
Basically, gdb-mi.el allocates a pty and passes it to the gdb process,
which hooks the pty up to the debugged process's input/output. That's
what the "1-inferior-tty-set /dev/pts/9" gdb command does. Emacs then
listens for input/output on the pty. Recently I fixed a bug in which
Emacs would use 100% CPU due to Emacs getting an EIO error on that pty
and then spinning; this fix involved setting up a sentinel that closes
the pty when Emacs gets EIO; it's possible the fix is not working for
you, though I don't know why. The other possibility is that the program
you are debugging does something strange with its input/output stream.
Thanks.
Chong Yidong
2012-05-07 06:11:42 UTC
Permalink
Post by Dov Grobgeld
I put breakpoints at the lines that you indicated, but as you
suspected, the breakpoints are only reached when I exit gdb with the
"quit" command.
What's next? Thanks again for looking into this.
Please apply the following patch, then, when Emacs is taking 100% CPU,
set a breakpoint at process.c:4854, i.e. at

if (p->pid == -2)
;

This captures the state just after Emacs calls read_process_output on
the pty passed to your program. If this breakpoint is triggered, please
report the value of nread and errno, and step through to the end of the
subsequent if/else block and report the gdb session. Thanks.


=== modified file 'src/process.c'
*** src/process.c 2012-04-20 06:39:29 +0000
--- src/process.c 2012-05-07 06:09:25 +0000
***************
*** 4847,4852 ****
--- 4847,4859 ----
buffered-ahead character if we have one. */

nread = read_process_output (proc, channel);
+
+ {
+ struct Lisp_Process *p = XPROCESS (proc);
+ if (p->pid == -2)
+ ;
+ }
+
if (nread > 0)
{
/* Since read_process_output can run a filter,
Chong Yidong
2012-05-07 06:26:14 UTC
Permalink
Actually, try the following patch instead (apparently gdb has some
issues with printing errno). Apply the patch, then when Emacs is taking
100% CPU do an interrupt and set the breakpoint at process.c:4855, then
when the breakpoint triggers do

n
p nread
p errno

and step through the subsequent if/else blocks. Thanks.

Basically, the 100% CPU appears to be because Emacs' select() call keeps
getting worken up by the pty attached to your program. But, for some
reason, no actual output being read from that pty. These debugging
steps are trying to figure out if some uncaught errno is being reported
by the pty read.


=== modified file 'src/process.c'
*** src/process.c 2012-04-20 06:39:29 +0000
--- src/process.c 2012-05-07 06:21:39 +0000
***************
*** 4822,4827 ****
--- 4822,4829 ----
&& !FD_ISSET (channel, &non_process_wait_mask))
{
int nread;
+ int saved_errno = 0;
+ struct Lisp_Process *pp;

/* If waiting for this channel, arrange to return as
soon as no more input to be processed. No more
***************
*** 4847,4852 ****
--- 4849,4859 ----
buffered-ahead character if we have one. */

nread = read_process_output (proc, channel);
+
+ pp = XPROCESS (proc);
+ if (pp->pid == -2)
+ saved_errno = errno;
+
if (nread > 0)
{
/* Since read_process_output can run a filter,
Dov Grobgeld
2012-05-08 05:33:15 UTC
Permalink
I added the above patch and the result is as follows:

After the following two lines:

nread = read_process_output (proc, channel);

pp = XPROCESS(proc);

nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
arbitrary, but constant number between 1000 and 2000).

This seems strange, as obviously the sub-process does not produce 4095
characters repeatedly.

Thanks,
Dov
Post by Chong Yidong
Actually, try the following patch instead (apparently gdb has some
issues with printing errno). Apply the patch, then when Emacs is taking
100% CPU do an interrupt and set the breakpoint at process.c:4855, then
when the breakpoint triggers do
n
p nread
p errno
and step through the subsequent if/else blocks. Thanks.
Basically, the 100% CPU appears to be because Emacs' select() call keeps
getting worken up by the pty attached to your program. But, for some
reason, no actual output being read from that pty. These debugging
steps are trying to figure out if some uncaught errno is being reported
by the pty read.
=== modified file 'src/process.c'
*** src/process.c 2012-04-20 06:39:29 +0000
--- src/process.c 2012-05-07 06:21:39 +0000
***************
*** 4822,4827 ****
--- 4822,4829 ----
&& !FD_ISSET (channel, &non_process_wait_mask))
{
int nread;
+ int saved_errno = 0;
+ struct Lisp_Process *pp;
/* If waiting for this channel, arrange to return as
soon as no more input to be processed. No more
***************
*** 4847,4852 ****
--- 4849,4859 ----
buffered-ahead character if we have one. */
nread = read_process_output (proc, channel);
+
+ pp = XPROCESS (proc);
+ if (pp->pid == -2)
+ saved_errno = errno;
+
if (nread > 0)
{
/* Since read_process_output can run a filter,
Dov Grobgeld
2012-05-08 07:56:21 UTC
Permalink
Some more info that I found through strace that might help. Alltogether
read_process_output() is called 214 times and thus a total of 870k of text
is read through /dev/ptmx to read_process_output() . Could the amount of
data possibly explain the slowness?

Regards,
Dov
Post by Chong Yidong
nread = read_process_output (proc, channel);
pp = XPROCESS(proc);
nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
arbitrary, but constant number between 1000 and 2000).
This seems strange, as obviously the sub-process does not produce 4095
characters repeatedly.
Thanks,
Dov
Post by Chong Yidong
Actually, try the following patch instead (apparently gdb has some
issues with printing errno). Apply the patch, then when Emacs is taking
100% CPU do an interrupt and set the breakpoint at process.c:4855, then
when the breakpoint triggers do
n
p nread
p errno
and step through the subsequent if/else blocks. Thanks.
Basically, the 100% CPU appears to be because Emacs' select() call keeps
getting worken up by the pty attached to your program. But, for some
reason, no actual output being read from that pty. These debugging
steps are trying to figure out if some uncaught errno is being reported
by the pty read.
=== modified file 'src/process.c'
*** src/process.c 2012-04-20 06:39:29 +0000
--- src/process.c 2012-05-07 06:21:39 +0000
***************
*** 4822,4827 ****
--- 4822,4829 ----
&& !FD_ISSET (channel, &non_process_wait_mask))
{
int nread;
+ int saved_errno = 0;
+ struct Lisp_Process *pp;
/* If waiting for this channel, arrange to return as
soon as no more input to be processed. No more
***************
*** 4847,4852 ****
--- 4849,4859 ----
buffered-ahead character if we have one. */
nread = read_process_output (proc, channel);
+
+ pp = XPROCESS (proc);
+ if (pp->pid == -2)
+ saved_errno = errno;
+
if (nread > 0)
{
/* Since read_process_output can run a filter,
Chong Yidong
2012-05-08 08:28:27 UTC
Permalink
    nread = read_process_output (proc, channel);
    pp = XPROCESS(proc);
nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
arbitrary, but constant number between 1000 and 2000).
Some more info that I found through strace that might help.
Alltogether read_process_output() is called 214 times and thus a total
of 870k of text is read through /dev/ptmx to read_process_output() .
Could the amount of data possibly explain the slowness?
Maybe, if this process IO is emitted non-stop. But this indicates that
the traffic is due to the main connection with the main gdb process
(which has a positive pid), not with the pty which gdb-mi uses for IO
(which has pid -2) like I guessed.

Could you do

M-: (setq gdb-enable-debug t) RET

and show the value of the variable `gdb-debug-log'?

For example, when I run M-x gdb on the Emacs binary itself,
`gdb-debug-log' gets 22 entries by the time I get to the (gdb) prompt;
this is the usual GDB-MI chatter.
Dov Grobgeld
2012-05-08 11:59:36 UTC
Permalink
Indeed, my result is much fatter.

(safe-length gdb-debug-log) => 223

and the total length of the messages is about 800k. So it seems that the
time spent is simply the parsing of this large chunk of data? What gdb
command is run that outputs all the file="..." commands?

Thanks,
Dov
Post by Chong Yidong
Post by Chong Yidong
nread = read_process_output (proc, channel);
pp = XPROCESS(proc);
nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
arbitrary, but constant number between 1000 and 2000).
Some more info that I found through strace that might help.
Alltogether read_process_output() is called 214 times and thus a total
of 870k of text is read through /dev/ptmx to read_process_output() .
Could the amount of data possibly explain the slowness?
Maybe, if this process IO is emitted non-stop. But this indicates that
the traffic is due to the main connection with the main gdb process
(which has a positive pid), not with the pty which gdb-mi uses for IO
(which has pid -2) like I guessed.
Could you do
M-: (setq gdb-enable-debug t) RET
and show the value of the variable `gdb-debug-log'?
For example, when I run M-x gdb on the Emacs binary itself,
`gdb-debug-log' gets 22 entries by the time I get to the (gdb) prompt;
Chong Yidong
2012-05-08 16:25:00 UTC
Permalink
Post by Dov Grobgeld
Indeed, my result is much fatter.
(safe-length gdb-debug-log) => 223
and the total length of the messages is about 800k. So it seems that
the time spent is simply the parsing of this large chunk of data? What
gdb command is run that outputs all the file="..." commands?
Those are status messages from turning on GDB's MI (machine interface)
system, I think, though I don't see why it makes so much difference in
your case.

If you type, from the shell,

gdb -i=mi YOUR-BINARY
r

do you similarly see a huge output?
Eli Zaretskii
2012-05-08 17:47:57 UTC
Permalink
Date: Wed, 09 May 2012 00:25:00 +0800
Those are status messages from turning on GDB's MI (machine interface)
system, I think, though I don't see why it makes so much difference in
your case.
If you type, from the shell,
gdb -i=mi YOUR-BINARY
r
do you similarly see a huge output?
As you know, in addition to "run", gdb-mi.el sends lots of other
commands behind the scenes, so the above is not a faithful simulation
of what happens when GDB is run by Emacs. But I agree that if the
above produces similarly voluminous output, we cannot really blame
gdb-mi.el.
Dov Grobgeld
2012-05-08 21:07:05 UTC
Permalink
So my latest investigations suggest that the problem is the
"-file-list-exec-source-files" command which generates the huge output due
to the large number of files that is part of the project.

The following shows the problem from the command line.

echo -file-list-exec-source-files > /tmp/gdb.in
gdb MyExec < /tmp/gdb.in > /tmp/gdb.out
wc /tmp/gdb.out
11 69 3725105 /tmp/gdb.out

(Note that this is on a my home box, where the output is much larger than
what I reported this morning possibly due to different paths).

So there are still several questions:

* Why does it take several minutes to parse a 3.7M file? Could it be
related to the fact that gdb-mi/emacs concatinates the entire string before
trying to parse it. Still 3.7M is far too much.

* Noted that I can't run gdb MyExec < /tmp/gdb.in in a shell buffer. It
gets slower and slower while the CPU stays at 100%.

* There is a huge redundancy in gdb.out. The command
-file-list-exec-source-files should output all source files included, but
the same source files are listed multiple times. Consider the huge file
size reduction after sorting and uniq'ing:

perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }' /tmp/gdb.out |
sort | uniq | wc

3931 3931 220654

Why doesn't -file-list-exec-source file do uniq internally. This seems like
a bug in gdb.

* Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
search for source files on demand?

Regards,
Dov
Post by Eli Zaretskii
Date: Wed, 09 May 2012 00:25:00 +0800
Those are status messages from turning on GDB's MI (machine interface)
system, I think, though I don't see why it makes so much difference in
your case.
If you type, from the shell,
gdb -i=mi YOUR-BINARY
r
do you similarly see a huge output?
As you know, in addition to "run", gdb-mi.el sends lots of other
commands behind the scenes, so the above is not a faithful simulation
of what happens when GDB is run by Emacs. But I agree that if the
above produces similarly voluminous output, we cannot really blame
gdb-mi.el.
Andreas Schwab
2012-05-08 21:24:38 UTC
Permalink
Post by Dov Grobgeld
* Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
search for source files on demand?
Customize gdb-create-source-file-list to nil.

Andreas.
--
Andreas Schwab, ***@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Dov Grobgeld
2012-05-08 21:30:08 UTC
Permalink
I first that at first too, but then I realized that it doesn't do it. The
gdb-mi.el source has the following logic.

(gdb-input
; Needs GDB 6.2 onwards.
(list "-file-list-exec-source-files" 'gdb-get-source-file-list))
(if gdb-create-source-file-list
(gdb-input
; Needs GDB 6.0 onwards.
(list "-file-list-exec-source-file" 'gdb-get-source-file)))

i.e. the gdb command "-file-list-exec-source-files" (note the s in files)
is called independantly from gdb-create-source-file-list which only
influences the execution of "-file-list-exec-source-file".
Post by Andreas Schwab
Post by Dov Grobgeld
* Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
search for source files on demand?
Customize gdb-create-source-file-list to nil.
Andreas.
--
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Andreas Schwab
2012-05-09 07:47:19 UTC
Permalink
Post by Dov Grobgeld
I first that at first too, but then I realized that it doesn't do it. The
gdb-mi.el source has the following logic.
(gdb-input
; Needs GDB 6.2 onwards.
(list "-file-list-exec-source-files" 'gdb-get-source-file-list))
(if gdb-create-source-file-list
(gdb-input
; Needs GDB 6.0 onwards.
(list "-file-list-exec-source-file" 'gdb-get-source-file)))
You are looking at a very old version of gdb-mi.el.

Andreas.
--
Andreas Schwab, ***@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Dov Grobgeld
2012-05-09 08:44:32 UTC
Permalink
Yes, sorry. I discovered that I looked at an old version. The latest git
version indeed allows disabling the -file-list-exec-source-files. I will
use that option which indeed is a work around for the problem.

In addition, I filed a bug for gdb that it should uniq the filenames output
by -file-list-exec-source-files.

I realized that all filelist-exec-source-files is used for is to turn on
gdb minor mode for all files that are currently open in emacs. Perhaps we
should turn the problem around by asking for a gdb function that answers
the question whether a file is referenced by an executable. It would then
be possible to loop over the emacs buffers and turn on gdb minor mode if
the file is referenced by the new gdb session.

Regards,
Dov
Post by Andreas Schwab
Post by Dov Grobgeld
I first that at first too, but then I realized that it doesn't do it. The
gdb-mi.el source has the following logic.
(gdb-input
; Needs GDB 6.2 onwards.
(list "-file-list-exec-source-files" 'gdb-get-source-file-list))
(if gdb-create-source-file-list
(gdb-input
; Needs GDB 6.0 onwards.
(list "-file-list-exec-source-file" 'gdb-get-source-file)))
You are looking at a very old version of gdb-mi.el.
Andreas.
--
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Eli Zaretskii
2012-05-09 17:36:14 UTC
Permalink
Date: Wed, 9 May 2012 11:44:32 +0300
In addition, I filed a bug for gdb that it should uniq the filenames output
by -file-list-exec-source-files.
Can you provide a link to that bug report?

FWIW, when I use -file-list-exec-source-files while debugging Emacs, I
don't see duplicate file names in the GDB output. Maybe I'm blind.
Dov Grobgeld
2012-05-10 06:00:49 UTC
Permalink
Here is a link to the gdb bug:

http://sourceware.org/bugzilla/show_bug.cgi?id=14081

I tried running file-list-exec-source-files and I get duplicates as well.
Try the following:

prompt> echo -file-list-exec-source-files > /tmp/gdb.in
prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb.out | sort | head -15
file=alloc.c
file=alloc.c
file=allocator.c
file=atimer.c
file=atimer.c
file=bidi.c
file=bidi.c
file=buffer.c
file=buffer.c
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h

My version of gdb is:

GNU gdb (GDB) Fedora (7.2-52.fc14)

For my executable gdb outputs full paths as well as the fullname field,
which expands the output considerably.

Still, it bothering me the fact that the above perl expression parses the
gdb output in a fraction of a second, (0.01s user time) whereas gdb-mi.el
takes more than 40s.

Regards,
Dov
Post by Dov Grobgeld
Date: Wed, 9 May 2012 11:44:32 +0300
In addition, I filed a bug for gdb that it should uniq the filenames
output
by -file-list-exec-source-files.
Can you provide a link to that bug report?
FWIW, when I use -file-list-exec-source-files while debugging Emacs, I
don't see duplicate file names in the GDB output. Maybe I'm blind.
Chong Yidong
2012-05-10 14:13:36 UTC
Permalink
Post by Dov Grobgeld
Still, it bothering me the fact that the above perl expression parses
the gdb output in a fraction of a second, (0.01s user time) whereas
gdb-mi.el takes more than 40s.
I would also like to learn more about where the bottleneck is.

Could you do the following:

M-: (require 'gdb-mi) RET
M-: (defun gdb-get-source-file-list () nil) RET

then run M-x gdb as usual, and see if that makes any difference in
performance? Leave gdb-create-source-file-list set at t.

(The above steps cause gdb-mi to issue the -file-list-exec-source-files
command and read the output, as usual, but skip parsing the output into
the source file list.)
Dov Grobgeld
2012-05-10 19:07:38 UTC
Permalink
Here are the tests when using the the latest cvs gdb that yields a gdb
output file of about 800k.

Without gdb-get-source-file-list override: ~139s
With gdb-get-source-file-list override: ~125s

Thus it is clear that most of the time is taken just reading the string
into emacs. But doing find-file on the same file is almost instantaneous.

Regards,
Dov
Post by Chong Yidong
Post by Dov Grobgeld
Still, it bothering me the fact that the above perl expression parses
the gdb output in a fraction of a second, (0.01s user time) whereas
gdb-mi.el takes more than 40s.
I would also like to learn more about where the bottleneck is.
M-: (require 'gdb-mi) RET
M-: (defun gdb-get-source-file-list () nil) RET
then run M-x gdb as usual, and see if that makes any difference in
performance? Leave gdb-create-source-file-list set at t.
(The above steps cause gdb-mi to issue the -file-list-exec-source-files
command and read the output, as usual, but skip parsing the output into
the source file list.)
Stefan Monnier
2012-05-10 20:25:59 UTC
Permalink
Post by Dov Grobgeld
Here are the tests when using the the latest cvs gdb that yields a gdb
output file of about 800k.
Without gdb-get-source-file-list override: ~139s
With gdb-get-source-file-list override: ~125s
Thus it is clear that most of the time is taken just reading the string
into emacs. But doing find-file on the same file is almost instantaneous.
Sounds like a perfect test case for the native elisp profiler (a
prototype of which is at
http://cx4a.org/hack/emacs-native-profiler.html, and hopefully it will
mature over the summer since it's funded as a GSoC).


Stefan
Chong Yidong
2012-05-11 06:33:52 UTC
Permalink
Post by Dov Grobgeld
Here are the tests when using the the latest cvs gdb that yields a gdb
output file of about 800k.
Without gdb-get-source-file-list override: ~139s
With gdb-get-source-file-list override: ~125s
Thus it is clear that most of the time is taken just reading the
string into emacs. But doing find-file on the same file is almost
instantaneous.
Here's another little experiment. Could you apply the two attached
patches, individually, and see what difference each patch makes?
(Again, with gdb-create-source-file-list at its default of t, and
without any other patches to gdb-mi.el.)
Dov Grobgeld
2012-05-11 08:29:57 UTC
Permalink
Here are the results.

With patch1: ~155s
With patch2: ~112s

On the other hand, I have patched gdb, seehttp://
sourceware.org/bugzilla/show_bug.cgi?id=14081, to do uniq internally in
gdb, and then it takes only about 10s.
Post by Chong Yidong
Post by Dov Grobgeld
Here are the tests when using the the latest cvs gdb that yields a gdb
output file of about 800k.
Without gdb-get-source-file-list override: ~139s
With gdb-get-source-file-list override: ~125s
Thus it is clear that most of the time is taken just reading the
string into emacs. But doing find-file on the same file is almost
instantaneous.
Here's another little experiment. Could you apply the two attached
patches, individually, and see what difference each patch makes?
(Again, with gdb-create-source-file-list at its default of t, and
without any other patches to gdb-mi.el.)
Eli Zaretskii
2012-05-11 09:47:53 UTC
Permalink
Date: Fri, 11 May 2012 11:29:57 +0300
With patch1: ~155s
With patch2: ~112s
On the other hand, I have patched gdb, seehttp://
sourceware.org/bugzilla/show_bug.cgi?id=14081, to do uniq internally in
gdb, and then it takes only about 10s.
Which is much faster, but still way too slow.

I think it's quite clear at this point that what takes time is reading
the stuff from GDB, not parsing it. Chong, am I right?
Chong Yidong
2012-05-11 13:27:36 UTC
Permalink
Post by Eli Zaretskii
I think it's quite clear at this point that what takes time is reading
the stuff from GDB, not parsing it. Chong, am I right?
That is what the evidence suggests, which indicates that we won't be
able to fix it for 24.1. Maybe there is some problem in the adaptive
read buffering code?
Dov Grobgeld
2012-11-05 20:36:16 UTC
Permalink
Is there any chance of having this bug solved in the foreseeable future?
This bug is the reason I am still sticking with emacs-23. As an
alternative, is it possible to use the old gdb-mode (without -mi) in
emacs-24?
Post by Chong Yidong
Post by Eli Zaretskii
I think it's quite clear at this point that what takes time is reading
the stuff from GDB, not parsing it. Chong, am I right?
That is what the evidence suggests, which indicates that we won't be
able to fix it for 24.1. Maybe there is some problem in the adaptive
read buffering code?
Eli Zaretskii
2012-11-05 20:46:47 UTC
Permalink
Date: Mon, 5 Nov 2012 22:36:16 +0200
As an alternative, is it possible to use the old gdb-mode (without
-mi) in emacs-24?
It was always possible: type "M-x gud-gdb RET".
Stefan Monnier
2012-11-05 23:51:41 UTC
Permalink
Post by Eli Zaretskii
As an alternative, is it possible to use the old gdb-mode (without
-mi) in emacs-24?
It was always possible: type "M-x gud-gdb RET".
IIUC this gives you the Emacs-22 version of M-x gdb, but not the
Emacs-23 one (which used the gdb-ui.el code).


Stefan
Eli Zaretskii
2012-05-10 16:32:04 UTC
Permalink
Date: Thu, 10 May 2012 09:00:49 +0300
I tried running file-list-exec-source-files and I get duplicates as well.
prompt> echo -file-list-exec-source-files > /tmp/gdb.in
prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb.out | sort | head -15
file=alloc.c
file=alloc.c
file=allocator.c
file=atimer.c
file=atimer.c
file=bidi.c
file=bidi.c
file=buffer.c
file=buffer.c
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
I don't see anything like that. Here's my output:

addr=0x011b4ea5
addr=0x011b4ea5
addr=0x012329a8
disp=del
disp=del
disp=keep
enabled=y
enabled=y
enabled=y
file=../lib/allocator.h
file=../lib/careadlinkat.h
file=../lib/ignore-value.h
file=../lib/intprops.h
file=../lib/intprops.h
file=../lib/intprops.h

IOW, all the duplicates I see are header files. Not a single .c file
shows up, not even if I change "head -15" into "head -100".
GNU gdb (GDB) Fedora (7.2-52.fc14)
Maybe you should upgrade, I dunno. I use 7.4.1, FWIW.

Or maybe GCC versions later than what I have do that.
For my executable gdb outputs full paths as well as the fullname field,
which expands the output considerably.
Here too, but that's expected (and necessary).
Dov Grobgeld
2012-05-10 18:43:39 UTC
Permalink
I just downloaded gdb from cvs and tried with the latest version and there
are still duplicates. Perhaps it is because of gcc? But on the positive
side there is indeed a huge difference in the gdb output.

prompt> gdb --version
GNU gdb (GDB) Fedora (7.3.50.20110722-13.fc16)
prompt> /usr/local/public-dev/bin/gdb --version
GNU gdb (GDB) 7.4.50.20120509-cvs
prompt> gdb -i=mi MyExec < /tmp/gdb.in > /tmp/gdb-old.out
prompt> /usr/local/public-dev/bin/gdb -i=mi MyExec < /tmp/gdb.in >
/tmp/gdb-new.out
prompt> ls -1s --block-size=1 /tmp/gdb*.out
884736 /tmp/gdb-new.out
3727360 /tmp/gdb-old.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-old.out | sort | wc
67311 67311 3522494
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-new.out | sort | wc
14221 14221 837082
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-old.out | sort |uniq| wc
3931 3931 220654
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-new.out | sort |uniq| wc
2245 2245 137404

But even the factor 837k vs 137k is substantial, so it is still valid to do
an internal uniq within gdb. I'll try to put together a patch.

Regards,
Dov
Post by Eli Zaretskii
Date: Thu, 10 May 2012 09:00:49 +0300
I tried running file-list-exec-source-files and I get duplicates as well.
prompt> echo -file-list-exec-source-files > /tmp/gdb.in
prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb.out | sort | head -15
file=alloc.c
file=alloc.c
file=allocator.c
file=atimer.c
file=atimer.c
file=bidi.c
file=bidi.c
file=buffer.c
file=buffer.c
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
addr=0x011b4ea5
addr=0x011b4ea5
addr=0x012329a8
disp=del
disp=del
disp=keep
enabled=y
enabled=y
enabled=y
file=../lib/allocator.h
file=../lib/careadlinkat.h
file=../lib/ignore-value.h
file=../lib/intprops.h
file=../lib/intprops.h
file=../lib/intprops.h
IOW, all the duplicates I see are header files. Not a single .c file
shows up, not even if I change "head -15" into "head -100".
GNU gdb (GDB) Fedora (7.2-52.fc14)
Maybe you should upgrade, I dunno. I use 7.4.1, FWIW.
Or maybe GCC versions later than what I have do that.
For my executable gdb outputs full paths as well as the fullname field,
which expands the output considerably.
Here too, but that's expected (and necessary).
Eli Zaretskii
2012-05-08 17:38:55 UTC
Permalink
Date: Tue, 8 May 2012 14:59:36 +0300
Indeed, my result is much fatter.
(safe-length gdb-debug-log) => 223
and the total length of the messages is about 800k.
Ouch! could you send it as a compressed attachment? I'd be interested
to see what gdb-mi.el commands generate such large output.
Jean-Philippe Gravel
2012-12-14 04:14:59 UTC
Permalink
Hi guys,



I actually have a fix for this problem.



I use Emacs to debug a software of colossal size. With Emacs 23, it used
to be possible to start gdb within a minute. With Emacs 24, it takes more
than a couple of hour. I never actually had the patience to wait for it to
finish.



As stated in previous posts, the command -file-list-exec-source-files is
the one triggering the bottleneck. In my case, the reply is 5Mb long.



It turns out that the problem IS the parsing of the data stream coming from
GDB. The function gud-gdbmi-marker-filter is home to a colossal
bottleneck. You’ll find in there not only one, but 4 major algorithmic
problems.



The first thing that strikes the eye is the way it handles the fact that
there are several types of GDB replies possible. Instead of parsing the
data stream linearly, accepting the GDB messages in the order of arrival,
it looks over the whole stream for the first type of message, then the
second, then the next. Complexity: O(nm), where n is the size of the steam
and m is the number of message types. Then, when finding a message
matching the type we look for, it is removed from the stream by cloning the
whole string, but padding the original location with spaces. Complexity:
O(ni), where i is the number of messages.



To go on with the analysis, consider the following: my tests indicate that
gdbmi-marker-filter receives data by chunk of about 225 bytes. Since I
receive 5Mb of data, gdbmi ingests about 22000 packets. For every chunk of
data received, the incoming data is concatenated to a new string: O(nj),
where j is the number of packets. Each time, the whole parsing described
above is restarted: O(nmj) (!!!). Feed in a 5Mb data stream and you’ll get
a hung emacs!



I fixed the above by writing a proper parser reading the data stream in
O(n). With my test-case, the parse time goes down from ‘too long to even
tell’, to about 3 seconds. Not only does it fix the startup problem, but
it makes pretty much all other gud commands impressively faster. With
emacs 23, it used to take almost a full second to do a single “gud-next” in
my software. When enabling gud-tooltip-mode, it was becoming totally
unusable. By removing the bottleneck in gud-gdbmi-marker-filter, the above
become instantaneous.



I just need to finalize a few things and I can send you a patch file.



Cheers!
Jean-Philippe Gravel
2012-12-18 04:45:49 UTC
Permalink
Here is my patch.

As stated previously, I only re-wrote gud-gdbmi-marker-filter. This
function now parses the GDB/MI records in the order of arrival. Only
the signature of each record is read by the new parser. The actual
content of the record (i.e. result strings) is still parsed by the
original code (which I will refer to as the record handlers below).

The new parser is based on the GDB/MI output BNF grammar available at:
ftp://ftp.gnu.org/pub/old-gnu/Manuals/gdb/html_node/gdb_214.html#SEC221

Records that are too large to be received in one data chunk can be
parsed progressively by the record handlers, if they support it. The
global configuration alist “gdbmi-bnf-result-state-configs” defines
the mapping between record types and record handlers. This structure
flags all the handlers as either progressive or atomic.

Progressive handlers are invokes as soon as a partial data chunks are
received. Atomic handlers on the other hand will not be invoked until
the whole record is received. This design allowed me to progressively
attack the optimization problem: the ^done / ^error messages being the
biggest bottleneck (the reply to -file-list-exec-source-files), I
started by only converting those to progressive parsing. If we find
that other messages cause performance issue, we can always convert
them to progressive parsing as well.

That being said, while the handler for ^done and ^error
(gdb-done-or-error) do receive the data progressively, it doesn’t
parse it on the fly. Instead, it accumulates the data chunks in a
temporary buffer and parses its content only when the record is
complete. This is sub-optimal, but my tests showed that optimizing
this part would have only a minimal effect compared to fixing
gud-gdbmi-marker-filter. I decided to keep this as a separate
optimization task, to be done later.

For performance reason, I tried to keep processing and data copy to a
minimum. I therefore work in-place, directly in the gud-marker-acc
string, instead of copying the string to a temporary buffer. The
parser walks in the string using an offset stored in gdbmi-bnf-offset.
By looking at the character at this offset, I can quickly detect the
type of record we received, BEFORE trying to parse it with
string-match.

Note: I am a little confused about when the parser states should be
(re)initialized. I would have expected the states to be initialized
before the GDB process is started (before gud-common-init) because
once the process starts, the marker-filter can be invoked at any time.
Instead, I find that the gdb-mi variables are all initialized in
gdb-init-1, which runs after the process is started. I added a new
function gdbmi-bnf-init that is invoked from within gdb-init-1, but
that doesn’t seem right. Does anyone have an opinion on this? I
certainly do think there is currently a problem because if the GDB/MI
initialization is interrupted expectedly (for instance because of an
error), it seems to restart in a very bad state the next time (I think
that's true even before my fix)…

Jean-Philippe
Chong Yidong
2012-12-21 04:01:04 UTC
Permalink
Post by Jean-Philippe Gravel
As stated previously, I only re-wrote gud-gdbmi-marker-filter. This
function now parses the GDB/MI records in the order of arrival. Only
the signature of each record is read by the new parser. The actual
content of the record (i.e. result strings) is still parsed by the
original code (which I will refer to as the record handlers below).
ftp://ftp.gnu.org/pub/old-gnu/Manuals/gdb/html_node/gdb_214.html#SEC221
Thanks. This looks like a very good change indeed. In order for us to
include it in Emacs, we need a copyright assignment; I hope you will be
willing to sign one. I will contact you off-list about how to do this.
Jean-Philippe Gravel
2013-03-01 03:31:03 UTC
Permalink
Post by Chong Yidong
Thanks. This looks like a very good change indeed. In order for us to
include it in Emacs, we need a copyright assignment; I hope you will be
willing to sign one. I will contact you off-list about how to do this.
My copyright assignment is finally complete.

While I was waiting for that, I found a problem with my patch. If you
use the gdb command "finish" to exit from a function, gdb replies with
a dump of the returned value (even though gdb-mi will not show it).
My previous patch was failing with a regexp overflow if the return
value was too big. This new patch will solve this problem.
Stefan Monnier
2013-03-11 17:14:09 UTC
Permalink
Post by Jean-Philippe Gravel
My copyright assignment is finally complete.
While I was waiting for that, I found a problem with my patch. If you
use the gdb command "finish" to exit from a function, gdb replies with
a dump of the returned value (even though gdb-mi will not show it).
My previous patch was failing with a regexp overflow if the return
value was too big. This new patch will solve this problem.
Thank you. I just installed it with the following changes (see patch below):

- gdbmi-debug-mode is a defvar (such debug stuff doesn't deserve a defcustom).
- Use the imperative "Return ..." rather than the present tense "Returns
..." in docstrings, as is the convention. I also integrated a few
other suggestions from C-u M-x checkdoc-current-buffer (some of which
affect code doesn't come from your patch, and there's more to fix).
- Use the new defvar-local.
- Fit within 80 columns.
- Use lexical-binding for closures.

and the following ChangeLog entry:

2013-03-11 Jean-Philippe Gravel <***@gmail.com>

* progmodes/gdb-mi.el: Speed up initialization (bug#10580).
Use lexical-binding. Fix up docstring according to conventions.
(gdbmi-debug-mode): New var.
(gdbmi-start-with, gdbmi-same-start, gdbmi-is-number, gdbmi-bnf-init)
(gdbmi-bnf-output, gdbmi-bnf-skip-unrecognized, gdbmi-bnf-gdb-prompt)
(gdbmi-bnf-result-record, gdbmi-bnf-out-of-band-record)
(gdbmi-bnf-async-record, gdbmi-bnf-stream-record)
(gdbmi-bnf-console-stream-output, gdbmi-bnf-target-stream-output)
(gdbmi-bnf-log-stream-output, gdbmi-bnf-result-and-async-record-impl)
(gdbmi-bnf-incomplete-record-result): New functions.
(gdb-car<): Remove function.
(gdbmi-record-list): Remove variable.
(gdbmi-bnf-state, gdbmi-bnf-offset): New vars.
(gdbmi-bnf-result-state-configs): New const.
(gud-gdbmi-marker-filter): Rewrite.
(gdb-ignored-notification, gdb-thread-created, gdb-thread-exited)
(gdb-thread-selected, gdb-running, gdb-starting, gdb-stopped):
Add `token' argument.
(gdb-done, gdb-error): New functions.
(gdb-done-or-error): Add `is-complete' argument. Change arg order.

Thank you very much for your help,


Stefan


--- lisp/progmodes/gdb-mi.el 2013-03-11 11:37:36.315869212 -0400
+++ lisp/progmodes/gdb-mi.el.new 2013-03-11 11:37:16.117759642 -0400
@@ -1,4 +1,4 @@
-;;; gdb-mi.el --- User Interface for running GDB
+;;; gdb-mi.el --- User Interface for running GDB -*- lexical-binding: t -*-

;; Copyright (C) 2007-2013 Free Software Foundation, Inc.

@@ -192,8 +192,8 @@
(defvar gdb-disassembly-position nil)

(defvar gdb-location-alist nil
- "Alist of breakpoint numbers and full filenames. Only used for files that
-Emacs can't find.")
+ "Alist of breakpoint numbers and full filenames.
+Only used for files that Emacs can't find.")
(defvar gdb-active-process nil
"GUD tooltips display variable values when t, and macro definitions otherwise.")
(defvar gdb-error "Non-nil when GDB is reporting an error.")
@@ -294,9 +294,7 @@
(funcall (cdr subscriber) signal)))

(defvar gdb-buf-publisher '()
- "Used to invalidate GDB buffers by emitting a signal in
-`gdb-update'.
-
+ "Used to invalidate GDB buffers by emitting a signal in `gdb-update'.
Must be a list of pairs with cars being buffers and cdr's being
valid signal handlers.")

@@ -327,8 +325,7 @@
"When in non-stop mode, stopped threads can be examined while
other threads continue to execute.

-GDB session needs to be restarted for this setting to take
-effect."
+GDB session needs to be restarted for this setting to take effect."
:type 'boolean
:group 'gdb-non-stop
:version "23.2")
@@ -336,19 +333,18 @@
;; TODO Some commands can't be called with --all (give a notice about
;; it in setting doc)
(defcustom gdb-gud-control-all-threads t
- "When enabled, GUD execution commands affect all threads when
-in non-stop mode. Otherwise, only current thread is affected."
+ "When non-nil, GUD execution commands affect all threads when
+in non-stop mode. Otherwise, only current thread is affected."
:type 'boolean
:group 'gdb-non-stop
:version "23.2")

(defcustom gdb-switch-reasons t
- "List of stop reasons which cause Emacs to switch to the thread
-which caused the stop. When t, switch to stopped thread no matter
-what the reason was. When nil, never switch to stopped thread
-automatically.
+ "List of stop reasons for which Emacs should switch thread.
+When t, switch to stopped thread no matter what the reason was.
+When nil, never switch to stopped thread automatically.

-This setting is used in non-stop mode only. In all-stop mode,
+This setting is used in non-stop mode only. In all-stop mode,
Emacs always switches to the thread which caused the stop."
;; exited, exited-normally and exited-signaled are not
;; thread-specific stop reasons and therefore are not included in
@@ -404,7 +400,7 @@
:link '(info-link "(gdb)GDB/MI Async Records"))

(defcustom gdb-switch-when-another-stopped t
- "When nil, Emacs won't switch to stopped thread if some other
+ "When nil, don't switch to stopped thread if some other
stopped thread is already selected."
:type 'boolean
:group 'gdb-non-stop
@@ -447,8 +443,7 @@
:version "23.2")

(defcustom gdb-show-threads-by-default nil
- "Show threads list buffer instead of breakpoints list by
-default."
+ "Show threads list buffer instead of breakpoints list by default."
:type 'boolean
:group 'gdb-buffers
:version "23.2")
@@ -490,12 +485,12 @@

(defcustom gdb-create-source-file-list t
"Non-nil means create a list of files from which the executable was built.
- Set this to nil if the GUD buffer displays \"initializing...\" in the mode
- line for a long time when starting, possibly because your executable was
- built from a large number of files. This allows quicker initialization
- but means that these files are not automatically enabled for debugging,
- e.g., you won't be able to click in the fringe to set a breakpoint until
- execution has already stopped there."
+Set this to nil if the GUD buffer displays \"initializing...\" in the mode
+line for a long time when starting, possibly because your executable was
+built from a large number of files. This allows quicker initialization
+but means that these files are not automatically enabled for debugging,
+e.g., you won't be able to click in the fringe to set a breakpoint until
+execution has already stopped there."
:type 'boolean
:group 'gdb
:version "23.1")
@@ -507,12 +502,8 @@
:group 'gdb
:version "22.1")

-(defcustom gdbmi-debug-mode nil
- "When non-nil, all the messages sent or received from GDB/MI are printed in
-the *Messages* buffer."
- :type 'boolean
- :group 'gud
- :version "24.3")
+(defvar gdbmi-debug-mode nil
+ "When non-nil, print the messages sent/received from GDB/MI in *Messages*.")

(defun gdb-force-mode-line-update (status)
(let ((buffer gud-comint-buffer))
@@ -577,7 +568,7 @@

(defmacro gdb-gud-context-call (cmd1 &optional cmd2 noall noarg)
"`gud-call' wrapper which adds --thread/--all options between
-CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'.
+CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'.

NOARG must be t when this macro is used outside `gud-def'"
`(gud-call
@@ -610,7 +601,7 @@

COMMAND-LINE is the shell command for starting the gdb session.
It should be a string consisting of the name of the gdb
-executable followed by command-line options. The command-line
+executable followed by command line options. The command line
options should include \"-i=mi\" to use gdb's MI text interface.
Note that the old \"--annotate\" option is no longer supported.

@@ -1263,7 +1254,7 @@
(cond
((> new previous)
;; Add new children to list.
- (dotimes (dummy previous)
+ (dotimes (_ previous)
(push (pop temp-var-list) var-list))
(dolist (child children)
(let ((varchild
@@ -1277,9 +1268,9 @@
(push varchild var-list))))
;; Remove deleted children from list.
((< new previous)
- (dotimes (dummy new)
+ (dotimes (_ new)
(push (pop temp-var-list) var-list))
- (dotimes (dummy (- previous new))
+ (dotimes (_ (- previous new))
(pop temp-var-list)))))
(push var1 var-list))
(setq var1 (pop temp-var-list)))
@@ -1511,7 +1502,7 @@
(gdb-input
(concat "-inferior-tty-set " tty) 'ignore))))

-(defun gdb-inferior-io-sentinel (proc str)
+(defun gdb-inferior-io-sentinel (proc _str)
(when (eq (process-status proc) 'failed)
;; When the debugged process exits, Emacs gets an EIO error on
;; read from the pty, and stops listening to it. If the gdb
@@ -1771,8 +1762,7 @@
"*"))

(defun gdb-current-context-mode-name (mode)
- "Add thread information to MODE which is to be used as
-`mode-name'."
+ "Add thread information to MODE which is to be used as `mode-name'."
(concat mode
(if gdb-thread-number
(format " [thread %s]" gdb-thread-number)
@@ -1819,7 +1809,8 @@
;; because we may need to update current gud-running value without
;; changing current thread (see gdb-running)
(defun gdb-setq-thread-number (number)
- "Only this function must be used to change `gdb-thread-number'
+ "Set `gdb-thread-number' to NUMBER.
+Only this function must be used to change `gdb-thread-number'
value to NUMBER, because `gud-running' and `gdb-frame-number'
need to be updated appropriately when current thread changes."
;; GDB 6.8 and earlier always output thread-id="0" when stopping.
@@ -1834,7 +1825,7 @@

Note that when `gdb-gud-control-all-threads' is t, `gud-running'
cannot be reliably used to determine whether or not execution
-control buttons should be shown in menu or toolbar. Use
+control buttons should be shown in menu or toolbar. Use
`gdb-running-threads-count' and `gdb-stopped-threads-count'
instead.

@@ -1886,7 +1877,7 @@


(defun gdbmi-start-with (str offset match)
- "Returns non-nil if string STR starts with MATCH, else returns nil.
+ "Return non-nil if string STR starts with MATCH, else returns nil.
OFFSET is the position in STR at which the comparison takes place."
(let ((match-length (length match))
(str-length (- (length str) offset)))
@@ -1894,7 +1885,7 @@
(string-equal match (substring str offset (+ offset match-length))))))

(defun gdbmi-same-start (str offset match)
- "Returns non-nil if STR and MATCH are equal up to the end of either strings, else returns nil.
+ "Return non-nil iff STR and MATCH are equal up to the end of either strings.
OFFSET is the position in STR at which the comparison takes place."
(let* ((str-length (- (length str) offset))
(match-length (length match))
@@ -1904,28 +1895,26 @@
(substring match 0 compare-length)))))

(defun gdbmi-is-number (character)
-"Returns non-nil if CHARACTER is a numerical character between 0 and 9,
-else returns nil."
+ "Return non-nil iff CHARACTER is a numerical character between 0 and 9."
(and (>= character ?0)
(<= character ?9)))


-(defvar gdbmi-bnf-state 'gdbmi-bnf-output
- "Current GDB/MI output parser state. The parser is placed in a
-different state when an incomplete data steam is received from GDB.
+(defvar-local gdbmi-bnf-state 'gdbmi-bnf-output
+ "Current GDB/MI output parser state.
+The parser is placed in a different state when an incomplete data steam is
+received from GDB.
This variable will preserve the state required to resume the parsing
when more data arrives.")
-(make-variable-buffer-local 'gdbmi-bnf-state)

-(defvar gdbmi-bnf-offset 0
- "Offset in gud-marker-acc at which the parser is reading.
+(defvar-local gdbmi-bnf-offset 0
+ "Offset in `gud-marker-acc' at which the parser is reading.
This offset is used to be able to parse the GDB/MI message
in-place, without the need of copying the string in a temporary buffer
or discarding parsed tokens by substringing the message.")
-(make-variable-buffer-local 'gdbmi-bnf-offset)

(defun gdbmi-bnf-init ()
- "Initializes the GDB/MI message parser"
+ "Initialize the GDB/MI message parser."
(setq gdbmi-bnf-state 'gdbmi-bnf-output)
(setq gdbmi-bnf-offset 0)
(setq gud-marker-acc ""))
@@ -1937,16 +1926,16 @@
output ==>
( out-of-band-record )* [ result-record ] gdb-prompt"

- (gdbmi-bnf-skip-unrecognized)
- (while (gdbmi-bnf-out-of-band-record))
- (gdbmi-bnf-result-record)
- (gdbmi-bnf-gdb-prompt))
+ (gdbmi-bnf-skip-unrecognized)
+ (while (gdbmi-bnf-out-of-band-record))
+ (gdbmi-bnf-result-record)
+ (gdbmi-bnf-gdb-prompt))


(defun gdbmi-bnf-skip-unrecognized ()
-"Used as a protection mechanism in case something goes wrong when parsing
-a GDB/MI reply message. This function will skip characters until is encounters
-the beginning of a valid record."
+ "Skip characters until is encounters the beginning of a valid record.
+Used as a protection mechanism in case something goes wrong when parsing
+a GDB/MI reply message."
(let ((acc-length (length gud-marker-acc))
(prefix-offset gdbmi-bnf-offset)
(prompt "(gdb) \n"))
@@ -1956,12 +1945,15 @@
(setq prefix-offset (1+ prefix-offset)))

(if (and (< prefix-offset acc-length)
- (not (member (aref gud-marker-acc prefix-offset) '(?^ ?* ?+ ?= ?~ ?@ ?&)))
+ (not (memq (aref gud-marker-acc prefix-offset)
+ '(?^ ?* ?+ ?= ?~ ?@ ?&)))
(not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt))
- (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc gdbmi-bnf-offset))
+ (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc
+ gdbmi-bnf-offset))
(let ((unrecognized-str (match-string 0 gud-marker-acc)))
(setq gdbmi-bnf-offset (match-end 0))
- (if gdbmi-debug-mode (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
+ (if gdbmi-debug-mode
+ (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
(gdb-shell unrecognized-str)
t))))

@@ -2043,12 +2035,14 @@
'&' c-string"
(when (< gdbmi-bnf-offset (length gud-marker-acc))
(if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&))
- (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc gdbmi-bnf-offset))
+ (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc
+ gdbmi-bnf-offset))
(let ((prefix (match-string 1 gud-marker-acc))
(c-string (match-string 2 gud-marker-acc)))

(setq gdbmi-bnf-offset (match-end 0))
- (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s" (match-string 0 gud-marker-acc)))
+ (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s"
+ (match-string 0 gud-marker-acc)))

(cond ((string-equal prefix "~")
(gdbmi-bnf-console-stream-output c-string))
@@ -2059,16 +2053,16 @@
t))))

(defun gdbmi-bnf-console-stream-output (c-string)
- "Handler for the console-stream-output GDB/MI output grammar rule"
+ "Handler for the console-stream-output GDB/MI output grammar rule."
(gdb-console c-string))

-(defun gdbmi-bnf-target-stream-output (c-string)
- "Handler for the target-stream-output GDB/MI output grammar rule"
+(defun gdbmi-bnf-target-stream-output (_c-string)
+ "Handler for the target-stream-output GDB/MI output grammar rule."
;; Not currently used.
)

(defun gdbmi-bnf-log-stream-output (c-string)
- "Handler for the log-stream-output GDB/MI output grammar rule"
+ "Handler for the log-stream-output GDB/MI output grammar rule."
;; Suppress "No registers." GDB 6.8 and earlier
;; duplicates MI error message on internal stream.
;; Don't print to GUD buffer.
@@ -2087,23 +2081,26 @@
("thread-selected" . (gdb-thread-selected . atomic))
("thread-existed" . (gdb-ignored-notification . atomic))
('default . (gdb-ignored-notification . atomic)))))
- "Two dimensional alist, mapping the type and class of message to a handler function.
-Handler functions are all flagged as either 'progressive' or 'atomic'. 'progressive'
-handlers are capable of parsing incomplete messages. They can be called several time
-with new data chunk as they arrive from GDB. 'progressive' handler must have an extra
-argument that is set to a non-nil value when the message is complete.
+ "Alist of alists, mapping the type and class of message to a handler function.
+Handler functions are all flagged as either `progressive' or `atomic'.
+`progressive' handlers are capable of parsing incomplete messages.
+They can be called several time with new data chunk as they arrive from GDB.
+`progressive' handlers must have an extra argument that is set to a non-nil
+value when the message is complete.

Implement the following GDB/MI output grammar rule:
result-class ==>
'done' | 'running' | 'connected' | 'error' | 'exit'

async-class ==>
- 'stopped' | others (where others will be added depending on the needs--this is still in development).")
+ 'stopped' | others (where others will be added depending on the needs
+ --this is still in development).")

(defun gdbmi-bnf-result-and-async-record-impl ()
- "Common implementation of the result-record and async-record rule. Both rule share
-the same syntax. Those records may be very large in size. For that reason, the 'result'
-part of the record is parsed by gdbmi-bnf-incomplete-record-result, which will keep
+ "Common implementation of the result-record and async-record rule.
+Both rules share the same syntax. Those records may be very large in size.
+For that reason, the \"result\" part of the record is parsed by
+`gdbmi-bnf-incomplete-record-result', which will keep
receiving characters as they arrive from GDB until the record is complete."
(let ((acc-length (length gud-marker-acc))
(prefix-offset gdbmi-bnf-offset))
@@ -2114,7 +2111,8 @@

(if (and (< prefix-offset acc-length)
(member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^))
- (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)" gud-marker-acc gdbmi-bnf-offset))
+ (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)"
+ gud-marker-acc gdbmi-bnf-offset))

(let ((token (match-string 1 gud-marker-acc))
(prefix (match-string 2 gud-marker-acc))
@@ -2124,9 +2122,11 @@
class-command)

(setq gdbmi-bnf-offset (match-end 0))
- (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s" (match-string 0 gud-marker-acc)))
+ (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s"
+ (match-string 0 gud-marker-acc)))

- (setq class-alist (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
+ (setq class-alist
+ (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
(setq class-command (cdr (assoc class class-alist)))
(if (null class-command)
(setq class-command (cdr (assoc 'default class-alist))))
@@ -2136,14 +2136,16 @@
(if (equal (cdr class-command) 'progressive)
(funcall (car class-command) token "" complete)
(funcall (car class-command) token "")))
- (setq gdbmi-bnf-state `(lambda () (gdbmi-bnf-incomplete-record-result ,token ',class-command)))
+ (setq gdbmi-bnf-state
+ (lambda ()
+ (gdbmi-bnf-incomplete-record-result token class-command)))
(funcall gdbmi-bnf-state))
t))))

(defun gdbmi-bnf-incomplete-record-result (token class-command)
"State of the parser used to progressively parse a result-record or async-record
-rule from an incomplete data stream. The parser will stay in this state until the end
-of the current result or async record is reached."
+rule from an incomplete data stream. The parser will stay in this state until
+the end of the current result or async record is reached."
(when (< gdbmi-bnf-offset (length gud-marker-acc))
;; Search the data stream for the end of the current record:
(let* ((newline-pos (string-match "\n" gud-marker-acc gdbmi-bnf-offset))
@@ -2154,10 +2156,13 @@
;; Update the gdbmi-bnf-offset only if the current chunk of data can
;; be processed by the class-command handler:
(when (or is-complete is-progressive)
- (setq result-str (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
+ (setq result-str
+ (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
(setq gdbmi-bnf-offset (+ 1 newline-pos)))

- (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result: %s" (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))
+ (if gdbmi-debug-mode
+ (message "gdbmi-bnf-incomplete-record-result: %s"
+ (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))

;; Update the parsing state before invoking the handler in class-command
;; to make sure it's not left in an invalid state if the handler was
@@ -2171,7 +2176,8 @@
(if is-complete
(funcall (car class-command) token result-str))))

- (unless is-complete ;; Incomplete gdb response: abort the parsing until we receive more data.
+ (unless is-complete
+ ;; Incomplete gdb response: abort parsing until we receive more data.
(if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream"))
(throw 'gdbmi-incomplete-stream nil))

@@ -2242,8 +2248,8 @@
;; gdb-invalidate-threads is defined to accept 'update-threads signal
(defun gdb-thread-created (_token _output-field))
(defun gdb-thread-exited (_token output-field)
- "Handle =thread-exited async record: unset `gdb-thread-number'
- if current thread exited and update threads list."
+ "Handle =thread-exited async record.
+Unset `gdb-thread-number' if current thread exited and update threads list."
(let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
(if (string= gdb-thread-number thread-id)
(gdb-setq-thread-number nil))
@@ -2289,7 +2295,7 @@
(setq gdb-active-process t)
(gdb-emit-signal gdb-buf-publisher 'update-threads))

-(defun gdb-starting (_output-field result)
+(defun gdb-starting (_output-field _result)
;; CLI commands don't emit ^running at the moment so use gdb-running too.
(setq gdb-inferior-status "running")
(gdb-force-mode-line-update
@@ -2462,8 +2468,8 @@
replaced with semicolons.

If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from
-partial output. This is used to get rid of useless keys in lists
-in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
+partial output. This is used to get rid of useless keys in lists
+in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
-break-info are examples of MI commands which issue such
responses.

@@ -2630,16 +2636,16 @@
handler-name
&optional signal-list)
"Define a trigger TRIGGER-NAME which sends GDB-COMMAND and sets
-HANDLER-NAME as its handler. HANDLER-NAME is bound to current
+HANDLER-NAME as its handler. HANDLER-NAME is bound to current
buffer with `gdb-bind-function-to-buffer'.

If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the
-defined trigger is called with an argument from SIGNAL-LIST. It's
+defined trigger is called with an argument from SIGNAL-LIST. It's
not recommended to define triggers with empty SIGNAL-LIST.
Normally triggers should respond at least to 'update signal.

Normally the trigger defined by this command must be called from
-the buffer where HANDLER-NAME must work. This should be done so
+the buffer where HANDLER-NAME must work. This should be done so
that buffer-local thread number may be used in GDB-COMMAND (by
calling `gdb-current-context-command').
`gdb-bind-function-to-buffer' is used to achieve this, see
@@ -2668,32 +2674,33 @@

Delete ((current-buffer) . TRIGGER-NAME) from
`gdb-pending-triggers', erase current buffer and evaluate
-CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called.
+CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called.

If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN."
`(defun ,handler-name ()
(gdb-delete-pending (cons (current-buffer) ',trigger-name))
- (let* ((buffer-read-only nil)
- (window (get-buffer-window (current-buffer) 0))
- (start (window-start window))
- (p (window-point window)))
+ (let* ((inhibit-read-only t)
+ ,@(unless nopreserve
+ '((window (get-buffer-window (current-buffer) 0))
+ (start (window-start window))
+ (p (window-point window)))))
(erase-buffer)
(,custom-defun)
(gdb-update-buffer-name)
- ,(when (not nopreserve)
- '(set-window-start window start)
- '(set-window-point window p)))))
+ ,@(when (not nopreserve)
+ '((set-window-start window start)
+ (set-window-point window p))))))

(defmacro def-gdb-trigger-and-handler (trigger-name gdb-command
handler-name custom-defun
&optional signal-list)
"Define trigger and handler.

-TRIGGER-NAME trigger is defined to send GDB-COMMAND. See
-`def-gdb-auto-update-trigger'.
+TRIGGER-NAME trigger is defined to send GDB-COMMAND.
+See `def-gdb-auto-update-trigger'.

-HANDLER-NAME handler uses customization of CUSTOM-DEFUN. See
-`def-gdb-auto-update-handler'."
+HANDLER-NAME handler uses customization of CUSTOM-DEFUN.
+See `def-gdb-auto-update-handler'."
`(progn
(def-gdb-auto-update-trigger ,trigger-name
,gdb-command
@@ -3050,37 +3057,38 @@
gdb-running-threads-count
gdb-stopped-threads-count))

- (gdb-table-add-row table
- (list
- (bindat-get-field thread 'id)
- (concat
- (if gdb-thread-buffer-verbose-names
- (concat (bindat-get-field thread 'target-id) " ") "")
- (bindat-get-field thread 'state)
- ;; Include frame information for stopped threads
- (if (not running)
- (concat
- " in " (bindat-get-field thread 'frame 'func)
- (if gdb-thread-buffer-arguments
- (concat
- " ("
- (let ((args (bindat-get-field thread 'frame 'args)))
- (mapconcat
- (lambda (arg)
- (apply #'format "%s=%s"
- (gdb-get-many-fields arg 'name 'value)))
- args ","))
- ")")
- "")
- (if gdb-thread-buffer-locations
- (gdb-frame-location (bindat-get-field thread 'frame)) "")
- (if gdb-thread-buffer-addresses
- (concat " at " (bindat-get-field thread 'frame 'addr)) ""))
- "")))
- (list
- 'gdb-thread thread
- 'mouse-face 'highlight
- 'help-echo "mouse-2, RET: select thread")))
+ (gdb-table-add-row
+ table
+ (list
+ (bindat-get-field thread 'id)
+ (concat
+ (if gdb-thread-buffer-verbose-names
+ (concat (bindat-get-field thread 'target-id) " ") "")
+ (bindat-get-field thread 'state)
+ ;; Include frame information for stopped threads
+ (if (not running)
+ (concat
+ " in " (bindat-get-field thread 'frame 'func)
+ (if gdb-thread-buffer-arguments
+ (concat
+ " ("
+ (let ((args (bindat-get-field thread 'frame 'args)))
+ (mapconcat
+ (lambda (arg)
+ (apply #'format "%s=%s"
+ (gdb-get-many-fields arg 'name 'value)))
+ args ","))
+ ")")
+ "")
+ (if gdb-thread-buffer-locations
+ (gdb-frame-location (bindat-get-field thread 'frame)) "")
+ (if gdb-thread-buffer-addresses
+ (concat " at " (bindat-get-field thread 'frame 'addr)) ""))
+ "")))
+ (list
+ 'gdb-thread thread
+ 'mouse-face 'highlight
+ 'help-echo "mouse-2, RET: select thread")))
(when (string-equal gdb-thread-number
(bindat-get-field thread 'id))
(setq marked-line (length gdb-threads-list))))
@@ -3096,8 +3104,8 @@
"Define a NAME command which will act upon thread on the current line.

CUSTOM-DEFUN may use locally bound `thread' variable, which will
-be the value of 'gdb-thread property of the current line. If
-'gdb-thread is nil, error is signaled."
+be the value of 'gdb-thread property of the current line.
+If `gdb-thread' is nil, error is signaled."
`(defun ,name (&optional event)
,(when doc doc)
(interactive (list last-input-event))
@@ -3246,7 +3254,7 @@
(defun gdb-memory-column-width (size format)
"Return length of string with memory unit of SIZE in FORMAT.

-SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as
+SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as
in `gdb-memory-format'."
(let ((format-base (cdr (assoc format
'(("x" . 16)
@@ -3748,8 +3756,7 @@
(error "Not recognized as break/watchpoint line")))))

(defun gdb-goto-breakpoint (&optional event)
- "Go to the location of breakpoint at current line of
-breakpoints buffer."
+ "Go to the location of breakpoint at current line of breakpoints buffer."
(interactive (list last-input-event))
(if event (posn-set-point (event-end event)))
;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer.
@@ -4133,7 +4140,7 @@

(defun gdb-get-source-file-list ()
"Create list of source files for current GDB session.
-If buffers already exist for any of these files, gud-minor-mode
+If buffers already exist for any of these files, `gud-minor-mode'
is set in them."
(goto-char (point-min))
(while (re-search-forward gdb-source-file-regexp nil t)
@@ -4144,8 +4151,8 @@
(gdb-init-buffer)))))

(defun gdb-get-main-selected-frame ()
- "Trigger for `gdb-frame-handler' which uses main current
-thread. Called from `gdb-update'."
+ "Trigger for `gdb-frame-handler' which uses main current thread.
+Called from `gdb-update'."
(if (not (gdb-pending-p 'gdb-get-main-selected-frame))
(progn
(gdb-input (gdb-current-context-command "-stack-info-frame")
@@ -4153,7 +4160,7 @@
(gdb-add-pending 'gdb-get-main-selected-frame))))

(defun gdb-frame-handler ()
- "Sets `gdb-selected-frame' and `gdb-selected-file' to show
+ "Set `gdb-selected-frame' and `gdb-selected-file' to show
overlay arrow in source buffer."
(gdb-delete-pending 'gdb-get-main-selected-frame)
(let ((frame (bindat-get-field (gdb-json-partial-output) 'frame)))
@@ -4214,8 +4221,8 @@

(defun gdb-preempt-existing-or-display-buffer (buf &optional split-horizontal)
"Find window displaying a buffer with the same
-`gdb-buffer-type' as BUF and show BUF there. If no such window
-exists, just call `gdb-display-buffer' for BUF. If the window
+`gdb-buffer-type' as BUF and show BUF there. If no such window
+exists, just call `gdb-display-buffer' for BUF. If the window
found is already dedicated, split window according to
SPLIT-HORIZONTAL and show BUF in the new window."
(if buf
@@ -4603,8 +4610,7 @@
(gud-gdb-fetch-lines-break (length context))
(gud-gdb-fetched-lines nil)
;; This filter dumps output lines to `gud-gdb-fetched-lines'.
- (gud-marker-filter #'gud-gdbmi-fetch-lines-filter)
- complete-list)
+ (gud-marker-filter #'gud-gdbmi-fetch-lines-filter))
(with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
(gdb-input (concat "complete " context command)
(lambda () (setq gud-gdb-fetch-lines-in-progress nil)))

Loading...