Age | Commit message (Collapse) | Author | Files | Lines |
|
With TERM=ansi, when resizing a TUI window from LINES/COLUMNS 31/118
(maximized) to 20/78 (de-maximized), I get a garbled screen (that ^L doesn't
fix) and a message:
...
@@ resize done 0, size = 77x20
...
with the resulting width being 77 instead of the expected 78.
[ The discrepancy also manifests in CLI, filed as PR30346. ]
The discrepancy comes from tui_resize_all, where we ask readline for the
screen size:
...
rl_get_screen_size (&screenheight, &screenwidth);
...
As it happens, when TERM is set to ansi, readline decides that the terminal
cannot auto-wrap lines, and reserves one column to deal with that, and as a
result reports back one less than the actual screen width:
...
$ echo $COLUMNS
78
$ TERM=xterm gdb -ex "show width" -ex q
Number of characters gdb thinks are in a line is 78.
$ TERM=ansi gdb -ex "show width" -ex q
Number of characters gdb thinks are in a line is 77.
...
In tui_resize_all, we need the actual screen width, and using a screenwidth of
one less than the actual value garbles the screen.
This is currently not causing trouble in testing because we have a workaround
in place in proc Term::resize. If we disable the workaround:
...
- stty columns [expr {$_cols + 1}] < $::gdb_tty_name
+ stty columns $_cols < $::gdb_tty_name
...
and dump the screen we get the same type of screen garbling:
...
0 +---------------------------------------+|
1 ||
2 ||
3 ||
...
Another way to reproduce the problem is using command "maint info screen".
After starting gdb with TERM=ansi, entering TUI, and issuing the command, we
get:
...
Number of characters curses thinks are in a line is 78.
...
and after maximizing and demaximizing the window we get:
...
Number of characters curses thinks are in a line is 77.
...
If we use TERM=xterm, we do get the expected 78.
Fix this by:
- detecting when readline will report back less than the actual screen width,
- accordingly setting a new variable readline_hidden_cols,
- using readline_hidden_cols in tui_resize_all to fix the resize problem, and
- removing the workaround in Term::resize.
The test-case gdb.tui/empty.exp serves as regression test.
I've applied the same fix in tui_async_resize_screen, the new test-case
gdb.tui/resize-2.exp serves as a regression test for that change. Without
that fix, we have:
...
FAIL: gdb.tui/resize-2.exp: again: gdb width 80
...
Tested on x86_64-linux.
PR tui/30337
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30337
|
|
Latest libc++[1] causes transitive include to <locale> when
<mutex> or <thread> header is included. This causes
gdb to not build[2] since <locale> defines isupper/islower etc.
functions that are explicitly macroed-out in safe-ctype.h to
prevent their use.
Use the suggestion from libc++ to include <locale> internally when
building in C++ mode to avoid build errors.
Use safe-gdb-ctype.h as the include instead of "safe-ctype.h"
to keep this isolated to gdb since rest of binutils
does not seem to use much C++.
[1]: https://reviews.llvm.org/D144331
[2]: https://issuetracker.google.com/issues/277967395
|
|
In commit 5d10a2041eb ("gdb: add string_file::release method") this was added:
...
+ std::string string_val = string.release ();
...
without updating subsequent uses of string.size (), which returns 0 after the
string.release () call.
Fix this by:
- using string_val.size () instead of string.size (), and
- adding an assert that would have caught this regression.
Tested on x86_64-linux.
Reviewed-By: Simon Marchi <simon.marchi@efficios.com>
PR tui/30389
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30389
|
|
The m_digits member of tui_source_window is documented as having semantics:
...
/* How many digits to use when formatting the line number. This
includes the trailing space. */
...
The commit 1b6d4bb2232 ("Redraw both spaces between line numbers and source
code") started printing two trailing spaces instead:
...
- xsnprintf (text, sizeof (text), "%*d ", m_digits - 1, lineno);
+ xsnprintf (text, sizeof (text), "%*d ", m_digits - 1, lineno);
...
Now that PR30325 is fixed, this no longer has any effect.
Fix this by reverting to the original behaviour: print one trailing space
char.
Tested on x86_64-linux.
Approved-By: Tom Tromey <tom@tromey.com>
|
|
With a hello world a.out, and maint set tui-left-margin-verbose on, we have
this disassembly window:
...
┌───────────────────────────────────────────────────────────┐
│___ 0x555555555149 <main> endbr64 │
│___ 0x55555555514d <main+4> push %rbp │
│___ 0x55555555514e <main+5> mov %rsp,%rbp │
│B+> 0x555555555151 <main+8> lea 0xeac(%rip),%rax│
│___ 0x555555555158 <main+15> mov %rax,%rdi │
...
Note the space between "B+>" and 0x555555555151. The space shows that a bit
of the left margin is not written, which is a problem because that location is
showing a character previously written, which happens to be a space, but also
may be something else, for instance a '[' as reported in PR tui/30325.
The problem is caused by confusion about the meaning of:
...
#define TUI_EXECINFO_SIZE 4
...
There's the meaning of defining the size of this zero-terminated char array:
...
char element[TUI_EXECINFO_SIZE];
...
which is used to print the "B+>" bit, which is 3 chars wide.
And there's the meaning of defining part of the size of the left margin:
...
int left_margin () const
{ return 1 + TUI_EXECINFO_SIZE + extra_margin (); }
...
where it represents 4 chars.
The discrepancy between the two causes the space between "B+>" and
"0x555555555151".
Fix this by redefining TUI_EXECINFO_SIZE to 3, and using:
...
char element[TUI_EXECINFO_SIZE + 1];
...
such that we have:
...
|B+>0x555555555151 <main+8> lea 0xeac(%rip),%rax │
...
This changes the layout of the disassembly window back to what it was before
commit 9e820dec13e ("Use a curses pad for source and disassembly windows"),
the commit that introduced the PR30325 regression.
This also changes the source window from:
...
│___000005__{ |
...
to:
...
│___000005_{ |
...
Tested on x86_64-linux.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30325
Approved-By: Tom Tromey <tom@tromey.com>
|
|
The TUI has two types of windows derived from tui_source_window_base:
- tui_source_window (the source window), and
- tui_disasm_window (the disassembly window).
The two windows share a common concept: the left margin.
With a hello world a.out, we can see the source window:
...
┌─/home/vries/hello.c───────────────────────────────────────┐
│ 5 { │
│B+> 6 printf ("hello\n"); │
│ 7 return 0; │
│ 8 } │
│ 9 │
│
...
where the left margin is the part holding "B+>" and the line number, and the
disassembly window:
...
┌───────────────────────────────────────────────────────────┐
│ 0x555555555149 <main> endbr64 │
│ 0x55555555514d <main+4> push %rbp │
│ 0x55555555514e <main+5> mov %rsp,%rbp │
│B+> 0x555555555151 <main+8> lea 0xeac(%rip),%rax│
│ 0x555555555158 <main+15> mov %rax,%rdi │
...
where the left margin is just the bit holding "B+>".
Because the left margin contains some spaces, it's not clear where it starts
and ends, making it harder to observe problems related to it.
Add a new maintenance command "maint set tui-left-margin-verbose", that when
set to on replaces the spaces in the left margin with either '_' or '0',
giving us this for the source window:
...
┌─/home/vries/hello.c───────────────────────────────────────┐
│___000005__{ │
│B+>000006__ printf ("hello\n"); │
│___000007__ return 0; │
│___000008__} │
...
and this for the disassembly window:
...
┌───────────────────────────────────────────────────────────┐
│___ 0x555555555149 <main> endbr64 │
│___ 0x55555555514d <main+4> push %rbp │
│___ 0x55555555514e <main+5> mov %rsp,%rbp │
│B+> 0x555555555151 <main+8> lea 0xeac(%rip),%rax│
│___ 0x555555555158 <main+15> mov %rax,%rdi │
...
Note the space between "B+>" and 0x555555555151. The space shows that a bit
of the left margin is not written, a problem reported as PR tui/30325.
Specifically, PR tui/30325 is about the fact that the '[' character from the
string "[ No Assembly Available ]" ends up in that same spot:
...
│B+>[0x555555555151 <main+8> lea 0xeac(%rip),%rax│
...
which only happens for certain window widths.
The new command allows us to spot the problem with any window width.
Likewise, when we revert the fix from commit 1b6d4bb2232 ("Redraw both spaces
between line numbers and source code"), we have:
...
┌─/home/vries/hello.c───────────────────────────────────────┐
│___000005_ { │
│B+>000006_ printf ("hello\n"); │
│___000007_ return 0; │
│___000008_ } │
...
showing a similar problem at the space between '_' and '{'.
Tested on x86_64-linux.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
|
|
Replace spaces with tabs in a bunch of places.
Change-Id: If0f87180f1d13028dc178e5a8af7882a067868b0
|
|
During my audit of the use of gdb_exception with regard to QUIT
processing, I found a try/catch in the scoped_switch_fork_info
destructor.
Static analysis found this call path from the destructor to
maybe_quit():
scoped_switch_fork_info::~scoped_switch_fork_info()
-> remove_breakpoints()
-> remove_breakpoint(bp_location*)
-> remove_breakpoint_1(bp_location*, remove_bp_reason)
-> memory_validate_breakpoint(gdbarch*, bp_target_info*)
-> target_read_memory(unsigned long, unsigned char*, long)
-> target_read(target_ops*, target_object, char const*, unsigned char*, unsigned long, long)
-> maybe_quit()
Since it's not safe to do a 'throw' from a destructor, we simply
call set_quit_flag and, for gdb_exception_forced_quit, also
set sync_quit_force_run. This will cause the appropriate
exception to be rethrown at the next QUIT check.
Another case is the try / catch in tui_getc() in tui-io.c. The
existing catch swallows the exception. I've added a catch for
'gdb_exception_forced_quit', which also swallows the exception,
but also sets sync_quit_force_run and calls set_quit_flag in
order to restart forced quit processing at the next QUIT check.
This is required because it isn't safe to throw into/through
readline.
Thanks to Pedro Alves for suggesting this idea.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=26761
Tested-by: Tom de Vries <tdevries@suse.de>
Approved-By: Pedro Alves <pedro@palves.net>
|
|
I noticed that the TUI temporarily sets pagination_enabled and
gdb_stdout in one spot. However, I don't believe these settings are
necessary here, as a ui_file is passed to
gdbarch_print_registers_info. This patch removes these settings.
|
|
This commit finishes the task that was started in the previous
commit.
Now that all Python TUI window factories are correctly deleted when
the Python interpreter is shut down, we no longer need to dynamically
allocate the known_window_types map in tui-layout.c
This commit changes known_window_types to a statically allocated data
structure, removes the dynamic allocation from
initialize_known_windows, and then replaces lots of '->' with '.'
throughout this file.
There should be no user visible changes after this commit.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
The documentation for gdb.register_window_type says:
"... It's an error to try to replace one of the built-in windows,
but other window types can be replaced. ..."
I take this to mean that if I imported a Python script like this:
gdb.register_window_type('my_window', FactoryFunction)
Then GDB would have a new TUI window 'my_window', which could be
created by calling FactoryFunction(). If I then, in the same GDB
session imported a script which included:
gdb.register_window_type('my_window', UpdatedFactoryFunction)
Then GDB would replace the old 'my_window' factory with my new one,
GDB would now call UpdatedFactoryFunction().
This is pretty useful in practice, as it allows users to iterate on
their window implementation within a single GDB session.
However, right now, this is not how GDB operates. The second call to
register_window_type is basically ignored and the old window factory
is retained.
This is because in tui_register_window (tui/tui-layout.c) we use
std::unordered_map::emplace to insert the new factory function, and
emplace doesn't replace an existing element in an unordered_map.
In this commit, before the emplace call, I now search for an already
existing element, and delete any matching element from the map, the
emplace call will then add the new factory function.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This patch implements a simplication that I suggested here:
https://sourceware.org/pipermail/gdb-patches/2022-March/186320.html
Currently, the interp::exec virtual method interface is such that
subclass implementations must catch exceptions and then return them
via normal function return.
However, higher up the in chain, for the CLI we get to
interpreter_exec_cmd, which does:
for (i = 1; i < nrules; i++)
{
struct gdb_exception e = interp_exec (interp_to_use, prules[i]);
if (e.reason < 0)
{
interp_set (old_interp, 0);
error (_("error in command: \"%s\"."), prules[i]);
}
}
and for MI we get to mi_cmd_interpreter_exec, which has:
void
mi_cmd_interpreter_exec (const char *command, char **argv, int argc)
{
...
for (i = 1; i < argc; i++)
{
struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
if (e.reason < 0)
error ("%s", e.what ());
}
}
Note that if those errors are reached, we lose the original
exception's error code. I can't see why we'd want that.
And, I can't see why we need to have interp_exec catch the exception
and return it via the normal return path. That's normally needed when
we need to handle propagating exceptions across C code, like across
readline or ncurses, but that's not the case here.
It seems to me that we can simplify things by removing some
try/catch-ing and just letting exceptions propagate normally.
Note, the "error in command" error shown above, which only exists in
the CLI interpreter-exec command, is only ever printed AFAICS if you
run "interpreter-exec console" when the top level interpreter is
already the console/tui. Like:
(gdb) interpreter-exec console "foobar"
Undefined command: "foobar". Try "help".
error in command: "foobar".
You won't see it with MI's "-interpreter-exec console" from a top
level MI interpreter:
(gdb)
-interpreter-exec console "foobar"
&"Undefined command: \"foobar\". Try \"help\".\n"
^error,msg="Undefined command: \"foobar\". Try \"help\"."
(gdb)
nor with MI's "-interpreter-exec mi" from a top level MI interpreter:
(gdb)
-interpreter-exec mi "-foobar"
^error,msg="Undefined MI command: foobar",code="undefined-command"
^done
(gdb)
in both these cases because MI's -interpreter-exec just does:
error ("%s", e.what ());
You won't see it either when running an MI command with the CLI's
"interpreter-exec mi":
(gdb) interpreter-exec mi "-foobar"
^error,msg="Undefined MI command: foobar",code="undefined-command"
(gdb)
This last case is because MI's interp::exec implementation never
returns an error:
gdb_exception
mi_interp::exec (const char *command)
{
mi_execute_command_wrapper (command);
return gdb_exception ();
}
Thus I think that "error in command" error is pretty pointless, and
since it simplifies things to not have it, the patch just removes it.
The patch also ends up addressing an old FIXME.
Change-Id: I5a6432a80496934ac7127594c53bf5221622e393
Approved-By: Tom Tromey <tromey@adacore.com>
Approved-By: Kevin Buettner <kevinb@redhat.com>
|
|
Add some additional debug output that I've found really useful while
working on the previous set of patches.
Unless tui debug is turned on, then there should be no user visible
changes with this commit.
|
|
While working on the previous couple of patches I noticed that when I
scroll the src and asm windows vertically, I get two refresh_window
calls.
The two calls can be traced back to
tui_source_window_base::update_source_window_as_is, in here we call
show_source_content, which calls refresh_window, and then
update_exec_info, which also calls refresh_window.
In this commit I propose making the refresh_window call in
update_exec_info optional. In update_source_window_as_is I'll then
call update_exec_info before calling show_source_content, and pass a
flag to update_exec_info to defer the refresh.
There are places where update_exec_info is used without any subsequent
refresh_window call (e.g. when a breakpoint is updated), so
update_exec_info does not to call refresh_window in some cases, which
is why I'm using a flag to control the refresh.
With this changes I'm now only seeing a single refresh_window call for
each vertical scroll.
There should be no user visible changes after this commit.
|
|
While working on the previous patches I noticed that in some cases I
was seeing two calls to tui_source_window_base::refresh_window when
scrolling the window horizontally.
The two calls would trigger in for the tui-disasm-long-lines.exp test
when the pad needed to be refilled. The two called both come from
tui_source_window_base::show_source_content. The first call is nested
within check_and_display_highlight_if_needed, while the second call is
done directly at the end of show_source_content.
The check_and_display_highlight_if_needed is being used to draw the
window box to the window, this is needed here because
show_source_content is what gets called when the window needs
updating, e.g. after a resize. We could potentially do the boxing in
refresh_window, but then we'd be doing it each time we scroll, even
though the box doesn't need changing in this case.
However, we can move the check_and_display_highlight_if_needed to be
the last thing done in show_source_content, this means that we can
rely on the refresh_window call within it to be our single refresh
call.
There should be no user visible changes after this commit.
|
|
This commit addresses an issue that is exposed by the test script
gdb.tui/tui-disasm-long-lines.exp, that is, tui_source_window_base
does not handle very long lines.
The problem can be traced back to the newpad call in
tui_source_window_base::show_source_content, this is where we allocate
a backing pad to hold the window content.
Unfortunately, there appears to be a limit to the size of pad that can
be allocated, and the gdb.tui/tui-disasm-long-lines.exp test goes
beyond this limit. As a consequence the newpad call fails and returns
nullptr.
It just so happens that the reset of the tui_source_window_base code
can handle the pad being nullptr (this happens anyway when the window
is first created, so we already depend on nullptr handling), so all
that happens is the source window displays no content.
... well, sort of ... something weird does happen in the command
window, we seem to see a whole bunch of blank lines. I've not
bothered to track down exactly what's happening there, but it's some
consequence of GDB attempting to write content to a WINDOW* that is
nullptr.
Before explaining my solution, I'll outline how things currently work:
Consider we have the following window content to display:
aaaaaaaaaa
bbbbbbbbbbbbbbbbbbbb
ccccccccccccccc
the longest line here is 20 characters. If our display window is 10
characters wide, then we will create a pad that is 20 characters wide,
and then copy the lines of content into the pad:
.--------------------.
|aaaaaaaaaa |
|bbbbbbbbbbbbbbbbbbbb|
|ccccccccccccccc |
.--------------------.
Now we will copy a 10 character wide view into this pad to the
display, our display will then see:
.----------.
|aaaaaaaaaa|
|bbbbbbbbbb|
|cccccccccc|
.----------.
As the user scrolls left and right we adjust m_horizontal_offset and
use this to select which part of the pad is copied onto the display.
The benefit of this is that we only need to copy the content to the
pad once, which includes processing the ansi escape sequences, and
then the user can scroll left and right as much as they want
relatively cheaply.
The problem then, is that if the longest content line is very long,
then we try to allocate a very large pad, which can fail.
What I propose is that we allow both the pad and the display view to
scroll. Once we allow this, then it becomes possible to allocate a
pad that is smaller than the longest display line. We then copy part
of the content into the pad. As the user scrolls the view left and
right GDB will continue to copy content from the pad just as it does
right now. But, when the user scrolls to the edge of the pad, GDB
will copy a new block of content into the pad, and then update the
view as normal. This all works fine so long as the maximum pad size
is larger than the current window size - which seems a reasonable
restriction, if ncurses can't support a pad of a given size it seems
likely it will not support a display window of that size either.
If we return to our example above, but this time we assume that the
maximum pad size is 15 characters, then initially the pad would be
loaded like this:
.---------------.
|aaaaaaaaaa |
|bbbbbbbbbbbbbbb|
|ccccccccccccccc|
.---------------.
Notice that the last 5 characters from the 'b' line are no longer
included in the pad. There is still enough content though to fill the
10 character wide display, just as we did before.
The pad contents remain unchanged until the user scrolls the display
right to this point:
.----------.
|aaaaa |
|bbbbbbbbbb|
|cccccccccc|
.----------.
Now, when the user scrolls right once more GDB spots that the user has
reached the end of the pad, and the pad contents are reloaded, like
this:
.---------------.
|aaaaa |
|bbbbbbbbbbbbbbb|
|cccccccccc |
.---------------.
The display can now be updated from the pad again just like normal.
With this change in place the gdb.tui/tui-disasm-long-lines.exp test
now correctly loads the assembler code, and we can scroll around as
expected.
Most of the changes are pretty mundane, just updating to match the
above. One interesting change though is the new member function
tui_source_window_base::puts_to_pad_with_skip. This replaces direct
calls to tui_puts when copying content to the pad.
The content strings contain ansi escape sequences. When these strings
are written to the pad these escape sequences are translated into
ncurses attribute setting calls.
Now however, we sometimes only write a partial string to the pad,
skipping some of the leading content. Imagine then that we have a
content line like this:
"\033[31mABCDEFGHIJKLM\033[0m"
Now the escape sequences in this content mean that the actual
content (the 'ABCDEFGHIJKLM') will have a red foreground color.
If we want to copy this to the pad, but skip the first 3 characters,
then what we expect is to have the pad contain 'DEFGHIJKLM', but this
text should still have a red foreground color.
It is this problem that puts_to_pad_with_skip solves. This function
skips some number of printable characters, but processes all the
escape sequences. This means that when we do start printing the
actual content the content will have the expected attributes.
/
|
|
I noticed that tui_source_window_base::m_horizontal_offset was
protected, but could be made private, so lets do that.
This makes more sense in the context of a later commit where I plan to
add another member variable that is similar to m_horizontal_offset.
The new member variable could also be private.
So I had to choose, place the new member variable next to
m_horizontal_offset making it protected, but grouping similar
variables together, or make m_horizontal_offset private, and then add
the new variable as private too.
I chose to make m_horizontal_offset private, which is this commit.
There should be no user visible changes after this commit.
|
|
This commit improves (I think) the errors from the tui focus command.
There are a number of errors that can be triggered by the focus
command, they include:
(1) Window name "NAME" is ambiguous
(2) Unrecognized window name "NAME"
(3) Window "NAME" cannot be focused
Error (1) is triggered when the user gives a partial window name, and
the name matches multiple windows in the current layout.
It is worth noting that the ambiguity must be within the current
layout; if the partial name matches one window in the current layout,
and one or more windows not in the current layout, then this is not
ambiguous, and focus will shift to the matching window in the current
layout.
This error was not previous being tested, but in this commit I make
use of the Python API to trigger and test this error.
Error (3) is simple enough, and was already being tested. This is
triggered by something like 'focus status'. The named window needs to
be present in the current layout, and non-focusable in order to
trigger the error.
Error (2) is what I'd like to improve in this commit. This error
triggers if the name the user gives doesn't match any window in the
current layout. Even if GDB does know about the window, but the
window isn't in the current layout, then GDB will say it doesn't
recognize the window name.
In this commit I propose to to split this error into three different
errors. These will be:
(a) Unrecognized window name "NAME"
(b) No windows matching "NAME" in the current layout
(c) Window "NAME" is not in the current layout
Error (a) is the same as before, but will now only trigger if GDB
doesn't know about window NAME at all. If the window is known, but
not in the current layout then one of the other errors will trigger.
Error (b) will trigger if NAME is ambiguous for multiple windows that
are not in the current layout. If NAME identifies a single window in
the current layout then that window will continue to be selected, just
as it currently is. Only in the case where NAME doesn't identify a
window in the current layout do we then check all the other known
windows, if NAME matches multiple of these, then (b) is triggered.
Finally, error (c) is used when NAME uniquely identifies a single
window that is not in the current layout.
The hope with these new errors is that the user will have a better
understanding of what went wrong. Instead of GDB claiming to not know
about a window, the mention of the current layout will hint to the
user that they should first switch layouts.
There are tests included for all the new errors.
|
|
Make use of a scoped_restore object in tui_mld_read_key instead of
doing a manual save/restore.
I don't think the existing code can throw an exception, so this is
just a cleanup rather than a bug fix.
There should be no user visible changes after this commit.
|
|
While working on the previous couple of commits, I noticed that the
'focus' command would happily suggest 'status' as a possible focus
completion, even though the 'status' window is non-focusable, and,
after the previous couple of commits, trying to focus the status
window will result in an error.
This commit improves the tab-completion results for the focus command
so that the status window is not included.
|
|
While working on the previous commit, I realised that there was an
error in tui_set_focus_command that could never be triggered.
Since the big tui rewrite (adding dynamic layouts) it is no longer
true that there is a tui_win_info object for every window at all
times. We now only create a tui_win_info object for a particular
window, when the window is part of the current layout. As a result,
if we have a tui_win_info pointer, then the window must be visible
inside tui_set_focus_command (this function calls tui_enable as its
first action, which makes the current layout visible).
The gdb.tui/tui-focus.exp test script exercises this area of code, and
doesn't trigger the assert, nor do any of our other existing tui
tests.
|
|
I noticed that we didn't have many tests of the tui 'focus' command,
so I started adding some. This exposed a bug in GDB; we are able to
focus windows that should not be focusable, e.g. the 'status' window.
This is harmless until we then do 'focus next' or 'focus prev', along
this code path we assert that the currently focused window is
focusable, which obviously, is not always true, so GDB fails with an
assertion error.
The fix is simple; add a check to the tui_set_focus_command function
to ensure that the selected window is focusable. If it is not then an
error is thrown. The new tests I've added cover this case.
|
|
This commit is the result of running the gdb/copyright.py script,
which automated the update of the copyright year range for all
source files managed by the GDB project to be updated to include
year 2023.
|
|
I stumbled across subset_compare today, and after looking at the
callers I realized it could be removed and replaced with calls to
startswith.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
|
|
I noticed a couple of spots that used '0' rather than 'false' when
modifying pagination_enabled. This patch cleans these up.
|
|
As discussed at:
https://sourceware.org/pipermail/gdb-patches/2020-June/169519.html
this patch disables source and assembly code highlighting for the
text highlighted by the TUI's current position indicator, and adds a
command to enable it back.
|
|
Fix some whitespace issues introduced with the frame_info_ptr patch.
Change-Id: I158d30d8108c97564276c647fc98283ff7b12163
|
|
Currently, every internal_error call must be passed __FILE__/__LINE__
explicitly, like:
internal_error (__FILE__, __LINE__, "foo %d", var);
The need to pass in explicit __FILE__/__LINE__ is there probably
because the function predates widespread and portable variadic macros
availability. We can use variadic macros nowadays, and in fact, we
already use them in several places, including the related
gdb_assert_not_reached.
So this patch renames the internal_error function to something else,
and then reimplements internal_error as a variadic macro that expands
__FILE__/__LINE__ itself.
The result is that we now should call internal_error like so:
internal_error ("foo %d", var);
Likewise for internal_warning.
The patch adjusts all calls sites. 99% of the adjustments were done
with a perl/sed script.
The non-mechanical changes are in gdbsupport/errors.h,
gdbsupport/gdb_assert.h, and gdb/gdbarch.py.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: Ia6f372c11550ca876829e8fd85048f4502bdcf06
|
|
This changes GDB to use frame_info_ptr instead of frame_info *
The substitution was done with multiple sequential `sed` commands:
sed 's/^struct frame_info;/class frame_info_ptr;/'
sed 's/struct frame_info \*/frame_info_ptr /g' - which left some
issues in a few files, that were manually fixed.
sed 's/\<frame_info \*/frame_info_ptr /g'
sed 's/frame_info_ptr $/frame_info_ptr/g' - used to remove whitespace
problems.
The changed files were then manually checked and some 'sed' changes
undone, some constructors and some gets were added, according to what
made sense, and what Tromey originally did
Co-Authored-By: Bruno Larsen <blarsen@redhat.com>
Approved-by: Tom Tomey <tom@tromey.com>
|
|
After the previous few commit, gdbarch_register_name no longer returns
nullptr. This commit audits all the calls to gdbarch_register_name
and removes any code that checks the result against nullptr.
There should be no visible change after this commit.
|
|
I noticed that, from Python, I could register a new TUI window that
had whitespace in its name, like this:
gdb.register_window_type('my window', MyWindowType)
however, it is not possible to then use this window in a new TUI
layout, e.g.:
(gdb) tui new-layout foo my window 1 cmd 1
Unknown window "my"
(gdb) tui new-layout foo "my window" 1 cmd 1
Unknown window ""my"
(gdb) tui new-layout foo my\ window 1 cmd 1
Unknown window "my\"
GDB clearly uses the whitespace to split the incoming command line.
I could fix this by trying to add a mechanism by which we can use
whitespace within a window name, but it seems like an easier solution
if we just forbid whitespace within a window name. Not only is this
easier, but I think this is probably the better solution, identifier
names with spaces in would mean we'd need to audit all the places a
window name could be printed and ensure that the use of a space didn't
make the output ambiguous.
So, having decided to disallow whitespace, I then thought about other
special characters. We currently accept anything as a window name,
and I wondered if this was a good idea.
My concerns were about how special characters used in a window name
might cause confusion, for example, we allow '$' in window names,
which is maybe fine now, but what if one day we wanted to allow
variable expansion when creating new layouts? Or what about starting
a window name with '-'? We already support a '-horizontal' option,
what if we want to add more in the future? Or use of the special
character '{' which has special meaning within a new layout?
In the end I figured it might make sense to place some restrictive
rules in place, and then relax the rules later if/when users complain,
we can consider each relaxation as its requested.
So, I propose that window names should match this regular expression:
[a-zA-Z][-_.a-zA-Z0-9]*
There is a chance that there is user code in the wild which will break
with the addition of this change, but hopefully adapting to the new
restrictions shouldn't be too difficult.
|
|
I went through all the uses of dynamic_cast<> in gdb, looking for ones
that could be replaced with checked_static_cast. This patch is the
result. Regression tested on x86-64 Fedora 34.
|
|
PR mi/15811 points out that "source"ing a file that uses
interpreter-exec will put gdb in a weird state, where the CLI stops
working. The bug is that tui_interp::suspend does not unregister the
event file descriptor.
The test case is from Andrew Burgess.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15811
|
|
The TUI checks against gdb_stdout to decide when to buffer. It seems
much cleaner to me to simply record this as an attribute of the stream
itself.
|
|
tui_out_new is just a simple wrapper for 'new' and can be removed,
simplifying gdb a tiny bit.
|
|
A few spots setting some gdb output stream variables have a "for
moment" comment. These comments aren't useful and I think the moment
has passed -- these are permanent now.
|
|
cli_out_new is just a small wrapper around 'new'. This patch removes
it, replacing it with uses of 'new' instead.
|
|
For historical reasons, the CLI and the TUI observers are basically
exact duplicates, except for the downcast:
cli:
struct cli_interp *cli = as_cli_interp (interp);
tui:
struct interp *tui = as_tui_interp (interp);
and how they get at the interpreter's ui_out:
cli:
cli->cli_uiout
tui:
tui->interp_ui_out ()
Since interp_ui_out() is a virtual method that also works for the CLI
interpreter, and, both the CLI and the TUI interpreters inherit from
the same base class (cli_interp_base), we can convert the CLI
observers to cast to cli_interp_base instead and use interp_ui_out()
too. With that, the CLI observers will work for the TUI interpreter
as well. This lets us completely eliminate the TUI observers. That's
what this commit does.
Change-Id: Iaf6cf12dfa200ed3ab203a895a72b69dfedbd6e0
|
|
The global interpreter_p is a manually-managed 'char *'. This patch
changes it to be a std::string instead, and removes some erroneous
comments.
|
|
Remove all macros related to getting and setting some symbol value:
#define SYMBOL_VALUE(symbol) (symbol)->value.ivalue
#define SYMBOL_VALUE_ADDRESS(symbol) \
#define SET_SYMBOL_VALUE_ADDRESS(symbol, new_value) \
#define SYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes
#define SYMBOL_VALUE_COMMON_BLOCK(symbol) (symbol)->value.common_block
#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block
#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->value.chain
#define MSYMBOL_VALUE(symbol) (symbol)->value.ivalue
#define MSYMBOL_VALUE_RAW_ADDRESS(symbol) ((symbol)->value.address + 0)
#define MSYMBOL_VALUE_ADDRESS(objfile, symbol) \
#define BMSYMBOL_VALUE_ADDRESS(symbol) \
#define SET_MSYMBOL_VALUE_ADDRESS(symbol, new_value) \
#define MSYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes
#define MSYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block
Replace them with equivalent methods on the appropriate objects.
Change-Id: Iafdab3b8eefc6dc2fd895aa955bf64fafc59ed50
|
|
Same idea as previous patch, but for symtab::objfile. I find
it clearer without this wrapper, as it shows that the objfile is
common to all symtabs of a given compunit. Otherwise, you could think
that each symtab (of a given compunit) can have a specific objfile.
Change-Id: Ifc0dbc7ec31a06eefa2787c921196949d5a6fcc6
|
|
Move 'struct reggroup' into the reggroups.h header. Remove the
reggroup_name and reggroup_type accessor functions, and just use the
name/type member functions within 'struct reggroup', update all uses
of these removed functions.
There should be no user visible changes after this commit.
|
|
Add a new function gdbarch_reggroups that returns a reference to a
vector containing all the reggroups for an architecture.
Make use of this function throughout GDB instead of the existing
reggroup_next and reggroup_prev functions.
Finally, delete the reggroup_next and reggroup_prev functions.
Most of these changes are pretty straight forward, using range based
for loops instead of the old style look using reggroup_next. There
are two places where the changes are less straight forward.
In gdb/python/py-registers.c, the register group iterator needed to
change slightly. As the iterator is tightly coupled to the gdbarch, I
just fetch the register group vector from the gdbarch when needed, and
use an index counter to find the next item from the vector when
needed.
In gdb/tui/tui-regs.c the tui_reg_next and tui_reg_prev functions are
just wrappers around reggroup_next and reggroup_prev respectively.
I've just inlined the logic of the old functions into the tui
functions. As the tui function had its own special twist (wrap around
behaviour) I think this is OK.
There should be no user visible changes after this commit.
|
|
Start GDB like:
$ gdb -q executable
(gdb) start
(gdb) layout src
... tui windows are now displayed ...
(gdb) tui reg next
At this point the data (register) window should be displayed, but will
contain the message 'Register Values Unavailable', and at the console
you'll see the message "unknown register group 'next'".
The same happens with 'tui reg prev' (but the error message is
slightly different).
At this point you can continue to use 'tui reg next' and/or 'tui reg
prev' and you'll keep getting the error message.
The problem is that when the data (register) window is first
displayed, it's current register group is nullptr. As a consequence
tui_reg_next and tui_reg_prev (tui/tui-regs.c) will always just return
nullptr, which triggers an error in tui_reg_command.
In this commit I change tui_reg_next and tui_reg_prev so that they
instead return the first and last register group respectively if the
current register group is nullptr.
So, after this, using 'tui reg next' will (in the above case) show the
first register group, while 'tui reg prev' will display the last
register group.
|
|
While looking at the 'tui reg' command as part of another patch, I
spotted a theoretical bug.
The 'tui reg' command takes the name of a register group, but also
handles partial register group matches, though the partial match has to
be unique. The current command logic goes:
With the code as currently written, if a target description named a
register group either 'prev' or 'next' then GDB would see this as an
ambiguous register name, and refuse to switch groups.
Naming a register group 'prev' or 'next' seems pretty unlikely, but,
by adding a single else block we can prevent this problem.
Now, if there's a 'prev' or 'next' register group, the user will not
be able to select the group directly, the 'prev' and 'next' names will
always iterate through the available groups instead. But at least the
user could select their groups by iteration, rather than direct
selection.
|
|
Make uses of 'reggroup *' const throughout tui-regs.{c,h}.
There should be no user visible changes after this commit.
|
|
Currently, in master gdb, when a tui window is changed in size, the
screen delta is mostly just added to the next available window. We
do take care to respect the min/max size, but in most cases, these
limits are just "the terminal size", and so, we end up placing the
whole delta on the next window.
Consider these steps in an 80 column, 24 line terminal:
(gdb) tui enable
(gdb) layout src
(gdb) layout split
(gdb) info win
Name Lines Columns Focus
src 8 80 (has focus)
asm 8 80
status 1 80
cmd 8 80
(gdb) winheight cmd +2
(gdb) info win
Name Lines Columns Focus
src 6 80 (has focus)
asm 8 80
status 1 80
cmd 10 80
Notice that initially, the windows were balanced, 8 lines each for the
major windows. Then, when the cmd window was adjusted, the extra two
lines were given to the asm window.
I think it would be nicer if the delta was spread more evenly over the
available windows. In the example above, after the adjustment the
layout now looks like:
(gdb) info win
Name Lines Columns Focus
src 7 80 (has focus)
asm 7 80
status 1 80
cmd 10 80
This is achieved within tui_layout_split::set_size, by just handing
out the delta in increments of 1 to each window (except for the window
the user adjusted), until there's no more delta left. Of course, we
continue to respect the min/max window sizes.
|
|
This commit removes some arbitrary adjustments made in
tui_cmd_window::max_height, tui_win_info::max_height, and
tui_win_info::max_width.
These member functions all subtract some constant from the theoretical
maximum height or width. I've looked back through the history a
little and can see no real reason why these adjustments should be
needed, with these adjustments removed all the existing tui tests
still pass.
However, retaining these restrictions causes some bugs, consider:
(gdb) tui new-layout hsrc {-horizontal src 1 cmd 1} 1
When this layout is selected with current master, gdb will leave a 4
line gap at the bottom of the terminal.
The problem is that the maximum height is restricted, for the cmd
window, to 4 less than the terminal height.
By removing this restriction gdb is able to size the windows to the
complete terminal height, and the layout is done correctly.
This 4 line restriction is also what prevents this layout from working
correctly:
(gdb) tui new-layout conly cmd 1
Previously, this layout would present a cmd window only, but there
would be a 4 line gap at the bottom of the terminal. This issue was
mentioned in an earlier commit in this series (when a different bug
was fixed), but with this commit, the above layout now correctly fills
the terminal. The associated test is updated.
After removing the adjustment in tui_cmd_window::max_height, the
implementation is now the same as the implementation in the parent
class tui_win_info, so I've completely removed the max_height call
from tui_cmd_window.
|
|
This commit allows the user to place the cmd window within horizontal
tui layouts. Consider this set of steps, carried out in an 80 columns
by 24 lines terminal, using current master gdb:
(gdb) tui new-layout hsrc { -horizontal src 1 cmd 1 } 1 status 1
(gdb) tui layout hsrc
What you end up with is a full width cmd window with the status bar
beneath. Where's the src window gone? We then try:
(gdb) info win
Name Lines Columns Focus
src 23 3 (has focus)
cmd 23 80
status 1 80
(gdb)
Something weird has gone on, gdb has overlapped the cmd window with
the src window. If we trigger the src window to redraw is content,
for example, 'list main', then we see corruption in the cmd window as
the src window overwrites it.
So, what's going on?
The problem is some code in tui_layout_split::apply, in tui-layout.c.
Within 'Step 1', there is a loop that calculates the min/max window
sizes for all windows within a tui_layout_split. However, there's a
special case for the cmd window.
This special case is trying to have the cmd window retain its current
size when a layout is re-applied, or a new layout is applied. This
makes sense, consider moving from the 'src' layout to the 'asm'
layout, this looks something like this (status window removed):
.-------. .-------.
| src | | asm |
|-------| ====> |-------|
| cmd | | cmd |
'-------' '-------'
If the user has gone to the effort of adjusting the cmd window size,
then, the thinking goes, we shouldn't reset the cmd window size when
switching layouts like this.
The problem though, is that when we do a switch more like this:
.-----------. .-----------.
| src | | | |
|-----------| ====> | asm | cmd |
| cmd | | | |
'-----------' '-----------'
Now retaining the cmd window width makes no sense; the new layout has
a completely different placement for the cmd window, instead of sizing
by height, we're now sizing by width. The existing code doesn't
understand this though, and tried to retain the full width for the cmd
window.
To solve this problem, I propose we introduce the idea of a layout
"fingerprint". The fingerprint tries to capture, in an abstract way,
where the cmd window lives within the layout.
Only when two layouts have the same fingerprint will we attempt to
retain the cmd window size.
The fingerprint for a layout is represented as a string, the string is
a series of 'V' or 'H' characters, ending with a single 'C'
character. The series of 'V' and 'H' characters represent the
vertical or horizontal layouts that must be passed through to find the
cmd window.
Here are a few examples:
# This layout is equivalent to the builtin 'src' layout.
# Fingerprint: VC
tui new-layout example1 src 2 status 0 cmd 1
# This layout is equivalent to the builtin 'split' layout.
# Fingerprint: VC
tui new-layout example2 src 1 asm 1 status 0 cmd 1
# This is the same layout that was given at the top.
# Fingerprint: VHC
tui new-layout hsrc { -horizontal src 1 cmd 1 } 1 status 1
And so, when switching between example1 and example2, gdb knows that
the cmd window is, basically, in the same sort of position within the
layout, and will retain the cmd window size.
In contrast, when switching to the hsrc layout, gdb understands that
the position of the cmd window is different, and does not try to
retain the cmd window size.
|
|
When we switch layouts we call the tui_layout_split::apply member
function to reapply the layout, and recalculate all the window sizes.
One special case is the cmd window, which we try to keep at its
existing size.
However, in some cases it is not appropriate to keep the cmd window at
its existing size. I will describe two such cases here, in one, we
want the cmd window to reduce in size, and in the other, we want the
cmd window to grow in size.
Try these steps in a 80 columns, by 24 lines terminal:
(gdb) tui enable
(gdb) layout src
(gdb) winheight cmd 20
(gdb) layout split
You should see that the status window is missing from the new layout,
and that the cmd window has been placed over the border of the asm
window. The 'info win' output is:
(gdb) info win
Name Lines Columns Focus
src 3 80 (has focus)
asm 3 80
status 1 80
cmd 20 80
Notice that gdb has assigned 27 lines of screen space, even with the
border overlap between the src and asm windows, this is still 2 lines
too many.
The problem here is that after switching layouts, gdb has forced the
cmd window to retain its 20 line height. Really, we want the cmd
window to reduce in height so that the src and asm windows can occupy
their minimum required space.
This commit allows this (details on how are below). After this
commit, in the above situation, we now see the status window displayed
correctly, and the 'info win' output is:
(gdb) info win
Name Lines Columns Focus
src 3 80 (has focus)
asm 3 80
status 1 80
cmd 18 80
The cmd window has been reduced in size by 2 lines so that everything
can fit on the screen.
The second example is one which was discussed in a recent commit,
consider this case (still in the 80 column, 24 line terminal):
(gdb) tui enable
(gdb) tui new-layout conly cmd 1
(gdb) layout conly
(gdb) info win
Name Lines Columns Focus
cmd 8 80 (has focus)
(gdb)
This layout only contains a cmd window, which we would expect to
occupy the entire terminal. But instead, the cmd window only occupies
the first 8 lines, and the rest of the terminal is unused!
The reason is, again, that the cmd window is keeping its previous
size (8 lines).
After this commit things are slightly different, the 'info win' output
is now:
(gdb) info win
Name Lines Columns Focus
cmd 20 80 (has focus)
Which is a little better, but why only 20 lines? Turns out there's
yet another bug hitting this case. That bug will be addressed in a
later commit, so, for now, we're accepting the 20 lines.
What this commit does is modify the phase of tui_layout_split::apply
that handles any left over space. Usually, in "Step 2", each
sub-layout has a size calculated. As the size is an integer, then,
when all sizes are calculated we may have some space left over.
This extra space is then distributed between all the windows fairly
until all the space is used up.
When we consider windows minimum size, or fixed size windows, then it
is possible that we might try to use more space than is available,
this was our first example above. The same code that added extra
space to the windows, can also be used to reclaim space (in the over
allocation case) to allow all windows to fit.
The problem then is the cmd window, which we often force to a fixed
size. Inside the loop that handles the allocation of excess space, if
we find that we have tried every window, and still have space either
left to give, or we need to claim back more space, then, if the cmd
window was changed to a fixed size, we can change the cmd window back
to a non-fixed-size window, and proceed to either give, or take space
from the cmd window as needed.
|