When running test-case gdb.fortran/function-calls.exp with target board
unix/gdb:debug_flags=-gdwarf-5, I run into:
...
(gdb) PASS: gdb.fortran/function-calls.exp: \
p derived_types_and_module_calls::pass_cart(c)
p derived_types_and_module_calls::pass_cart_nd(c_nd)^M
^M
Program received signal SIGSEGV, Segmentation fault.^M
0x0000000000400f73 in derived_types_and_module_calls::pass_cart_nd \
(c=<error reading variable: Cannot access memory at address 0xc>) at \
function-calls.f90:130^M
130 pass_cart_nd = ubound(c%d,1,4)^M
The program being debugged was signaled while in a function called from GDB.^M
GDB has restored the context to what it was before the call.^M
To change this behavior use "set unwindonsignal off".^M
Evaluation of the expression containing the function^M
(derived_types_and_module_calls::pass_cart_nd) will be abandoned.^M
(gdb) FAIL: gdb.fortran/function-calls.exp: p
...
The problem originates in read_array_type, when reading a DW_TAG_array_type
with a dwarf-5 DW_TAG_generic_subrange child. This is not supported, and the
fallout of this is that rather than constructing a new array type, the code
proceeds to modify the element type.
Fix this conservatively by issuing a complaint and bailing out in
read_array_type when not being able to construct an array type, such that we
have:
...
(gdb) maint expand-symtabs function-calls.f90^M
During symbol reading: unable to find array range \
- DIE at 0xe1e [in module function-calls]^M
During symbol reading: unable to find array range \
- DIE at 0xe1e [in module function-calls]^M
(gdb) KFAIL: gdb.fortran/function-calls.exp: no complaints in srcfile \
(PRMS: symtab/27388)
...
Tested on x86_64-linux.
gdb/ChangeLog:
2021-02-09 Tom de Vries <tdevries@suse.de>
PR symtab/27341
* dwarf2/read.c (read_array_type): Return NULL when not being able to
construct an array type. Add assert to ensure that element_type is
not being modified.
gdb/testsuite/ChangeLog:
2021-02-09 Tom de Vries <tdevries@suse.de>
PR symtab/27341
* lib/gdb.exp (with_complaints): New proc, factored out of ...
(gdb_load_no_complaints): ... here.
* gdb.fortran/function-calls.exp: Add test-case.
This reverts commit 82a1fd3a49.
It was pointed out:
https://sourceware.org/pipermail/gdb-patches/2021-February/175750.html
that commit 82a1fd3a49 caused GDB to have an unconditional
dependency on ELF specific parts of BFD. What this means is that if
GDB and BFD are built for a non-elf target then there will be
undefined symbol references within GDB.
The right solution isn't immediately obvious. So rather than rush a
fix in I'm reverting this commit for now, and will bring it back once
I have a good solution.
gdb/ChangeLog:
* gcore.c (struct gcore_collect_regset_section_cb_data): Delete.
(gcore_collect_regset_section_cb): Delete.
(gcore_collect_thread_registers): Delete.
(gcore_build_thread_register_notes): Delete.
(gcore_find_signalled_thread): Delete.
* gcore.h: Remove 'gdbsupport/gdb_signals.h' include and delete
'gdbarch' and 'thread_info' declarations.
(gcore_build_thread_register_notes): Delete declaration.
(gcore_find_signalled_thread): Likewise.
* fbsd-tdep.c: Remove 'gcore.h' include.
(struct fbsd_collect_regset_section_cb_data): New struct.
(fbsd_collect_regset_section_cb): New function.
(fbsd_collect_thread_registers): New function.
(struct fbsd_corefile_thread_data): New struct.
(fbsd_corefile_thread): New function.
(fbsd_make_corefile_notes): Call FreeBSD specific code.
* linux-tdep.c: Remove 'gcore.h' include.
(struct linux_collect_regset_section_cb_data): New struct.
(linux_collect_regset_section_cb): New function.
(linux_collect_thread_registers): New function.
(linux_corefile_thread): Call Linux specific code.
(find_signalled_thread): New function.
(linux_make_corefile_notes): Call find_signalled_thread.
While running tests on arm-none-eabi, I noticed following errors in some
gdb.threads tests.
ERROR: can't read "testfile": no such variable
These were being caused by ${testfile} being used before 'standard_testfile'
which sets it. This patch just moves standard_testfile before the use.
2021-02-09 Abid Qadeer <abidh@codesourcery.com>
gdb/testsuite/ChangeLog:
* gdb.threads/signal-command-handle-nopass.exp: Call
'standard_testfile' before using 'testfile'.
* gdb.threads/signal-command-multiple-signals-pending.exp: Likewise.
* gdb.threads/signal-delivered-right-thread.exp: Likewise
* gdb.threads/signal-sigtrap.exp: Likewise
With a certain Ada program, ada-lang.c:coerce_unspec_val_to_type can
cause a crash. This function may copy a value, and in the particular
case in the crash, the new value's type is smaller than the original
type. This causes coerce_unspec_val_to_type to create a lazy value --
but the original value is also not_lval, so later, when the value is
un-lazied, gdb asserts.
As with the previous patch, we believe there is a compiler bug here,
but it is difficult to reproduce, so we're not completely certain.
In the particular case we saw, the original value has record type, and
the record holds some variable-length arrays. This leads to the
type's length being 0. At the same time, the value is optimized out.
This patch changes coerce_unspec_val_to_type to handle an
optimized-out value correctly.
It also slightly restructures this code to avoid a crash should a
not_lval value wind up here. This is a purely defensive change.
This change also made it clear that value_contents_copy_raw can now be
made static, so that is also done.
gdb/ChangeLog
2021-02-09 Tom Tromey <tromey@adacore.com>
* ada-lang.c (coerce_unspec_val_to_type): Avoid making lazy
not_lval value.
* value.c (value_contents_copy_raw): Now static.
* value.h (value_contents_copy_raw): Don't declare.
resolve_dynamic_struct says:
gdb_assert (type->num_fields () > 0);
However, a certain Ada program has a structure with no fields but with
a dynamic size, causing this assertion to fire.
It is difficult to be certain, but we think this is a compiler bug.
However, in the meantime this assertion does not seem to be checking
any kind of internal consistency; so this patch removes it.
gdb/ChangeLog
2021-02-09 Tom Tromey <tromey@adacore.com>
* gdbtypes.c (resolve_dynamic_struct): Handle structure with no
fields.
When compiling an exec like this:
...
$ gcc -fdebug-types-section hello.c -gdwarf-5
...
we run into:
...
$ readelf -w a.out > READELF
readelf: Warning: Unexpected form 20 encountered whilst finding \
abbreviation for type
...
Fix this by handling DW_FORM_ref_sig8 conservatively in
get_type_abbrev_from_form.
binutils/ChangeLog:
2021-02-09 Tom de Vries <tdevries@suse.de>
PR binutils/27370
* dwarf.c (get_type_abbrev_from_form): Handle DW_FORM_ref_sig8.
PR 27381
* read.c (s_incbin): Check that the file to be included is a
regular, non-directory file.
* testsuite/gas/all/pr27381.s: New test source file.
* testsuite/gas/all/pr27381.d: New test control file.
* testsuite/gas/all/pr27381.err: Expected error output for the new test.
* testsuite/gas/all/gas.exp: Run the new test.
With this exec:
...
$ gcc -gsplit-dwarf hello.c -gdwarf-5
...
we run into:
...
$ readelf -w a.out > READELF
readelf: Warning: CU at offset c7 contains corrupt or unsupported unit type: 4.
readelf: Warning: CU at offset c7 contains corrupt or unsupported unit type: 4.
...
Fix this by handling DW_UT_skeleton and DW_UT_split_compile in
process_debug_info.
Note that this just adds the parsing of DWO_id, but not yet any printing of
it.
Tested on x86_64-linux.
binutils/ChangeLog:
2021-02-09 Tom de Vries <tdevries@suse.de>
PR binutils/27386
* dwarf.c (process_debug_info): Handling DW_UT_skeleton and
DW_UT_split_compile.
PR 27384
* listing.c (listing_psize): Check the result of the width
expression before assigning it to paper_width.
* testsuite/gas/all/pr27384.s: New test source file.
* testsuite/gas/all/pr27384.d: New test control file.
* testsuite/gas/all/pr27384.err: Expected errors from new test.
* testsuite/gas/all/gas.exp: Run the new test.
PR 27355
* testsuite/gas/elf/pr27355.s: New test source file.
* testsuite/gas/elf/pr27355.d: New test control file.
* testsuite/gas/elf/pr27355.err: Expected errors from new test.
* testsuite/gas/elf/elf.exp: Run the new test.
The test expects the ifunc resolver to run lazily, at a later stage.
Depending on the distro and toolchain configuration, this is not the
case. Some configurations use non-lazy binding and thus the ifunc resolver
resolves all the ifunc references very early in the process startup, before
main.
Ubuntu is one such case. It has switched its toolchains to pass -Wl,z,now by
default, since 16.04. This wasn't a problem before 20.04 (at least for
aarch64) because the toolchains did not support ifunc's.
Forcing lazy binding makes the test run as expected, as opposed to the 80 or
so failures it showed before the change.
Tested on aarch64-linux/x86_64-linux Ubuntu 20.04.
gdb/testsuite:
2021-02-08 Luis Machado <luis.machado@linaro.org>
* gdb.base/gnu-ifunc.exp (build): Pass -Wl,z,lazy.
When running test-case gdb.dwarf2/enqueued-cu-base-addr.exp with target board
cc-with-dwz, I get:
...
gdb compile failed, dwz: enqueued-cu-base-addr: \
Couldn't find DIE at [100] referenced by DW_AT_type from DIE at [d8]
...
At 0xd8 we have DIE:
...
<1><d8>: Abbrev Number: 3 (DW_TAG_variable)
<d9> DW_AT_name : foo
<dd> DW_AT_type : <0x100>
<e1> DW_AT_const_value : 1
...
referring to:
...
<1><100>: Abbrev Number: 3 (DW_TAG_base_type)
<101> DW_AT_byte_size : 4
<102> DW_AT_encoding : 5 (signed)
<103> DW_AT_name : int
...
The reference is inter-CU, but the used abbrev uses DW_FORM_ref4:
...
3 DW_TAG_variable [no children]
DW_AT_name DW_FORM_string
DW_AT_type DW_FORM_ref4
DW_AT_const_value DW_FORM_sdata
DW_AT value: 0 DW_FORM value: 0
...
which is for intra-CU references.
Fix this by using a '%' instead of a ':' label prefix in the dwarf assembly.
Tested on x86_64-linux.
gdb/testsuite/ChangeLog:
2021-02-08 Tom de Vries <tdevries@suse.de>
* gdb.dwarf2/enqueued-cu-base-addr.exp: Fix inter-CU reference.
When stepping over thread-lock related codes (in uClibc), the inferior process
gets stuck and never manages to enter the critical section:
------8<-------
1 size_t fwrite(const void * __restrict ptr, size_t size,
2 size_t nmemb, register FILE * __restrict stream)
3 {
4 size_t retval;
5 __STDIO_AUTO_THREADLOCK_VAR;
6
7 > __STDIO_AUTO_THREADLOCK(stream);
8
9 retval = fwrite_unlocked(ptr, size, nmemb, stream);
10
11 __STDIO_AUTO_THREADUNLOCK(stream);
12
13 return retval;
14 }
------>8-------
Here, we are at line 7. Using the "next" command leads no where.
However, setting a breakpoint on line 9 and issuing "continue" works.
Looking at the assembly instructions reveals that we're dealing with the
critical section entry code [1] that should never be interrupted, in this
case by the debugger's implicit breakpoints:
------8<-------
...
1 add_s r0,r13,0x38
2 mov_s r3,1
3 llock r2,[r0] <-.
4 brne.nt r2,0,14 --. |
5 scond r3,[r0] | |
6 bne -10 --|--'
7 brne_s r2,0,84 <-'
...
------>8-------
Lines 3 until 5 (inclusive) are supposed to be executed atomically.
Therefore, GDB should never (implicitly) insert a breakpoint on lines
4 and 5, else the program will try to acquire the lock again by jumping
back to line 3 and gets stuck in an infinite loop.
The solution is to make GDB aware of these patterns so it inserts
breakpoints after the sequence -- line 6 in this example.
[1]
https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/libc/sysdeps/linux/arc/bits/atomic.h#n46
------8<-------
({ \
__typeof(oldval) prev; \
\
__asm__ __volatile__( \
"1: llock %0, [%1] \n" \
" brne %0, %2, 2f \n" \
" scond %3, [%1] \n" \
" bnz 1b \n" \
"2: \n" \
: "=&r"(prev) \
: "r"(mem), "ir"(oldval), \
"r"(newval) /* can't be "ir". scond can't take limm for "b" */\
: "cc", "memory"); \
\
prev; \
})
------>8-------
"llock" (Load Locked) loads the 32-bit word pointed by the source
operand. If the load is completed without any interruption or
exception, the physical address is remembered, in Lock Physical Address
(LPA), and the Lock Flag (LF) is set to 1. LF is a non-architecturally
visible flag and is cleared whenever an interrupt or exception takes
place. LF is also cleared (atomically) whenever another process writes
to the LPA.
"scond" (Store Conditional) will write to the destination address if
and only if the LF is set to 1. When finished, with or without a write,
it atomically copies the LF value to ZF (Zero Flag).
These two instructions together provide the mechanism for entering a
critical section. The code snippet above comes from uClibc:
-----------------------
v3 (after Tom's remarks[2]):
handle_atomic_sequence()
- no need to initialize the std::vector with "{}"
- fix typo in comments: "conditial" -> "conditional"
- add braces to the body of "if" condition because of the comment line
arc_linux_software_single_step()
- make the performance slightly more efficient by moving a few
variables after the likely "return" point.
v2 (after Simon's remarks[3]):
- handle_atomic_sequence() gets a copy of an instruction instead of
a reference.
- handle_atomic_sequence() asserts if the given instruction is an llock.
[2]
https://sourceware.org/pipermail/gdb-patches/2021-February/175805.html
[3]
https://sourceware.org/pipermail/gdb-patches/2021-January/175487.html
gdb/ChangeLog:
PR tdep/27369
* arc-linux-tdep.c (handle_atomic_sequence): New.
(arc_linux_software_single_step): Call handle_atomic_sequence().
If the user implements a TUI window in Python, and this window
responds to GDB events and then redraws its window contents then there
is currently an edge case which can lead to problems.
The Python API documentation suggests that calling methods like erase
or write on a TUI window (from Python code) will raise an exception if
the window is not valid.
And the description for is_valid says:
This method returns True when this window is valid. When the user
changes the TUI layout, windows no longer visible in the new layout
will be destroyed. At this point, the gdb.TuiWindow will no longer
be valid, and methods (and attributes) other than is_valid will
throw an exception.
From this I, as a user, would expect that if I did 'tui disable' to
switch back to CLI mode, then the window would no longer be valid.
However, this is not the case.
When the TUI is disabled the windows in the TUI are not deleted, they
are simply hidden. As such, currently, the is_valid method continues
to return true.
This means that if the users Python code does something like:
def event_handler (e):
global tui_window_object
if tui_window_object->is_valid ():
tui_window_object->erase ()
tui_window_object->write ("Hello World")
gdb.events.stop.connect (event_handler)
Then when a stop event arrives GDB will try to draw the TUI window,
even when the TUI is disabled.
This exposes two bugs. First, is_valid should be returning false in
this case, second, if the user forgot to add the is_valid call, then I
believe the erase and write calls should be throwing an
exception (when the TUI is disabled).
The solution to both of these issues is I think bound together, as it
depends on having a working 'is_valid' check.
There's a rogue assert added into tui-layout.c as part of this
commit. While working on this commit I managed to break GDB such that
TUI_CMD_WIN was nullptr, this was causing GDB to abort. I'm leaving
the assert in as it might help people catch issues in the future.
This patch is inspired by the work done here:
https://sourceware.org/pipermail/gdb-patches/2020-December/174338.html
gdb/ChangeLog:
* python/py-tui.c (gdbpy_tui_window) <is_valid>: New member
function.
(REQUIRE_WINDOW): Call is_valid member function.
(REQUIRE_WINDOW_FOR_SETTER): New define.
(gdbpy_tui_is_valid): Call is_valid member function.
(gdbpy_tui_set_title): Call REQUIRE_WINDOW_FOR_SETTER instead.
* tui/tui-data.h (struct tui_win_info) <is_visible>: Check
tui_active too.
* tui/tui-layout.c (tui_apply_current_layout): Add an assert.
* tui/tui.c (tui_enable): Move setting of tui_active earlier in
the function.
gdb/doc/ChangeLog:
* python.texinfo (TUI Windows In Python): Extend description of
TuiWindow.is_valid.
gdb/testsuite/ChangeLog:
* gdb.python/tui-window-disabled.c: New file.
* gdb.python/tui-window-disabled.exp: New file.
* gdb.python/tui-window-disabled.py: New file.
There's a bug in the python tui API. If the user tries to delete the
window title attribute then this will trigger undefined behaviour in
GDB due to a missing nullptr check.
gdb/ChangeLog:
* python/py-tui.c (gdbpy_tui_set_title): Check that the new value
for the title is not nullptr.
gdb/testsuite/ChangeLog:
* gdb.python/tui-window.exp: Add new tests.
* gdb.python/tui-window.py (TestWindow) <__init__>: Store
TestWindow object into global the_window.
<remote_title>: New method.
(delete_window_title): New function.
This commit was inspired by this mailing list patch:
https://sourceware.org/pipermail/gdb-patches/2021-January/174713.html
Currently, calling tui_layout_window::apply will add the window from
the layout object to the global tui_windows list.
Unfortunately, when the user runs the 'winheight' command, this calls
tui_adjust_window_height, which calls the tui_layout_base::adjust_size
function, which can then call tui_layout_base::apply. The consequence
of this is that when the user does 'winheight' duplicate copies of a
window can be added to the global tui_windows list.
The original patch fixed this by changing the apply function to only
update the global list some of the time.
This patch takes a different approach. The apply function no longer
updates the global tui_windows list. Instead a new virtual function
is added to tui_layout_base which is used to gather all the currently
applied windows into a vector. Finally tui_apply_current_layout is
updated to make use of this new function to update the tui_windows
list.
The benefits I see in this approach are, (a) the apply function now no
longer touches global state, this solves the immediate problem,
and (b) now that tui_windows is updated directly in the function
tui_apply_current_layout, we can drop the saved_tui_windows global.
gdb/ChangeLog:
* tui-layout.c (saved_tui_windows): Delete.
(tui_apply_current_layout): Don't make use of saved_tui_windows,
call new get_windows member function instead.
(tui_get_window_by_name): Check in tui_windows.
(tui_layout_window::apply): Don't add to tui_windows.
* tui-layout.h (tui_layout_base::get_windows): New member function.
(tui_layout_window::get_windows): Likewise.
(tui_layout_split::get_windows): Likewise.
gdb/testsuite/ChangeLog:
* gdb.tui/winheight.exp: Add more tests.
In commit:
commit f237f998d1
Date: Mon Jan 25 18:43:19 2021 +0000
gdb/tui: remove special handling of locator/status window
I accidentally remove a call to delete the tui window objects. Now
every time GDB changes tui layout it is leaking windows.
gdb/ChangeLog:
* tui/tui-layout.c (tui_apply_current_layout): Restore the delete
of the window objects.
While working on another patch I noticed an oddly formatted error
message in the Python code.
When 'set python print-stack message' is in effect then consider this
Python script:
class TestCommand (gdb.Command):
def __init__ (self):
gdb.Command.__init__ (self, "test-cmd", gdb.COMMAND_DATA)
def invoke(self, args, from_tty):
raise RuntimeError ("bad")
TestCommand ()
And this GDB session:
(gdb) source path/to/python/script.py
(gdb) test-cmd
Python Exception <class 'RuntimeError'> bad:
Error occurred in Python: bad
The line 'Python Exception <class 'RuntimeError'> bad:' doesn't look
terrible in this situation, the colon at the end of the first line
makes sense given the second line.
However, there are places in GDB where there is no second line
printed, for example consider this python script:
def stop_listener (e):
raise RuntimeError ("bad")
gdb.events.stop.connect (stop_listener)
Then this GDB session:
(gdb) file helloworld.exe
(gdb) start
Temporary breakpoint 1 at 0x40112a: file hello.c, line 6.
Starting program: helloworld.exe
Temporary breakpoint 1, main () at hello.c:6
6 printf ("Hello World\n");
Python Exception <class 'RuntimeError'> bad:
(gdb) si
0x000000000040112f 6 printf ("Hello World\n");
Python Exception <class 'RuntimeError'> bad:
In this case there is no auxiliary information displayed after the
warning, and the line ending in the colon looks weird to me.
A quick survey of the code seems to indicate that it is not uncommon
for there to be no auxiliary information line printed, its not just
the one case I found above.
I propose that the line that currently looks like this:
Python Exception <class 'RuntimeError'> bad:
Be reformatted like this:
Python Exception <class 'RuntimeError'>: bad
I think this looks fine then in either situation. The first now looks
like this:
(gdb) test-cmd
Python Exception <class 'RuntimeError'>: bad
Error occurred in Python: bad
And the second like this:
(gdb) si
0x000000000040112f 6 printf ("Hello World\n");
Python Exception <class 'RuntimeError'>: bad
There's just two tests that needed updating. Errors are checked for
in many more tests, but most of the time the pattern doesn't care
about the colon.
gdb/ChangeLog:
* python/python.c (gdbpy_print_stack): Reformat an error message.
gdb/testsuite/ChangeLog:
* gdb.python/py-framefilter.exp: Update expected results.
* gdb.python/python.exp: Update expected results.
The rx simulator now has no build warnings. Delete the call to
SIM_AC_OPTION_WARNINGS in configure.ac, the default yes will be
provided by SIM_AC_OUTPUT.
sim/rx/ChangeLog:
* configure: Regenerate.
* configure.ac (SIM_AC_OPTION_WARNINGS): Delete call.
Pointer arithmetic on void * pointers results in a GCC warning. Avoid
the warning by casting the pointer to its actual type earlier in the
function.
sim/rx/ChangeLog:
* mem.c (mem_put_blk): Rename parameter, add cast from parameter
type to local type. Remove cast later in the function.
(mem_get_blk): Likewise.
* mem.h (mem_put_blk): Rename parameter to match definition.
(mem_get_blk): Likewise.
In load.c there's some GCC warnings about undefined
functions (bfd_get_elf_phdr_upper_bound and bfd_get_elf_phdrs). To
get the declarations of these functions include 'elf-bfd.h'. This
headers also pulls in other elf related headers, like 'elf/internal.h'
and 'elf/common.h', so these no longer need to be explicitly included
from load.c.
In trace.c and include for trace.h is missing, again this results in
GCC warnings for missing function declarations.
sim/rx/ChangeLog:
* load.c: Replace 'elf/internal.h' and 'elf/common.h' includes
with 'elf-bfd.h' include.
* trace.c: Add 'trace.h' include.
Silence a GCC compiler warning by using PRIx64 in printf format string
instead of hard coded "llx".
sim/rx/ChangeLog:
* reg.c (trace_register_changes): Use PRIx64 in printf format
string.
For sim code variables still need to be declared at the start of the
enclosing block. This silences a few GCC warnings.
sim/rx/ChangeLog:
* syscalls.c (rx_syscall): Move declaration of some variables to
the start of the enclosing block.
* trace.c (load_file_and_line): Likewise.
Calling printf with the format being a non constant string results in
a GCC warning:
warning: format not a string literal and no format arguments [-Wformat-nonliteral]
Provide a constant format string to printf in the few places this
warning is triggered.
sim/rx/ChangeLog:
* reg.c (fpsw2str): Provide a format string to printf.
(trace_register_changes): Likewise.
Some functions that should be marked static.
sim/rx/ChangeLog:
* fpu.c (check_exceptions): Make static.
* gdb-if.c (handle_step): Likewise.
* mem.c (mem_put_byte): Likewise.
While experimenting with switching on warnings for the rx simulator I
discovered this bug. In sim_do_command we get passed a 'const char *'
argument. We create a copy of this string to work with locally, but
then while processing this we accidentally switch back to reference
the original string.
sim/rx/ChangeLog:
* gdb-if.c (sim_do_command): Work with a copy of the command.
The rx simulator doesn't define sim_memory_map and so fails to link
with GDB. Define it now to return NULL, this can be extended later to
return an actual memory map if anyone wants this functionality.
sim/rx/ChangeLog:
* gdb-if.c (sim_memory_map): New function.
My initial goal was to fix our gdb/testsuite/lib/tuiterm.exp such that
it would correctly support (some limited) scrolling of the command
window.
What I observe is that when sending commands to the tui command window
in a test script with:
Term::command "p 1"
The command window would be left looking like this:
(gdb)
(gdb) p 1$1 = 1
(gdb)
When I would have expected it to look like this:
(gdb) p 1
$1 = 1
(gdb)
Obviously a bug in our tuiterm.exp library, right???
Wrong!
Turns out there's a bug in GDB.
If in GDB I enable the tui and then type (slowly) the 'p 1\r' (the \r
is pressing the return key at the end of the string), then you do
indeed get the "expected" terminal output.
However, if instead I copy the 'p 1\r' string and paste it into the
tui in one go then I now see the same corrupted output as we do when
using tuiterm.exp.
It turns out the problem is that GDB fails when handling lots of input
arriving quickly with a \r (or \n) on the end.
The reason for this bug is as follows:
When the tui is active the terminal is in no-echo mode, so characters
sent to the terminal are not echoed out again. This means that when
the user types \r, this is not echoed to the terminal.
The characters read in are passed to readline and \r indicates that
the command line is complete and ready to be processed. However, the
\r is not included in readlines command buffer, and is NOT printed by
readline when is displays its buffer to the screen.
So, in GDB we have to manually spot the \r when it is read in and
update the display. Printing a newline character to the output and
moving the cursor to the next line. This is done in tui_getc_1.
Now readline tries to reduce the number of write calls. So if we very
quickly (as in paste in one go) the text 'p 1' to readline (this time
with no \r on the end), then readline will fetch the fist character
and add it to its internal buffer. But before printing the character
out readline checks to see if there's more input incoming. As we
pasted multiple characters, then yes, readline sees the ' ' and adds
this to its buffer, and finally the '1', this too is added to the
buffer.
Now if at this point we take a break, readline sees there is no more
input available, and so prints its buffer out.
Now when we press \r the code in tui_getc_1 kicks in, adds a \n to the
output and moves the cursor to the next line.
But, if instead we paste 'p 1\r' in one go then readline adds 'p 1' to
its buffer as before, but now it sees that there is still more input
available. Now it fetches the '\r', but this triggers the newline
behaviour, we print '\n' and move to the next line - however readline
has not printed its buffer yet!
So finally we end up on the next line. There's no more input
available so readline prints its buffer, then GDB gets passed the
buffer, handles it, and prints the result.
The solution I think is to put of our special newline insertion code
until we know that readline has finished printing its buffer. Handily
we know when this is - the next thing readline does is pass us the
command line buffer for processing. So all we need to do is hook in
to the command line processing, and before we pass the command line to
GDB's internals we do all of the magic print a newline and move the
cursor to the next line stuff.
Luckily, GDB's interpreter mechanism already provides the hooks we
need to do this. So all I do here is move the newline printing code
from tui_getc_1 into a new function, setup a new input_handler hook
for the tui, and call my new newline printing function.
After this I can enable the tui and paste in 'p 1\r' and see the
correct output.
Also the tuiterm.exp library will now see non-corrupted output.
gdb/ChangeLog:
* tui/tui-interp.c (tui_command_line_handler): New function.
(tui_interp::resume): Register tui_command_line_handler as the
input_handler.
* tui/tui-io.c (tui_inject_newline_into_command_window): New
function.
(tui_getc_1): Delete handling of '\n' and '\r'.
* tui-io.h (tui_inject_newline_into_command_window): Declare.
gdb/testsuite/ChangeLog:
* gdb.tui/scroll.exp: Tighten expected results. Remove comment
about bug in GDB, update expected results, and add more tests.
The implementation of the delete line escape sequence in tuiterm.exp
was wrong. Delete should take a count and then delete COUNT lines at
the current cursor location, all remaining lines in the scroll region
are moved up to replace the deleted lines, with blank lines being
added at the end of the scroll region.
It's not clear to me what "scroll region" means here (or at least how
that is defined), but for now I'm just treating the whole screen as
the scroll region, which seems to work fine.
In contrast the current broken implementation deletes COUNT lines at
the cursor location moving the next COUNT lines up to fill the gap.
The rest of the screen is then cleared.
gdb/testsuite/ChangeLog:
* gdb.tui/scroll.exp: New file.
* gdb.tui/tui-layout-asm-short-prog.exp: Update expected results.
* lib/tuiterm.exp (Term::_csi_M): Delete count lines, scroll
remaining lines up.
(Term::check_region_contents): New proc.
(Term::check_box_contents): Use check_region_contents.
Remove x86 ISA level run-time tests since with glibc 2.33, they will fail
to run on machines with lesser x86 ISA level:
tmpdir/property-5-pie: CPU ISA level is lower than required
PR ld/27358
* testsuite/ld-i386/i386.exp: Remove property 3/4/5 run-time
tests.
* testsuite/ld-x86-64/x86-64.exp: Likewise.
If the regs window is not big enough to show all registers, the
registers whose values changed are always drawn, even if they are not
in the currently visible area.
So this marks the invisible register sub windows with y=0, and skips
their rerender call in check_register_values.
gdb/ChangeLog:
2021-02-07 Hannes Domani <ssbssa@yahoo.de>
* tui/tui-regs.c (tui_data_window::display_registers_from):
Mark invisible register sub windows.
(tui_data_window::check_register_values): Ignore invisible
register sub windows.
Function n_spaces can't handle negative values, and returns an invalid
pointer in this case.
gdb/ChangeLog:
2021-02-07 Hannes Domani <ssbssa@yahoo.de>
* tui/tui-regs.c (tui_data_item_window::rerender): Don't call
n_spaces with a negative value.
Otherwise the register window is redrawn empty when scrolling or
changing its size with winheight.
gdb/ChangeLog:
2021-02-07 Hannes Domani <ssbssa@yahoo.de>
* tui/tui-regs.c (tui_data_window::display_registers_from):
Add refresh_window call.
The last frame in a corrupt stack stores the frame_id of the next frame,
so these two frames currently compare as equal.
So if you have a backtrace where the oldest frame is corrupt, this happens:
(gdb) py
>f = gdb.selected_frame()
>while f.older():
> f = f.older()
>print(f == f.newer())
>end
True
With this change, that same example returns False.
gdb/ChangeLog:
2021-02-07 Hannes Domani <ssbssa@yahoo.de>
* python/py-frame.c (frapy_richcompare): Compare frame_id_is_next.
Printing "invalid" is better than printing an uninitialised buffer
and occasionally running off the end of the buffer.
* unwind-ia64.c (unw_print_xyreg): Don't leave output buffer
uninitialised on invalid input.
These ports don't use the common sim core, so they weren't providing
a sim_memory_map for gdb, so they failed to link with the new memory
map logic added for the sim. Add stubs to fix.
Few arches implement STATE_WATCHPOINTS()->pc while all of them implement
sim_pc_get. Lets switch the sim-watch core for monitoring pc events to
the sim_pc_get API so this module works for all ports, and then we can
delete this old back channel of snooping in the port's cpu state -- the
code needs the pointer to the pc storage so that it can read out bytes
and compare them to the watchrange.
This also fixes the logic on multi-cpu sims by removing the limitation
of only being able to watch CPU0's state.
The AC_CONFIG_HEADER macro is long deprecated, so switch to the
newer form. This also gets rid of the position limitation, and
drops support for an argument to SIM_AC_COMMON which we haven't
used anywhere.