; * etc/DEBUG: Improve the redisplay section.

This commit is contained in:
Eli Zaretskii 2023-09-16 09:25:08 +03:00
parent e110312ad9
commit ba924be452

View file

@ -472,6 +472,16 @@ and, assuming that "xtype" says that args[0] is a symbol:
** Debugging Emacs redisplay problems
The Emacs display code includes special debugging code, but it is normally
disabled. Configuring Emacs with --enable-checking='yes,glyphs' enables it.
Building Emacs like that activates many assertions which scrutinize display
code operation more than Emacs does normally. (To see the code which tests
these assertions, look for calls to the 'eassert' macros.) Any assertion that
is reported to fail should be investigated. Redisplay problems that cause
aborts or segfaults in production builds of Emacs will many times be caught by
these assertions before they cause a crash.
If you configured Emacs with --enable-checking='glyphs', you can use redisplay
tracing facilities from a running Emacs session.
@ -481,21 +491,18 @@ code paths taken by the display engine under various conditions, especially if
some redisplay optimizations produce wrong results. (You know that redisplay
optimizations might be involved if "M-x redraw-display RET", or even just
typing "M-x", causes Emacs to correct the bad display.) Since the cursor
blinking feature triggers periodic redisplay cycles, we recommend disabling
'blink-cursor-mode' before invoking 'trace-redisplay', so that you have less
clutter in the trace. You can also have up to 30 last trace messages dumped to
standard error by invoking the 'dump-redisplay-history' command.
blinking feature and ElDoc trigger periodic redisplay cycles, we recommend
disabling 'blink-cursor-mode' and 'global-eldoc-mode' before invoking
'trace-redisplay', so that you have less clutter in the trace. You can also
have up to 30 last trace messages dumped to standard error by invoking the
'dump-redisplay-history' command.
To find the code paths which were taken by the display engine, search xdisp.c
for the trace messages you see.
The command 'dump-glyph-matrix' is useful for producing on standard error
stream a full dump of the selected window's glyph matrix. See the function's
doc string for more details. If you are debugging redisplay issues in
text-mode frames, you may find the command 'dump-frame-glyph-matrix' useful.
Other commands useful for debugging redisplay are 'dump-glyph-row' and
'dump-tool-bar-row'.
doc string for more details.
If you run Emacs under GDB, you can print the contents of any glyph matrix by
just calling that function with the matrix as its argument. For example, the
@ -507,13 +514,11 @@ whose pointer is in 'w':
(The second argument 2 tells dump_glyph_matrix to print the glyphs in
a long form.)
The Emacs display code includes special debugging code, but it is normally
disabled. Configuring Emacs with --enable-checking='yes,glyphs' enables it.
If you are debugging redisplay issues in text-mode frames, you may find the
command 'dump-frame-glyph-matrix' useful.
Building Emacs like that activates many assertions which scrutinize
display code operation more than Emacs does normally. (To see the
code which tests these assertions, look for calls to the 'eassert'
macros.) Any assertion that is reported to fail should be investigated.
Other commands useful for debugging redisplay are 'dump-glyph-row' and
'dump-tool-bar-row'.
When you debug display problems running emacs under X, you can use
the 'ff' command to flush all pending display updates to the screen.
@ -535,36 +540,40 @@ object of the relevant type as argument. For example, 'pgrowx' dumps all
glyphs in its argument, which must be of type 'struct glyph_row'.
Since redisplay is performed by Emacs very frequently, you need to place your
breakpoints cleverly to avoid hitting them all the time, when the issue you are
debugging did not (yet) happen. Here are some useful techniques for that:
breakpoints cleverly to avoid hitting them all the time, when the issue you
are debugging did not (yet) happen. Here are some useful techniques for that:
. Put a breakpoint at 'Fredraw_display' before running Emacs. Then do
whatever is required to reproduce the bad display, and invoke "M-x
redraw-display". The debugger will kick in, and you can set or enable
breakpoints in strategic places, knowing that the bad display will be
. Put a breakpoint at 'Frecenter' or 'Fredraw_display' before running Emacs.
Then do whatever is required to reproduce the bad display, and type C-l or
"M-x redraw-display" just before invoking the last action that reproduces
the bug. The debugger will kick in, and you can set or enable breakpoints
in strategic places, knowing that the bad display will happen soon. With a
breakpoint at 'Fredraw_display', you can even reproduce the bug and invoke
"M-x redraw-display" afterwards, knowing that the bad display will be
redrawn from scratch.
. For debugging incorrect cursor position, a good place to put a breakpoint is
in 'set_cursor_from_row'. The first time this function is called as part of
'redraw-display', Emacs is redrawing the minibuffer window, which is usually
not what you want; type "continue" to get to the call you want. In general,
always make sure 'set_cursor_from_row' is called for the right window and
buffer by examining the value of w->contents: it should be the buffer whose
display you are debugging.
. For debugging incorrect cursor position, a good place to put a breakpoint
is in 'set_cursor_from_row'. The first time this function is called as
part of 'redraw-display', Emacs is redrawing the minibuffer window, which
is usually not what you want; type "continue" to get to the call you want.
In general, always make sure 'set_cursor_from_row' is called for the right
window and buffer by examining the value of w->contents: it should be the
buffer whose display you are debugging.
. 'set_cursor_from_row' is also a good place to look at the contents of a
screen line (a.k.a. "glyph row"), by means of the 'pgrow' GDB command. Of
course, you need first to make sure the cursor is on the screen line which
you want to investigate. If you have set a breakpoint in 'Fredraw_display',
as advised above, move cursor to that line before invoking 'redraw-display'.
you want to investigate. If you have set a breakpoint in 'Fredraw_display'
or 'Frecenter', as advised above, move cursor to that line before invoking
these commands.
. If the problem happens only at some specific buffer position or for some
specific rarely-used character, you can make your breakpoints conditional on
those values. The display engine maintains the buffer and string position
it is processing in the it->current member; for example, the buffer
character position is in it->current.pos.charpos. Most redisplay functions
accept a pointer to a 'struct it' object as their argument, so you can make
conditional breakpoints in those functions, like this:
specific rarely-used character, you can make your breakpoints conditional
on those values. The display engine maintains the buffer and string
position it is processing in the it->current member; for example, the
buffer character position is in it->current.pos.charpos. Most redisplay
functions accept a pointer to a 'struct it' object as their argument, so
you can make conditional breakpoints in those functions, like this:
(gdb) break x_produce_glyphs if it->current.pos.charpos == 1234
@ -578,6 +587,16 @@ debugging did not (yet) happen. Here are some useful techniques for that:
GET_FROM_IMAGE for displaying an image, etc. See 'enum it_method' in
dispextern.h for the full list of values.
. When the display engine is processing a 'display' text property or an
overlay string, it pushes on the iterator stack the state variables
describing its iteration of buffer text, then reinitializes the iterator
object for processing the property or overlay. The it->sp ("stack
pointer") member, if it is greater than zero, means the iterators stack was
pushed at least once. You can therefore condition your breakpoints on the
value of it->sp being positive or being of a certain positive value, to
debug display problems that happen only with display properties or
overlays.
** Debugging problems with native-compiled Lisp.
When you encounter problems specific to native-compilation of Lisp, we