Age | Commit message (Collapse) | Author | Files | Lines |
|
symtab::blockvector is a wrapper around compunit_symtab::blockvector.
It is a bit misleadnig, as it gives the impression that a symtab has a
blockvector. Remove it, change all users to fetch the blockvector
through the compunit instead.
Change-Id: Ibd062cd7926112a60d52899dff9224591cbdeebf
|
|
I think the symtab::dirname method is bogus, or at least very
misleading. It makes you think that it returns the directory that was
used to find that symtab's file during compilation (i.e. the directory
the file refers to in the DWARF line header file table), or the
directory part of the symtab's filename maybe. In fact, it returns the
compilation unit's directory, which is the CWD of the compiler, at
compilation time. At least for DWARF, if the symtab's filename is
relative, it will be relative to that directory. But if the symtab's
filename is absolute, then the directory returned by symtab::dirname has
nothing to do with the symtab's filename.
Remove symtab::dirname to avoid this confusion, change all users to
fetch the same information through the compunit. At least, it will be
clear that this is a compunit property, not a symtab property.
Change-Id: I2894c3bf3789d7359a676db3c58be2c10763f5f0
|
|
Change gdb_breakpoint to accept a linespec, not just a function. In
fact, no behavior changes are necessary, this only changes the parameter
name and documentation. Change runto as well, since the two are so
close (runto forwards all its arguments to gdb_breakpoint).
I wrote this for a downstrean GDB port, but thought it could be
useful upstream, eventually, even though not callers take advantage of
it yet.
Change-Id: I08175fd444d5a60df90fd9985e1b5dfd87c027cc
|
|
This commit updates the comments in the gdb/reggroups.{c,h} files.
Fill in some missing comments, correct a few comments that were not
clear, and where we had comments duplicated between .c and .h files,
update the .c to reference the .h.
No user visible changes after this commit.
|
|
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.
|
|
Convert the 'struct reggroup' into a real class, with a constructor
and getter methods.
There should be no user visible changes after this commit.
|
|
Convert the 7 global, pre-defined, register groups const, and fix the
fall out (a minor tweak required in riscv-tdep.c).
There should be no user visible changes after this commit.
|
|
Convert the reggroup_new and reggroup_gdbarch_new functions to return
a 'const regggroup *', and fix up all the fallout.
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.
|
|
Replace manual linked list with a std::vector. This commit doesn't
change the reggroup_next and reggroup_prev API, but that will change
in a later commit.
This commit is focused on the minimal changes needed to manage the
reggroups using a std::vector, without changing the API exposed by the
reggroup.c file.
There should be no user visible changes after this commit.
|
|
There's a set of 7 default register groups. If we don't add any
gdbarch specific register groups during gdbarch initialisation, then
when we iterate over the register groups using reggroup_next and
reggroup_prev we will make use of these 7 default groups. See the use
of default_groups in gdb/reggroups.c for details on this.
However, if the gdbarch adds its own groups during gdbarch
initialisation, then these groups will be used in preference to the
default groups.
A problem arises though if the particular architecture makes use of
the target description mechanism. If the default target
description(s) (i.e. those internal to GDB that are used when the user
doesn't provide their own) don't mention any additional register
groups then the default register groups will be used.
But if the target description does mention additional groups then the
default groups are not used, and instead, the groups from the target
description are used.
The problem with this is that what usually happens is that the target
description will mention additional groups, e.g. groups for special
registers. Most architectures that use target descriptions work
around this by adding all (or most) of the default register groups in
all cases. See i386_add_reggroups, aarch64_add_reggroups,
riscv_add_reggroups, xtensa_add_reggroups, and others.
In this patch, my suggestion is that we should just add the default
register groups for every architecture, always. This change is in
gdb/reggroups.c.
All the remaining changes are me updating the various architectures to
not add the default groups themselves.
So, where will this change be visible to the user? I think the
following commands will possibly change:
* info registers / info all-registers:
The user can provide a register group to these commands. For example,
on csky, we previously never added the 'vector' group. Now, as a
default group, this will be available, but (presumably) will not
contain any registers. I don't think this is necessarily a bad
thing, there's something to be said for having some consistent
defaults available. There are other architectures that didn't add
all 7 of the defaults, which will now have gained additional groups.
* maint print reggroups
This prints the set of all available groups. As a maintenance
command I'm less concerned with the output changing here.
Obviously, for the architectures that didn't previously add all the
defaults, this list just got bigger.
* maint print register-groups
This prints all the registers, and the groups they are in. If the
defaults were not previously being added then a register (obviously)
can't appear in one of the default groups. Now the groups are
available then registers might be in more groups than previously.
However, this is again a maintenance command, so I'm less concerned
about this changing.
|
|
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.
|
|
Update reggroup_find to return a const reggroup *.
There are other function in gdb/reggroup.{c,h} files that could
benefit from returning const, these will be updated in later commits.
There should be no user visible changes after this commit.
|
|
Convert uses of 'struct reggroup *' in python/py-registers.c to be
'const'.
There should be no user visible changes after this commit.
|
|
Make uses of 'reggroup *' const throughout tui-regs.{c,h}.
There should be no user visible changes after this commit.
|
|
Change gdbarch_register_reggroup_p to take a 'const struct reggroup *'
argument. This requires a change to the gdb/gdbarch-components.py
script, regeneration of gdbarch.{c,h}, and then updates to all the
architectures that implement this method.
There should be no user visible changes after this commit.
|
|
This commit makes the 'struct reggroup *' argument const for the
following functions:
reggroup_next
reggroup_prev
reggroup_name
reggroup_type
There are other places that could benefit from const in the
reggroup.{c,h} files, but these will be changing in further commits.
There should be no user visible changes after this commit.
|
|
While working on a different patch, I triggered an assertion from the
initialize_current_architecture code, specifically from one of
the *_gdbarch_init functions in a *-tdep.c file. This exposes a
couple of issues with GDB.
This is easy enough to reproduce by adding 'gdb_assert (false)' into a
suitable function. For example, I added a line into i386_gdbarch_init
and can see the following issue.
I start GDB and immediately hit the assert, the output is as you'd
expect, except for the very last line:
$ ./gdb/gdb --data-directory ./gdb/data-directory/
../../src.dev-1/gdb/i386-tdep.c:8455: internal-error: i386_gdbarch_init: Assertion `false' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
... snip ...
---------------------
../../src.dev-1/gdb/i386-tdep.c:8455: internal-error: i386_gdbarch_init: Assertion `false' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) ../../src.dev-1/gdb/ser-event.c:212:16: runtime error: member access within null pointer of type 'struct serial'
Something goes wrong when we try to query the user. Note, I
configured GDB with --enable-ubsan, I suspect that without this the
above "error" would actually just be a crash.
The backtrace from ser-event.c:212 looks like this:
(gdb) bt 10
#0 serial_event_clear (event=0x675c020) at ../../src/gdb/ser-event.c:212
#1 0x0000000000769456 in invoke_async_signal_handlers () at ../../src/gdb/async-event.c:211
#2 0x000000000295049b in gdb_do_one_event () at ../../src/gdbsupport/event-loop.cc:194
#3 0x0000000001f015f8 in gdb_readline_wrapper (
prompt=0x67135c0 "../../src/gdb/i386-tdep.c:8455: internal-error: i386_gdbarch_init: Assertion `false' failed.\nA problem internal to GDB has been detected,\nfurther debugging may prove unreliable.\nQuit this debugg"...)
at ../../src/gdb/top.c:1141
#4 0x0000000002118b64 in defaulted_query(const char *, char, typedef __va_list_tag __va_list_tag *) (
ctlstr=0x2e4eb68 "%s\nQuit this debugging session? ", defchar=0 '\000', args=0x7fffffffa6e0)
at ../../src/gdb/utils.c:934
#5 0x0000000002118f72 in query (ctlstr=0x2e4eb68 "%s\nQuit this debugging session? ")
at ../../src/gdb/utils.c:1026
#6 0x00000000021170f6 in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (problem=0x6107bc0 <internal_error_problem>, file=0x2b976c8 "../../src/gdb/i386-tdep.c",
line=8455, fmt=0x2b96d7f "%s: Assertion `%s' failed.", ap=0x7fffffffa8e8) at ../../src/gdb/utils.c:417
#7 0x00000000021175a0 in internal_verror (file=0x2b976c8 "../../src/gdb/i386-tdep.c", line=8455,
fmt=0x2b96d7f "%s: Assertion `%s' failed.", ap=0x7fffffffa8e8) at ../../src/gdb/utils.c:485
#8 0x00000000029503b3 in internal_error (file=0x2b976c8 "../../src/gdb/i386-tdep.c", line=8455,
fmt=0x2b96d7f "%s: Assertion `%s' failed.") at ../../src/gdbsupport/errors.cc:55
#9 0x000000000122d5b6 in i386_gdbarch_init (info=..., arches=0x0) at ../../src/gdb/i386-tdep.c:8455
(More stack frames follow...)
It turns out that the problem is that the async event handler
mechanism has been invoked, but this has not yet been initialized.
If we look at gdb_init (in gdb/top.c) we can indeed see the call to
gdb_init_signals is after the call to initialize_current_architecture.
If I reorder the calls, moving gdb_init_signals earlier, then the
initial error is resolved, however, things are still broken. I now
see the same "Quit this debugging session? (y or n)" prompt, but when
I provide an answer and press return GDB immediately crashes.
So what's going on now? The next problem is that the call_readline
field within the current_ui structure is not initialized, and this
callback is invoked to process the reply I entered.
The problem is that call_readline is setup as a result of calling
set_top_level_interpreter, which is called from captured_main_1.
Unfortunately, set_top_level_interpreter is called after gdb_init is
called.
I wondered how to solve this problem for a while, however, I don't
know if there's an easy "just reorder some lines" solution here.
Looking through captured_main_1 there seems to be a bunch of
dependencies between printing various things, parsing config files,
and setting up the interpreter. I'm sure there is a solution hiding
in there somewhere.... I'm just not sure I want to spend any longer
looking for it.
So.
I propose a simpler solution, more of a hack/work-around. In utils.c
we already have a function filtered_printing_initialized, this is
checked in a few places within internal_vproblem. In some of these
cases the call gates whether or not GDB will query the user.
My proposal is to add a new readline_initialized function, which
checks if the current_ui has had readline initialized yet. If this is
not the case then we should not attempt to query the user.
After this change GDB prints the error message, the backtrace, and
then aborts (including dumping core). This actually seems pretty sane
as, if GDB has not yet made it through the initialization then it
doesn't make much sense to allow the user to say "no, I don't want to
quit the debug session" (I think).
|
|
Update binutils to recognize the NT_ARM_SYSTEM_CALL set that is dumped by
Linux to core files.
|
|
bfd * coff-i386.c (in_reloc_p): Add R_SECTION.
(howto_table): Add R_SECTION.
(coff_pe_i386_relocation_section): Add support for R_SECTION.
(coff_i386_reloc_type_lookup): Add support for
BFD_RELOC_16_SECCIDX.
* coff-x86_64.c (in_reloc_p): Add R_SECTION.
(howto_table): Add R_SECTION.
(coff_pe_amd64_relocation_section): Add support for R_SECTION.
(coff_amd64_reloc_type_lookup): Add support for
BFD_RELOC_16_SECCIDX.
* reloc.c: Add BFD_RELOC_16_SECIDX.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
gas * config/tc-i386.c (pe_directive_secidx): New function.
(md_pseudo_table): Add support for secidx.
(x86_cons_fix_new): Likewise.
(tc_gen_reloc): Likewise.
* expr.c (op_rank): Add O_secidx.
* expr.h (operatorT): Likewise.
* symbols.c (resolve_symbol_value): Add support for O_secidx.
* testsuite/gas/i386/secidx.s: New test source file.
* testsuite/gas/i386/secidx.d: New test driver file.
* testsuite/gas/i386/i386.exp: Run new test.
include * coff/i386.h: Define R_SECTION.
* coff/x86_64.h: Likewise.
ld * testsuite/ld-pe/secidx1.s: New test source file.
* testsuite/ld-pe/secidx2.s: New test source file.
* testsuite/ld-pe/secidx.d: New test driver file.
* testsuite/ld-pe/secidx_64.d: New test driver file.
* testsuite/ld-pe/pe.exp: Add new tests.
|
|
To help tools like addr2line looking up function names, in particular
when dealing with e.g. PE/COFF binaries (linked from ELF objects), where
there's no ELF symbol table to fall back to, emit minimalistic
information for functions marked as such and having their size
specified.
Notes regarding the restriction to (pure) ELF:
- I realize this is a layering violation; I don't see how to deal with
that in a better way.
- S_GET_SIZE(), when OBJ_MAYBE_ELF is defined, looks wrong: Unlike
S_SET_SIZE() it does not check whether the hook is NULL.
- symbol_get_obj(), when OBJ_MAYBE_ELF is defined, looks unusable, as
its return type can only ever be one object format's type (and this
may then not be ELF's).
The new testcases are limited to x86 because I wanted to include the
case where function size can't be determined yet at the time Dwarf2 info
is generated. As .nops gains support by further targets, they could also
be added here then (with, as necessary, expecations suitably relaxed to
cover for insn size differences).
|
|
Just like insns encoded the more conventional way these should have line
number info associated with them.
|
|
Just like insns encoded the more conventional way these should have line
number info associated with them.
|
|
Since no such test looks to exist, derive one from insn.s.
|
|
So far z16 was identified as arch14. After the machine has been
announced we can now add the real name.
gas/ChangeLog:
* config/tc-s390.c (s390_parse_cpu): Add z16 as alternate CPU
name.
* doc/as.texi: Add z16 and arch14 to CPU string list.
* doc/c-s390.texi: Add z16 to CPU string list.
opcodes/ChangeLog:
* s390-mkopc.c (main): Enable z16 as CPU string in the opcode
table.
|
|
|
|
$ objdump -d outputs/gdb.base/varargs/varargs
00000001200012e8 <find_max_float_real>:
...
1200013b8: c7c10000 lwc1 $f1,0(s8)
1200013bc: c7c00004 lwc1 $f0,4(s8)
1200013c0: 46000886 mov.s $f2,$f1
1200013c4: 46000046 mov.s $f1,$f0
1200013c8: 46001006 mov.s $f0,$f2
1200013cc: 46000886 mov.s $f2,$f1
1200013d0: 03c0e825 move sp,s8
1200013d4: dfbe0038 ld s8,56(sp)
1200013d8: 67bd0080 daddiu sp,sp,128
1200013dc: 03e00008 jr ra
1200013e0: 00000000 nop
From the above disassembly, we can see that when the return value of the
function is a complex type and len <= 2 * MIPS64_REGSIZE, the return value
will be passed through $f0 and $f2, so fix the corresponding processing
in mips_n32n64_return_value().
$ make check RUNTESTFLAGS='GDB=../gdb gdb.base/varargs.exp --outdir=test'
Before applying the patch:
FAIL: gdb.base/varargs.exp: print find_max_float_real(4, fc1, fc2, fc3, fc4)
FAIL: gdb.base/varargs.exp: print find_max_double_real(4, dc1, dc2, dc3, dc4)
# of expected passes 9
# of unexpected failures 2
After applying the patch:
# of expected passes 11
This also fixes:
FAIL: gdb.base/callfuncs.exp: call inferior func with struct - returns float _Complex
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Co-Authored-By: Maciej W. Rozycki <macro@orcam.me.uk>
|
|
This changes jit.c to use new and delete, rather than XCNEW. This
simplifies the code a little. This was useful for another patch I'm
working on, and I thought it would make sense to send it separately.
Regression tested on x86-64 Fedora 34.
|
|
Bug 28980 shows that trying to value_copy an entirely optimized out
value causes an internal error. The original bug report involves MI and
some Python pretty printer, and is quite difficult to reproduce, but
another easy way to reproduce (that is believed to be equivalent) was
proposed:
$ ./gdb -q -nx --data-directory=data-directory -ex "py print(gdb.Value(gdb.Value(5).type.optimized_out()))"
/home/smarchi/src/binutils-gdb/gdb/value.c:1731: internal-error: value_copy: Assertion `arg->contents != nullptr' failed.
This is caused by 5f8ab46bc691 ("gdb: constify parameter of
value_copy"). It added an assertion that the contents buffer is
allocated if the value is not lazy:
if (!value_lazy (val))
{
gdb_assert (arg->contents != nullptr);
This was based on the comment on value::contents, which suggest that
this is the case:
/* Actual contents of the value. Target byte-order. NULL or not
valid if lazy is nonzero. */
gdb::unique_xmalloc_ptr<gdb_byte> contents;
However, it turns out that it can also be nullptr also if the value is
entirely optimized out, for example on exit of
allocate_optimized_out_value. That function creates a lazy value, marks
the entire value as optimized out, and then clears the lazy flag. But
contents remains nullptr.
This wasn't a problem for value_copy before, because it was calling
value_contents_all_raw on the input value, which caused contents to be
allocated before doing the copy. This means that the input value to
value_copy did not have its contents allocated on entry, but had it
allocated on exit. The result value had it allocated on exit. And that
we copied bytes for an entirely optimized out value (i.e. meaningless
bytes).
From here I see two choices:
1. respect the documented invariant that contents is nullptr only and
only if the value is lazy, which means making
allocate_optimized_out_value allocate contents
2. extend the cases where contents can be nullptr to also include
values that are entirely optimized out (note that you could still
have some entirely optimized out values that do have contents
allocated, it depends on how they were created) and adjust
value_copy accordingly
Choice #1 is safe, but less efficient: it's not very useful to allocate
a buffer for an entirely optimized out value. It's even a bit less
efficient than what we had initially, because values coming out of
allocate_optimized_out_value would now always get their contents
allocated.
Choice #2 would be more efficient than what we had before: giving an
optimized out value without allocated contents to value_copy would
result in an optimized out value without allocated contents (and the
input value would still be without allocated contents on exit). But
it's more risky, since it's difficult to ensure that all users of the
contents (through the various_contents* accessors) are all fine with
that new invariant.
In this patch, I opt for choice #2, since I think it is a better
direction than choice #1. #1 would be a pessimization, and if we go
this way, I doubt that it will ever be revisited, it will just stay that
way forever.
Add a selftest to test this. I initially started to write it as a
Python test (since the reproducer is in Python), but a selftest is more
straightforward.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28980
Change-Id: I6e2f5c0ea804fafa041fcc4345d47064b5900ed7
|
|
This is the last of the correctness fixes I've been carrying around for the
v850.
Like the other recent fixes, this is another case where we haven't been as
careful as we should WRT host vs target types. For the divq instruction
both operands are 32 bit types. Yet in the simulator code we convert them
from unsigned int to signed long by assignment. So 0xfffffffb (aka -5)
turns into 4294967291 and naturally that changes the result of our division.
The fix is simple, insert a cast to int32_t to force interpretation as a
signed value.
Testcase for the simulator is included. It has a trivial dependency on the
bins patch.
|
|
I've been carrying this for a few years. One test in the GCC testsuite is
failing due to a bug in the handling of the v850e3v5 instruction "bins".
When the "bins" instruction specifies a 32bit bitfield size, the simulator
exhibits undefined behavior by trying to shift a 32 bit quantity by 32 bits.
In the case of a 32 bit shift, we know what the resultant mask should be. So
we can just set it.
That seemed better than using 1UL for the constant (on a 32bit host unsigned
long might still just be 32 bits) or needlessly forcing everything to
long long types.
Thankfully the case where this shows up is only bins <src>, 0, 32, <dest>
which would normally be encoded as a simple move.
* testsuite/v850/allinsns.exp: Add v850e3v5.
* testsuite/v850/bins.cgs: New test.
* v850/simops.c (v850_bins): Avoid undefined behavior on left shift.
|
|
Implement the "init" method of struct tramp_frame to prepend tramp
frame unwinder for signal on LoongArch.
With this patch, the following failed testcases can be fixed:
FAIL: gdb.base/annota1.exp: backtrace @ signal handler (timeout)
FAIL: gdb.base/annota3.exp: backtrace @ signal handler (pattern 2)
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
|
|
Since this commit:
commit 8322445e0584be846f5873b9aab257dc9fbda05d
Date: Tue Jun 21 01:11:45 2016 +0100
Introduce interpreter factories
Interpreters should be registered with GDB, not by calling interp_add,
but with a call to interp_factory_register. I've checked the insight
source, and it too has moved over to using interp_factory_register.
In this commit I make interp_add static within interps.c.
There should be no user visible change after this commit.
|
|
offset entry tables.
PR 28981
* dwarf.c (fetch_indexed_value): Rename to fecth_indexed_addr and
return the address, rather than a string.
(fetch_indexed_value): New function - returns a value indexed by a
DW_FORM_loclistx or DW_FORM_rnglistx form.
(read_and_display_attr_value): Add support for DW_FORM_loclistx
and DW_FORM_rnglistx.
(process_debug_info): Load the loclists and rnglists sections.
(display_loclists_list): Add support for DW_LLE_base_addressx,
DW_LLE_startx_endx, DW_LLE_startx_length and
DW_LLE_default_location.
(display_offset_entry_loclists): New function. Displays a
.debug_loclists section that contains offset entry tables.
(display_debug_loc): Call the new function.
(display_debug_rnglists_list): Add support for
DW_RLE_base_addressx, DW_RLE_startx_endx and DW_RLE_startx_length.
(display_debug_ranges): Display the contents of the section's
header.
* dwarf.h (struct debug_info): Add loclists_base field.
* testsuite/binutils-all/dw5.W: Update expected output.
* testsuite/binutils-all/x86-64/pr26808.dump: Likewise.
|
|
This set of changes enable support for the ARMv8.1-m PACBTI extensions [1].
The goal of the PACBTI extensions is similar in scope to that of a-profile
PAC/BTI (aarch64 only), but the underlying implementation is different.
One important difference is that the pointer authentication code is stored
in a separate register, thus we don't need to mask/unmask the return address
from a function in order to produce a correct backtrace.
The patch introduces the following modifications:
- Extend the prologue analyser for 32-bit ARM to handle some instructions
from ARMv8.1-m PACBTI: pac, aut, pacg, autg and bti. Also keep track of
return address signing/authentication instructions.
- Adds code to identify object file attributes that indicate the presence of
ARMv8.1-m PACBTI (Tag_PAC_extension, Tag_BTI_extension, Tag_PACRET_use and
Tag_BTI_use).
- Adds support for DWARF pseudo-register RA_AUTH_CODE, as described in the
aadwarf32 [2].
- Extends the dwarf unwinder to track the value of RA_AUTH_CODE.
- Decorates backtraces with the "[PAC]" identifier when a frame has signed
the return address.
- Makes GDB aware of a new XML feature "org.gnu.gdb.arm.m-profile-pacbti". This
feature is not included as an XML file on GDB's side because it is only
supported for bare metal targets.
- Additional documentation.
[1] https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension
[2] https://github.com/ARM-software/abi-aa/blob/main/aadwarf32/aadwarf32.rst
|
|
While working on the disassembler I was getting frustrated. Every
time I touched disasm.h it seemed like every file in GDB would need to
be rebuilt. Surely the disassembler can't be required by that many
parts of GDB, right?
Turns out that disasm.h is included in target.h, so pretty much every
file was being rebuilt!
The only thing from disasm.h that target.h needed is the
gdb_disassembly_flag enum, as this is part of the target_ops api.
In this commit I move gdb_disassembly_flag into its own file. This is
then included in target.h and disasm.h, after which, the number of
files that depend on disasm.h is much reduced.
I also audited all the other includes of disasm.h and found that the
includes in mep-tdep.c and python/py-registers.c are no longer needed,
so I've removed these.
Now, after changing disasm.h, GDB rebuilds much quicker.
There should be no user visible changes after this commit.
|
|
|
|
Simon pointed out that timestamped_file probably needed to implement a
few more methods. This patch introduces a new file-wrapping file that
forwards most of its calls, making it simpler to implement new such
files. It also converts timestamped_file and pager_file to use it.
Regression tested on x86-64 Fedora 34.
|
|
I don't think there's any need to call init_thread_list in
windows-nat.c. This patch removes it. I tested this using the
internal AdaCore test suite on Windows, which FWIW does include some
multi-threaded inferiors.
|
|
Tom de Vries reported some failures in this test:
continue
Continuing.
[New inferior 2 (process 14967)]
Thread 1.1 "vfork-follow-pa" hit Breakpoint 2, break_parent () at /home/vries/gdb_versions/devel/src/gdb/testsuite/gdb.base/vfork-follow-parent.c:23
23 }
(gdb) FAIL: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: continue to end of inferior 2
inferior 1
[Switching to inferior 1 [process 14961] (/home/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.base/vfork-follow-parent/vfork-follow-parent)]
[Switching to thread 1.1 (process 14961)]
#0 break_parent () at /home/vries/gdb_versions/devel/src/gdb/testsuite/gdb.base/vfork-follow-parent.c:23
23 }
(gdb) PASS: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: inferior 1
continue
Continuing.
[Inferior 2 (process 14967) exited normally]
(gdb) FAIL: gdb.base/vfork-follow-parent.exp: resolution_method=schedule-multiple: continue to break_parent (the program exited)
Here, we continue both the vfork parent and child, since
schedule-multiple is on. The child exits, which un-freezes the parent
and makes an exit event available to GDB. We expect GDB to consume this
exit event and present it to the user. Here, we see that GDB shows the
parent hitting a breakpoint before showing the child exit.
Because of the vfork, we know that chronologically, the child exiting
must have happend before the parent hitting a breakpoint. However,
scheduling being what it is, it is possible for the parent to un-freeze
and exit quickly, such that when GDB pulls events out of the kernel,
exit events for both processes are available. And then, GDB may chose
at random to return the one for the parent first. This is what I
imagine what causes the failure shown above.
We could change the test to expect both possible outcomes, but I wanted
to avoid complicating the .exp file that way. Instead, add a variable
that the parent loops on that we set only after we confirmed the exit of
the child. That should ensure that the order is always the same.
Note that I wasn't able to reproduce the failure, so I can't tell if
this fix really fixes the problem.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29021
Change-Id: Ibc8e527e0e00dac54b22021fe4d9d8ab0f3b28ad
|
|
I got failures like this once on a CI:
frame^M
&"frame\n"^M
~"#0 child_sub_function () at /home/jenkins/workspace/binutils-gdb_master_build/arch/amd64/target_board/unix/src/binutils-gdb/gdb/testsuite/gdb.mi/user-selected-context-sync.c:33\n"^M
~"33\t dummy = !dummy; /* thread loop line */\n"^M
^done^M
(gdb) ^M
FAIL: gdb.mi/mi-cmd-user-context.exp: frame 1 (unexpected output)
The problem is that the test expects the following regexp:
".*#0 0x.*"
And that typically works, when the output of the frame command looks
like:
#0 0x00005555555551bb in child_sub_function () at ...
Note the lack of hexadecimal address in the failing case. Whether or
not the hexadecimal address is printed (roughly) depends on whether the
current PC is at the beginning of a line. So depending on where thread
2 was when GDB stopped it (after thread 1 hit its breakpoint), we can
get either output. Adjust the regexps to not expect an hexadecimal
prefix (0x) but a function name instead (either child_sub_function or
child_function). That one is always printed, and is also a good check
that we are in the frame we expect.
Note that for test "frame 5", we are showing a pthread frame (on my
system), so the function name is internal to pthread, not something we
can rely on. In that case, it's almost certain that we are not at the
beginning of a line, or that we don't have debug info, so I think it's
fine to expect the hex prefix.
And for test "frame 6", it's ok to _not_ expect a hex prefix (what the
test currently does), since we are showing thread 1, which has hit a
breakpoint placed at the beginning of a line.
When testing this, Tom de Vries pointed out that the current test code
doesn't ensure that the child threads are in child_sub_function when
they are stopped. If the scheduler chooses so, it is possible for the
child threads to be still in the pthread_barrier_wait or child_function
functions when they get stopped. So that would be another racy failure
waiting to happen.
The only way I can think of to ensure the child threads are in the
child_sub_function function when they get stopped is to synchronize the
threads using some variables instead of pthread_barrier_wait. So,
replace the barrier with an array of flags (one per child thread). Each
child thread flips its flag in child_sub_function to allow the main
thread to make progress and eventually hit the breakpoint.
I copied user-selected-context-sync.c to a new mi-cmd-user-context.c and
made modifications to that, to avoid interfering with
user-selected-context-sync.exp.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29025
Change-Id: I919673bbf9927158beb0e8b7e9e980b8d65eca90
|
|
Someone at IRC spotted a bug in qRcmd handling. This looks like an oversight
or it is that way for historical reasons.
The code in gdb/remote.c:remote_target::rcmd uses isdigit instead of
isxdigit. One could argue that we are expecting decimal numbers, but further
below we use fromhex ().
Update the function to use isxdigit instead and also update the documentation.
I see there are lots of other cases of undocumented number format for error
messages, mostly described as NN instead of nn. For now I'll just update
this particular function.
|
|
The test introduced by this patch would fail in this configuration, with
the native-gdbserver or native-extended-gdbserver boards:
FAIL: gdb.threads/next-fork-other-thread.exp: fork_func=fork: target-non-stop=auto: non-stop=off: displaced-stepping=auto: i=2: next to for loop
The problem is that the step operation is forgotten when handling the
fork/vfork. With "debug infrun" and "debug remote", it looks like this
(some lines omitted for brevity). We do the next:
[infrun] proceed: enter
[infrun] proceed: addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT
[infrun] resume_1: step=1, signal=GDB_SIGNAL_0, trap_expected=0, current thread [4154304.4154304.0] at 0x5555555553bf
[infrun] do_target_resume: resume_ptid=4154304.0.0, step=1, sig=GDB_SIGNAL_0
[remote] Sending packet: $vCont;r5555555553bf,5555555553c4:p3f63c0.3f63c0;c:p3f63c0.-1#cd
[infrun] proceed: exit
We then handle a fork event:
[infrun] fetch_inferior_event: enter
[remote] wait: enter
[remote] Packet received: T05fork:p3f63ee.3f63ee;06:0100000000000000;07:b08e59f6ff7f0000;10:bf60e8f7ff7f0000;thread:p3f63c0.3f63c6;core:17;
[remote] wait: exit
[infrun] print_target_wait_results: target_wait (-1.0.0 [process -1], status) =
[infrun] print_target_wait_results: 4154304.4154310.0 [Thread 4154304.4154310],
[infrun] print_target_wait_results: status->kind = FORKED, child_ptid = 4154350.4154350.0
[infrun] handle_inferior_event: status->kind = FORKED, child_ptid = 4154350.4154350.0
[remote] Sending packet: $D;3f63ee#4b
[infrun] resume_1: step=0, signal=GDB_SIGNAL_0, trap_expected=0, current thread [4154304.4154310.0] at 0x7ffff7e860bf
[infrun] do_target_resume: resume_ptid=4154304.0.0, step=0, sig=GDB_SIGNAL_0
[remote] Sending packet: $vCont;c:p3f63c0.-1#73
[infrun] fetch_inferior_event: exit
In the first snippet, we resume the stepping thread with the range-stepping (r)
vCont command. But after handling the fork (detaching the fork child), we
resumed the whole process freely. The stepping thread, which was paused by
GDBserver while reporting the fork event, was therefore resumed freely, instead
of confined to the addresses of the stepped line. Note that since this
is a "next", it could be that we have entered a function, installed a
step-resume breakpoint, and it's ok to continue freely the stepping
thread, but that's not the case here. The two snippets shown above were
next to each other in the logs.
For the fork case, we can resume stepping right after handling the
event.
However, for the vfork case, where we are waiting for the
external child process to exec or exit, we only resume the thread that
called vfork, and keep the others stopped (see patch "gdb: fix handling of
vfork by multi-threaded program" prior in this series). So we can't
resume the stepping thread right now. Instead, do it after handling the
vfork-done event.
Change-Id: I92539c970397ce880110e039fe92b87480f816bd
|
|
target_waitstatus::child_ptid if kind == TARGET_WAITKIND_THREAD_EXITED
Following the previous patch, running
gdb.threads/forking-threads-plus-breakpoints.exp continuously eventually
gives me an internal error.
gdb/target/waitstatus.h:372: internal-error: child_ptid: Assertion `m_kind == TARGET_WAITKIND_FORKED || m_kind == TARGET_WAITKIND_VFORKED' failed.^M
FAIL: gdb.threads/forking-threads-plus-breakpoint.exp: cond_bp_target=0: detach_on_fork=on: displaced=off: inferior 1 exited (GDB internal error)
The backtrace is:
0x55925b679c85 internal_error(char const*, int, char const*, ...)
/home/simark/src/binutils-gdb/gdbsupport/errors.cc:55
0x559258deadd2 target_waitstatus::child_ptid() const
/home/simark/src/binutils-gdb/gdb/target/waitstatus.h:372
0x55925a7cbac9 remote_target::remove_new_fork_children(threads_listing_context*)
/home/simark/src/binutils-gdb/gdb/remote.c:7311
0x55925a79dfdb remote_target::update_thread_list()
/home/simark/src/binutils-gdb/gdb/remote.c:3981
0x55925ad79b83 target_update_thread_list()
/home/simark/src/binutils-gdb/gdb/target.c:3793
0x55925addbb15 update_thread_list()
/home/simark/src/binutils-gdb/gdb/thread.c:2031
0x559259d64838 stop_all_threads(char const*, inferior*)
/home/simark/src/binutils-gdb/gdb/infrun.c:5104
0x559259d88b45 keep_going_pass_signal
/home/simark/src/binutils-gdb/gdb/infrun.c:8215
0x559259d8951b keep_going
/home/simark/src/binutils-gdb/gdb/infrun.c:8251
0x559259d78835 process_event_stop_test
/home/simark/src/binutils-gdb/gdb/infrun.c:6858
0x559259d750e9 handle_signal_stop
/home/simark/src/binutils-gdb/gdb/infrun.c:6580
0x559259d6c07b handle_inferior_event
/home/simark/src/binutils-gdb/gdb/infrun.c:5832
0x559259d57db8 fetch_inferior_event()
/home/simark/src/binutils-gdb/gdb/infrun.c:4222
Indeed, the code accesses target_waitstatus::child_ptid when the kind
is TARGET_WAITKIND_THREAD_EXITED, which is not right. A
TARGET_WAITKIND_THREAD_EXITED event does not have a child_ptid value
associated, it has an exit status, which we are not interested in. The
intent is to remove from the thread list the thread that has exited.
Its ptid is found in the stop reply event, get it from there.
Change-Id: Icb298cbb80b8779fdf0c660dde9a5314d5591535
|
|
The test introduced by the following patch would sometimes fail in this
configuration:
FAIL: gdb.threads/next-fork-other-thread.exp: fork_func=vfork: target-non-stop=on: non-stop=off: displaced-stepping=auto: i=14: next to for loop
The test has multiple threads constantly forking or vforking while the
main thread keep doing "next"s.
(After writing the commit message, I realized this also fixes a similar
failure in gdb.threads/forking-threads-plus-breakpoint.exp with the
native-gdbserver and native-extended-gdbserver boards.)
As stop_all_threads is called, because the main thread finished its
"next", it inevitably happens at some point that we ask the remote
target to stop a thread and wait() reports that this thread stopped with
a fork or vfork event, instead of the SIGSTOP we sent to try to stop it.
While running this test, I attached to GDBserver and stopped at
linux-low.cc:3626. We can see that the status pulled from the kernel
for 2742805 is indeed a vfork event:
(gdb) p/x w
$3 = 0x2057f
(gdb) p WIFSTOPPED(w)
$4 = true
(gdb) p WSTOPSIG(w)
$5 = 5
(gdb) p/x (w >> 8) & (PTRACE_EVENT_VFORK << 8)
$6 = 0x200
However, the statement at line 3626 overrides that:
ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
OURSTATUS becomes "stopped by a SIGTRAP". The information about the
fork or vfork is lost.
It's then all downhill from there, stop_all_threads eventually asks for
a thread list update. That thread list includes the child of that
forgotten fork or vfork, the remote target goes "oh cool, a new process,
let's attach to it!", when in fact that vfork child's destiny was to be
detached.
My reverse-engineered understanding of the code around there is that the
if/else between lines 3562 and 3583 (in the original code) makes sure
OURSTATUS is always initialized (not "ignore"). Either the details are
already in event_child->waitstatus (in the case of fork/vfork, for
example), in which case we just copy event_child->waitstatus to
ourstatus. Or, if the event is a plain "stopped by a signal" or a
syscall event, OURSTATUS is set to "stopped", but without a signal
number. Lines 3601 to 3629 (in the original code) serve to fill in that
last bit of information.
The problem is that when `w` holds the vfork status, the code wrongfully
takes this branch, because WSTOPSIG(w) returns SIGTRAP:
else if (current_thread->last_resume_kind == resume_stop
&& WSTOPSIG (w) != SIGSTOP)
The intent of this branch is, for example, when we sent SIGSTOP to try
to stop a thread, but wait() reports that it stopped with another signal
(that it must have received from somewhere else simultaneously), say
SIGWINCH. In that case, we want to report the SIGWINCH. But in our
fork/vfork case, we don't want to take this branch, as the thread didn't
really stop because it received a signal. For the non "stopped by a
signal" and non "syscall signal" cases, we would ideally skip over all
that snippet that fills in the signal or syscall number.
The fix I propose is to move this snipppet of the else branch of the
if/else above. In addition to moving the code, the last two "else if"
branches:
else if (current_thread->last_resume_kind == resume_stop
&& WSTOPSIG (w) != SIGSTOP)
{
/* A thread that has been requested to stop by GDB with vCont;t,
but, it stopped for other reasons. */
ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
}
else if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
are changed into a single else:
else
ourstatus->set_stopped (gdb_signal_from_host (WSTOPSIG (w)));
This is the default path we take if:
- W is not a syscall status
- W does not represent a SIGSTOP that have sent to stop the thread and
therefore want to suppress it
Change-Id: If2dc1f0537a549c293f7fa3c53efd00e3e194e79
|
|
(follow-fork-mode=parent, detach-on-fork=on)
There is a problem with how GDB handles a vfork happening in a
multi-threaded program. This problem was reported to me by somebody not
using vfork directly, but using system(3) in a multi-threaded program,
which may be implemented using vfork.
This patch only deals about the follow-fork-mode=parent,
detach-on-fork=on case, because it would be too much to chew at once to
fix the bugs in the other cases as well (I tried).
The problem
-----------
When a program vforks, the parent thread is suspended by the kernel
until the child process exits or execs. Specifically, in a
multi-threaded program, only the thread that called vfork is suspended,
other threads keep running freely. This is documented in the vfork(2)
man page ("Caveats" section).
Let's suppose GDB is handling a vfork and the user's desire is to detach
from the child. Before detaching the child, GDB must remove the software
breakpoints inserted in the shared parent/child address space, in case
there's a breakpoint in the path the child is going to take before
exec'ing or exit'ing (unlikely, but possible). Otherwise the child could
hit a breakpoint instruction while running outside the control of GDB,
which would make it crash. GDB must also avoid re-inserting breakpoints
in the parent as long as it didn't receive the "vfork done" event (that
is, when the child has exited or execed): since the address space is
shared with the child, that would re-insert breakpoints in the child
process also. So what GDB does is:
1. Receive "vfork" event for the parent
2. Remove breakpoints from the (shared) address space and set
program_space::breakpoints_not_allowed to avoid re-inserting them
3. Detach from the child thread
4. Resume the parent
5. Wait for and receive "vfork done" event for the parent
6. Clean program_space::breakpoints_not_allowed and re-insert
breakpoints
7. Resume the parent
Resuming the parent at step 4 is necessary in order for the kernel to
report the "vfork done" event. The kernel won't report a ptrace event
for a thread that is ptrace-stopped. But the theory behind this is that
between steps 4 and 5, the parent won't actually do any progress even
though it is ptrace-resumed, because the kernel keeps it suspended,
waiting for the child to exec or exit. So it doesn't matter for that
thread if breakpoints are not inserted.
The problem is when the program is multi-threaded. In step 4, GDB
resumes all threads of the parent. The thread that did the vfork stays
suspended by the kernel, so that's fine. But other threads are running
freely while breakpoints are removed, which is a problem because they
could miss a breakpoint that they should have hit.
The problem is present with all-stop and non-stop targets. The only
difference is that with an all-stop targets, the other threads are
stopped by the target when it reports the vfork event and are resumed by
the target when GDB resumes the parent. With a non-stop target, the
other threads are simply never stopped.
The fix
-------
There many combinations of settings to consider (all-stop/non-stop,
target-non-stop on/off, follow-fork-mode parent/child, detach-on-fork
on/off, schedule-multiple on/off), but for this patch I restrict the
scope to follow-fork-mode=parent, detach-on-fork=on. That's the
"default" case, where we detach the child and keep debugging the
parent. I tried to fix them all, but it's just too much to do at once.
The code paths and behaviors for when we don't detach the child are
completely different.
The guiding principle for this patch is that all threads of the vforking
inferior should be stopped as long as breakpoints are removed. This is
similar to handling in-line step-overs, in a way.
For non-stop targets (the default on Linux native), this is what
happens:
- In follow_fork, we call stop_all_threads to stop all threads of the
inferior
- In follow_fork_inferior, we record the vfork parent thread in
inferior::thread_waiting_for_vfork_done
- Back in handle_inferior_event, we call keep_going, which resumes only
the event thread (this is already the case, with a non-stop target).
This is the thread that will be waiting for vfork-done.
- When we get the vfork-done event, we go in the (new) handle_vfork_done
function to restart the previously stopped threads.
In the same scenario, but with an all-stop target:
- In follow_fork, no need to stop all threads of the inferior, the
target has stopped all threads of all its inferiors before returning
the event.
- In follow_fork_inferior, we record the vfork parent thread in
inferior::thread_waiting_for_vfork_done.
- Back in handle_inferior_event, we also call keep_going. However, we
only want to resume the event thread here, not all inferior threads.
In internal_resume_ptid (called by resume_1), we therefore now check
whether one of the inferiors we are about to resume has
thread_waiting_for_vfork_done set. If so, we only resume that
thread.
Note that when resuming multiple inferiors, one vforking and one not
non-vforking, we could resume the vforking thread from the vforking
inferior plus all threads from the non-vforking inferior. However,
this is not implemented, it would require more work.
- When we get the vfork-done event, the existing call to keep_going
naturally resumes all threads.
Testing-wise, add a test that tries to make the main thread hit a
breakpoint while a secondary thread calls vfork. Without the fix, the
main thread keeps going while breakpoints are removed, resulting in a
missed breakpoint and the program exiting.
Change-Id: I20eb78e17ca91f93c19c2b89a7e12c382ee814a1
|
|
This helped me, it shows which ptid we actually call target_resume with.
Change-Id: I2dfd771e83df8c25f39371a13e3e91dc7882b73d
|
|
A following patch will want to stop all threads of a given inferior (as
opposed to all threads of all inferiors) while handling a vfork, and
restart them after. To help with this, add inferior parameters to
stop_all_threads and restart_threads. This is done as a separate patch
to make sure this doesn't cause regressions on its own, and to keep the
following patches more concise.
No visible changes are expected here, since all calls sites pass
nullptr, which should keep the existing behavior.
Change-Id: I4d9ba886ce842042075b4e346cfa64bbe2580dbf
|
|
inferior::thread_waiting_for_vfork_done
The inferior::waiting_for_vfork_done flag indicates that some thread in
that inferior is waiting for a vfork-done event. Subsequent patches
will need to know which thread precisely is waiting for that event.
Replace the boolean flag (waiting_for_vfork_done) with a thread_info
pointer (thread_waiting_for_vfork_done).
I think there is a latent buglet in that waiting_for_vfork_done is
currently not reset on inferior exec or exit. I could imagine that if a
thread in the parent process calls exec or exit while another thread of
the parent process is waiting for its vfork child to exec or exit, we
could end up with inferior::waiting_for_vfork_done without a thread
actually waiting for a vfork-done event anymore. And since that flag is
checked in resume_1, things could misbehave there.
Since the new field points to a thread_info object, and those are
destroyed on exec or exit, it could be worse now since we could try to
access freed memory, if thread_waiting_for_vfork_done were to point to a
stale thread_info. To avoid this, clear the field in
infrun_inferior_exit and infrun_inferior_execd.
Change-Id: I31b847278613a49ba03fc4915f74d9ceb228fdce
|