Commit Graph

879 Commits

Author SHA1 Message Date
Tom de Vries
1d45d90934 [gdb/symtab] Work around PR gas/29517
When using glibc debuginfo generated with gas 2.39, we run into PR gas/29517:
...
$ gdb -q -batch a.out -ex start -ex "p (char *)strstr (\"haha\", \"ah\")"
Temporary breakpoint 1 at 0x40051b: file hello.c, line 6.

Temporary breakpoint 1, main () at hello.c:6
6	  printf ("hello\n");
Invalid cast.
...
while without glibc debuginfo installed we get the expected result:
...
$n = 0x7ffff7daa1b1 "aha"
...
and likewise with glibc debuginfo generated with gas 2.40.

The strstr ifunc resolves to __strstr_sse2_unaligned.  The problem is that gas
generates dwarf that states that the return type is void:
...
<1><3e1e58>: Abbrev Number: 2 (DW_TAG_subprogram)
    <3e1e59>   DW_AT_name        : __strstr_sse2_unaligned
    <3e1e5d>   DW_AT_external    : 1
    <3e1e5e>   DW_AT_low_pc      : 0xbbd2e
    <3e1e66>   DW_AT_high_pc     : 0xbc1c3
...
while the return type should be a DW_TAG_unspecified_type, as is the case
with gas 2.40.

We can still use the workaround of casting to another function type for both
__strstr_sse2_unaligned:
...
(gdb) p ((char * (*) (const char *, const char *))__strstr_sse2_unaligned) \
  ("haha", "ah")
$n = 0x7ffff7daa211 "aha"
...
and strstr (which requires using *strstr to dereference the ifunc before we
cast):
...
gdb) p ((char * (*) (const char *, const char *))*strstr) ("haha", "ah")
$n = 0x7ffff7daa251 "aha"
...
but that's a bit cumbersome to use.

Work around this in the dwarf reader, such that we have instead:
...
(gdb) p (char *)strstr ("haha", "ah")
$n = 0x7ffff7daa1b1 "aha"
...

This also requires fixing producer_is_gcc to stop returning true for
producer "GNU AS 2.39.0".

Tested on x86_64-linux.

Approved-By: Andrew Burgess <aburgess@redhat.com>

PR symtab/30911
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30911
2023-10-16 16:32:28 +02:00
Matheus Branco Borella
8b9c08edda [gdb/symtab] Add name_of_main and language_of_main to the DWARF index
This patch adds a new section to the DWARF index containing the name
and the language of the main function symbol, gathered from
`cooked_index::get_main`, if available. Currently, for lack of a better name,
this section is called the "shortcut table". The way this name is both saved and
applied upon an index being loaded in mirrors how it is done in
`cooked_index_functions`, more specifically, the full name of the main function
symbol is saved and `set_objfile_main_name` is used to apply it after it is
loaded.

The main use case for this patch is in improving startup times when dealing with
large binaries. Currently, when an index is used, GDB has to expand symtabs
until it finds out what the language of the main function symbol is. For some
large executables, this may take a considerable amount of time to complete,
slowing down startup. This patch bypasses that operation by having both the name
and language of the main function symbol be provided ahead of time by the index.

In my testing (a binary with about 1.8GB worth of DWARF data) this change brings
startup time down from about 34 seconds to about 1.5 seconds.

When testing the patch with target board cc-with-gdb-index, test-case
gdb.fortran/nested-funcs-2.exp starts failing, but this is due to a
pre-existing issue, filed as PR symtab/30946.

Tested on x86_64-linux, with target board unix and cc-with-gdb-index.

PR symtab/24549
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=24549

Approved-By: Tom de Vries <tdevries@suse.de>
2023-10-10 10:26:40 +02:00
Tom Tromey
ef0f16ccf8 Remove explanatory comments from includes
I noticed a comment by an include and remembered that I think these
don't really provide much value -- sometimes they are just editorial,
and sometimes they are obsolete.  I think it's better to just remove
them.  Tested by rebuilding.

Approved-By: Andrew Burgess <aburgess@redhat.com>
2023-09-20 11:45:16 -06:00
Tom de Vries
973db6fae3 [gdb/symtab] Error out for .debug_types section in dwz file
There are two methods to factor out type information in a dwarf4 executable:
- use -fdebug-info-types to generate type units in a .debug_types section, and
- use dwz to create partial units.

The dwz method has an extra benefit: it also allows to factor out information
between executables into a newly created .dwz file, pointed to by a
.gnu_debugaltlink section.

There is nothing prohibiting a .gnu_debugaltlink file to contain a
.debug_types section.

It's just not generated by dwz or any other tool atm, and consequently gdb has
no support for it.  Enhancement PR symtab/30838 is open about the lack of
support.

Make the current situation explicit by emitting a dwarf error:
...
(gdb) file struct-with-sig-2^M
Reading symbols from struct-with-sig-2...^M
Dwarf Error: .debug_types section not supported in dwz file^M
...
and add an assert in write_gdbindex:
...
+      /* See enhancement PR symtab/30838.  */
+      gdb_assert (!(per_cu->is_dwz && per_cu->is_debug_types));
...
to clarify why we can use:
...
      data_buf &cu_list = (per_cu->is_debug_types
                           ? types_cu_list
                           : per_cu->is_dwz ? dwz_cu_list : objfile_cu_list);
...

The test-case is a modified copy from gdb.dwarf2/struct-with-sig.exp, so it
keeps the copyright years range.

Tested on x86_64-linux.

Tested-By: Guinevere Larsen <blarsen@redhat.com>

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30838
2023-09-20 16:05:55 +02:00
Tom Tromey
76fc0f6213 Give a language to a type
This changes main_type to hold a language, and updates the debug
readers to set this field.  This is done by adding the language to the
type-allocator object.

Note that the non-DWARF readers are changed on a "best effort" basis.

This patch also reimplements type::is_array_like to use the type's
language, and it adds a new type::is_string_like as well.  This in
turn lets us change the Python implementation of these methods to
simply defer to the type.
2023-09-19 13:28:42 -06:00
Tom Tromey
d948c67c5d Regularize some DWARF type initialization
In one spot, it will be convenient for a subsequent patch if the CU is
passed to a type-creation helper function.  In another spot, remove
the redundant 'objfile' parameter to another such function.
2023-09-19 13:28:42 -06:00
Tom Tromey
d559227272 Pass a type allocator to init_fixed_point_type
init_fixed_point_type currently takes an objfile and creates its own
type allocator.  However, for a later patch it is more convenient if
this function accepts a type allocator.  This patch makes this change.
2023-09-19 13:28:42 -06:00
Tom de Vries
93203eebe2 [gdb/symtab] Fix overly large gdb-index file check for 32-bit
Add a unit test which checks that write_gdb_index_1 will throw
an error when the size of the file would exceed the maximum value
capable of being represented by 'offset_type'.

The unit test fails on 32-bit systems due to wrapping overflow.  Fix this by
changing the type of total_len in write_gdbindex_1 from size_t to uint64_t.

Tested on x86_64-linux.

Co-Authored-By: Kevin Buettner <kevinb@redhat.com>
Approved-by: Kevin Buettner <kevinb@redhat.com>
2023-09-16 04:10:53 +02:00
Tom Tromey
fe26aa9533 Rename split_style::DOT
This renames split_style::DOT, to avoid name clashes when building gdb
with an old version of Bison (2.3, the version available on macOS).

In particular the error looks like:

./split-name.h:34:3: error: expected identifier
  DOT,
  ^
m2-exp.c:163:13: note: expanded from macro 'DOT'

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30286
2023-09-15 07:39:47 -06:00
Kevin Buettner
98f6baad7c Throw error when creating an overly large gdb-index file
The header in a .gdb_index section uses 32-bit unsigned offsets to
refer to other areas of the section.  Thus, there is a size limit of
2^32-1 which is currently unaccounted for by GDB's code for outputting
these sections.

At the moment, when GDB creates an overly large section, it will exit
abnormally due to an internal error, which is caused by a failed
assert in assert_file_size, which in turn is called from
write_gdbindex_1, both of which are in gdb/dwarf2/index-write.c.

This is what happens when that assert fails:

$ gdb -q -nx -iex 'set auto-load no' -iex 'set debuginfod enabled off' -ex file ./libgraph_tool_inference.so -ex "save gdb-index `pwd`/"
Reading symbols from ./libgraph_tool_inference.so...
No executable file now.
Discard symbol table from `libgraph_tool_inference.so'? (y or n) n
Not confirmed.
../../gdb/dwarf2/index-write.c:1069: internal-error: assert_file_size: Assertion `file_size == expected_size' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
0x55fddb4d78b0 gdb_internal_backtrace_1
	../../gdb/bt-utils.c:122
0x55fddb4d78b0 _Z22gdb_internal_backtracev
	../../gdb/bt-utils.c:168
0x55fddb98b5d4 internal_vproblem
	../../gdb/utils.c:396
0x55fddb98b8de _Z15internal_verrorPKciS0_P13__va_list_tag
	../../gdb/utils.c:476
0x55fddbb71654 _Z18internal_error_locPKciS0_z
	../../gdbsupport/errors.cc:58
0x55fddb5a0f23 assert_file_size
	../../gdb/dwarf2/index-write.c:1069
0x55fddb5a1ee0 assert_file_size
	/usr/include/c++/13/bits/stl_iterator.h:1158
0x55fddb5a1ee0 write_gdbindex_1
	../../gdb/dwarf2/index-write.c:1119
0x55fddb5a51be write_gdbindex
	../../gdb/dwarf2/index-write.c:1273
[...]
---------------------
../../gdb/dwarf2/index-write.c:1069: internal-error: assert_file_size: Assertion `file_size == expected_size' failed.

This problem was encountered while building the python-graph-tool
package on Fedora.  The Fedora bugzilla bug can be found here:

https://bugzilla.redhat.com/show_bug.cgi?id=1773651

This commit prevents the internal error from occurring by calling error()
when the file size exceeds 2^32-1.

Using a gdb built with this commit, I now see this behavior instead:

$ gdb -q -nx -iex 'set auto-load no' -iex 'set debuginfod enabled off' -ex file ./libgraph_tool_inference.so -ex "save gdb-index `pwd`/"
Reading symbols from ./libgraph_tool_inference.so...
No executable file now.
Discard symbol table from `/mesquite2/fedora-bugs/1773651/libgraph_tool_inference.so'? (y or n) n
Not confirmed.
Error while writing index for `/mesquite2/fedora-bugs/1773651/libgraph_tool_inference.so': gdb-index maximum file size of 4294967295 exceeded
(gdb)

I wish I could provide a test case, but due to the sizes of both the
input and output files, I think that testing resources would be
strained or exceeded in many environments.

My testing on Fedora 38 shows no regressions.

Approved-by: Tom Tromey <tom@tromey.com>
2023-09-14 16:52:16 -07:00
Andrew Burgess
54392c4df6 gdb: fix buffer overflow in DWARF reader
In this commit:

  commit 48ac197b0c
  Date:   Fri Nov 19 10:12:44 2021 -0700

      Handle multiple addresses in call_site_target

a buffer overflow bug was introduced when the following code was
added:

  CORE_ADDR *saved = XOBNEWVAR (&objfile->objfile_obstack, CORE_ADDR,
                                addresses.size ());
  std::copy (addresses.begin (), addresses.end (), saved);

The definition of XOBNEWVAR is (from libiberty.h):

  #define XOBNEWVAR(O, T, S)	((T *) obstack_alloc ((O), (S)))

So 'saved' is going to point to addresses.size () bytes of memory,
however, the std::copy will write addresses.size () number of
CORE_ADDR sized entries to the address pointed to by 'saved', this is
going to result in memory corruption.

The mistake is that we should have used XOBNEWVEC, which allocates a
vector of entries, the definition of XOBNEWVEC is:

  #define XOBNEWVEC(O, T, N) \
    ((T *) obstack_alloc ((O), sizeof (T) * (N)))

Which means we will have set aside enough space to create a copy of
the contents of the addresses vector.

I'm not sure how to create a test for this problem, this issue cropped
up when debugging a particular i686 built binary, which just happened
to trigger a glibc assertion (likely due to random memory corruption),
debugging the same binary built for x86-64 appeared to work just fine.

Using valgrind on the failing GDB binary pointed straight to the cause
of the problem, and with this patch in place there are no longer
valgrind errors in this area.

If anyone has ideas for a test I'm happy to work on something.

Co-Authored-By: Keith Seitz <keiths@redhat.com>
Approved-By: Tom Tromey <tom@tromey.com>
2023-09-14 22:13:07 +01:00
Tom de Vries
be7d5d2c41 [gdb/symtab] Fix gdb-index writing for .debug_types
With test-case gdb.ada/same_enum.exp and target board dwarf4-gdb-index we run
into:
...
(gdb) print red^M
No definition of "red" in current context.^M
(gdb) FAIL: gdb.ada/same_enum.exp: print red
...

[ This is a regression since commit 844a72efbc ("Simplify gdb_index writing"),
so this is broken in gdb 12 and 13. ]

The easiest way to see what's going wrong is with readelf.  We have in section
.gdb_index:
...
[7194] pck__red:
        2 [static, variable]
        3 [static, variable]
...
which points to the CUs 2 and 3 in the CU list (shown using "2" and "3"), but
should be pointing to the TUs 2 and 3 in the TU list (shown using "T2" and
"T3").

Fix this by removing the counter / types_counter distinction in
write_gdbindex, such that we get the expected:
...
[7194] pck__red:
        T2 [static, variable]
        T3 [static, variable]
...

[ While reading write_gdbindex I noticed a few oddities related to dwz
handling, I've filed PR30829 about this. ]

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30827
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30827
2023-09-07 21:59:33 +02:00
Tom Tromey
dec28322cf Introduce TYPE_SPECIFIC_RUST_STUFF
This adds a new enum constant, TYPE_SPECIFIC_RUST_STUFF, and changes
the DWARF reader to set this on Rust types.  This will be used as a
flag in a later patch.

Note that the size of the type_specific_field bitfield had to be
increased.  I checked that this did not impact the size of main_type.
2023-09-05 11:02:34 -06:00
Tom Tromey
655e4e52ef Avoid crash with Ada and -fdata-sections
A user noticed that gdb would crash when showing a backtrace.
Investigation showed this to be a crash in the DWARF reader when
handling a "pragma export" symbol.  The bug here is that earlier code
decides to eliminate the symbol, but the export code tries to add it
anyway -- but to a NULL list.
2023-09-05 09:48:24 -06:00
Simon Marchi
3be8c91910 gdb: remove FIELD_BITSIZE
Replace with field::bitsize.

Change-Id: I400be235d6a1f446d0a4aafac01df5e850185d3a
Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 13:16:14 -04:00
Simon Marchi
886176b865 gdb: introduce field::bitsize / field::set_bitsize
Add these two methods, rename the field to m_bitsize to make it pseudo
private.

Change-Id: Ief95e5cf106e72f2c22ae47b033d0fa47202b413
Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 13:16:13 -04:00
Simon Marchi
454977cdc4 gdb: remove TYPE_FIELD_ARTIFICIAL
Replace with type::field + field::is_artificial.

Change-Id: Ie3bacae49d9bd02e83e504c1ce01470aba56a081
Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 13:16:13 -04:00
Simon Marchi
321d8b3f28 gdb: introduce field::is_artificial / field::set_is_artificial
Add these two methods, rename the field to m_artificial to make it
pseudo private.

Change-Id: If3a3825473d1d79bb586a8a074b87bba9b43fb1a
Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 13:16:11 -04:00
Tom Tromey
8688bb6278 Unify DW_TAG_typedef case in new_symbol
This patch merges the DW_TAG_typedef case in new_symbol with some
other type-related cases.  These all have identical code.

Reviewed-By: Guinevere Larsen <blarsen@redhat.com>
2023-08-31 07:39:50 -06:00
Tom de Vries
959db21230 [gdb/symtab] Replace TYPE_ALLOC with TYPE_ZALLOC where required
Handle the remaining uses of TYPE_ALLOC, either by:
- replacing with TYPE_ZALLOC, or
- adding a comment explaining why zero-initialization is not necessary.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 09:37:44 +02:00
Tom de Vries
6d3c2d749b [gdb/symtab] Replace TYPE_ALLOC + B_CLRALL with TYPE_ZALLOC
I noticed some cases of TYPE_ALLOC followed by B_CLRALL.

Replace these with TYPE_ZALLOC.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-31 09:37:44 +02:00
Tom de Vries
2774f2dad5 [gdb/symtab] Factor out type::{alloc_fields,copy_fields}
After finding this code in buildsym_compunit::finish_block_internal:
...
              ftype->set_fields
                ((struct field *)
                 TYPE_ALLOC (ftype, nparams * sizeof (struct field)));
...
and fixing PR30810 by using TYPE_ZALLOC, I wondered if there were more
locations that needed fixing.

I decided to make things easier to spot by factoring out a new function
alloc_fields:
...
 /* Allocate the fields array of this type, with NFIELDS elements.  If INIT,
     zero-initialize the allocated memory.  */
  void
  type::alloc_fields (unsigned int nfields, bool init = true);
...
where:
- a regular use would be "alloc_fields (nfields)", and
- an exceptional use that needed no initialization would be
  "alloc_fields (nfields, false)".

Pretty soon I discovered that most of the latter cases are due to
initialization by memcpy, so I added two variants of copy_fields as well.

After this rewrite there are 8 uses of set_fields left:
...
gdb/coffread.c:	  type->set_fields (nullptr);
gdb/coffread.c:	  type->set_fields (nullptr);
gdb/coffread.c:	  type->set_fields (nullptr);
gdb/eval.c:  type->set_fields
gdb/gdbtypes.c:  type->set_fields (args);
gdb/gdbtypes.c:  t->set_fields (XRESIZEVEC (struct field, t->fields (),
gdb/dwarf2/read.c:      type->set_fields (new_fields);
gdb/dwarf2/read.c:	      sub_type->set_fields (sub_type->fields () + 1);
...

These fall into the following categories:
- set to nullptr (coffread.c),
- type not owned by objfile or gdbarch (eval.c), and
- modifying an existing fields array, like adding an element at the end or
  dropping an element at the start (the rest).

Tested on x86_64-linux.
2023-08-31 09:37:44 +02:00
Tom Tromey
b8a175b415 Use sect_offset_str in cooked_index::dump
Mark Wielaard pointed out that cooked_index::dump uses PRIx64, and
Andreas Schwab pointed out that gdb already has sect_offset_str.  This
patch applies both these observations.
2023-08-28 10:37:38 -06:00
Tom de Vries
8d83f51b91 [gdb/symtab] Handle self-reference in inherit_abstract_dies
Building gdb with gcc 7.5.0 and -flto -O2 -flto-partition=one generates a
self-referencing DIE:
...
 <2><91dace>: Abbrev Number: 405 (DW_TAG_label)
    <91dad0>   DW_AT_abstract_origin: <0x91dace>
...

When encountering the self-reference DIE in inherit_abstract_dies we loop
following the abstract origin, effectively hanging gdb.

Fix this by handling self-referencing DIEs in the loop in
inherit_abstract_dies.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30799
https://sourceware.org/bugzilla/show_bug.cgi?id=30799
2023-08-28 16:27:58 +02:00
Andrew Burgess
0b72cde372 gdb: add gdb::make_unique function
While GDB is still C++11, lets add a gdb::make_unique template
function that can be used to create std::unique_ptr objects, just like
the C++14 std::make_unique.

If GDB is being compiled with a C++14 compiler then the new
gdb::make_unique function will delegate to the std::make_unique.  I
checked with gcc, and at -O1 and above gdb::make_unique will be
optimised away completely in this case.

If C++14 (or later) becomes our minimum, then it will be easy enough
to go through the code and replace gdb::make_unique with
std::make_unique later on.

I've make use of this function in all the places I think this can
easily be used, though I'm sure I've probably missed some.

Should be no user visible changes after this commit.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-23 09:50:30 +01:00
Tom de Vries
2b9ed6db3f [gdb/build, c++20] Fix invalid conversion in test_symbols
When building gdb with -std=c++20, I run into:
...
gdb/dwarf2/read.c:2709:3: error: invalid conversion from ‘const char8_t*’ to \
  ‘const char*’ [-fpermissive]
 2709 |   u8"u8função",
      |   ^~~~~~~~~~~~
      |   |
      |   const char8_t*
...

Fix this by making the conversion explicit.

Tested on x86_64-linux.
2023-08-17 10:41:34 +02:00
Tom de Vries
eeee4389cf [gdb/symtab] Handle self-reference DIE
While working on a dwarf assembly test-case I accidentally created the
following pathological dwarf:
...
 <1><be>: Abbrev Number: 3 (DW_TAG_class_type)
    <bf>   DW_AT_name        : c1
    <c2>   DW_AT_specification: <0xbe>
...
and noticed gdb segfaulting during cooked index creating due to running out of
stack.  This is a regression from gdb-12, where gdb just hung.

Fix this by inhibiting the scan_attributes self-recursion for self-references.

The same test-case with -readnow makes gdb hang, so also fix this in
dwarf2_attr and follow_die_ref.

Note that this doesn't fix the same problems for the more complicated case of:
...
 <1><be>: Abbrev Number: 3 (DW_TAG_class_type)
    <bf>   DW_AT_name        : c1
    <c2>   DW_AT_specification: <0xc6>
 <1><c6>: Abbrev Number: 4 (DW_TAG_class_type)
    <c7>   DW_AT_name        : c2
    <ca>   DW_AT_specification: <0xbe>
...
but the approach for deciding whether to fix pathological dwarf cases is as
per PR27981 comment 3:
...
yes if it is cheap/obvious, and no if it is something complicated or expensive.
...
and at this point I'm not sure whether fixing this will fall in the first
category.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-16 23:43:25 +02:00
Tom de Vries
aef36dee93 [gdb/symtab] Don't deduplicate variables in gdb-index
When running test-case gdb.python/py-symbol.exp with target board
cc-with-gdb-index, we run into:
...
(gdb) python print (len (gdb.lookup_static_symbols ('rr')))^M
1^M
(gdb) FAIL: gdb.python/py-symbol.exp: print (len (gdb.lookup_static_symbols ('rr')))
...

[ Note that the test-case contains rr in both py-symtab.c:
...
static int __attribute__ ((used)) rr = 42;	/* line of rr */
...
and py-symtab-2.c:
...
static int __attribute__ ((used)) rr = 99;	/* line of other rr */
... ]

This passes with gdb-12-branch, and fails with gdb-13-branch.

AFAIU the current code in symtab_index_entry::minimize makes the assumption
that it's fine to store only one copy of rr in the gdb-index, because
"print rr" will only ever print one, and always the same.

But that fails to recognize that gdb supports gdb.lookup_static_symbols, which
returns a list of variables rather than the first one.

In other words, the current approach breaks feature parity between cooked
index and gdb-index.

Note btw that also debug-names has both instances:
...
[  5] #00597969 rr:
        <4> DW_TAG_variable DW_IDX_compile_unit=3 DW_IDX_GNU_internal=1
        <4> DW_TAG_variable DW_IDX_compile_unit=4 DW_IDX_GNU_internal=1
...

Fix this in symtab_index_entry::minimize, by not deduplicating variables.

Tested on x86_64-linux, with target boards unix and cc-with-gdb-index.

Reviewed-by: Kevin Buettner <kevinb@redhat.com>

PR symtab/30720
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30720
2023-08-13 14:08:06 +02:00
Tom de Vries
aa5b8b8cc3 [gdb/symtab] Fix off-by-one error in cooked_indexer::recurse
Test-case gdb.dwarf2/pr13961.exp contains:
...
 <1><25>: Abbrev Number: 8 (DW_TAG_class_type)
    <26>   DW_AT_specification: <0x2a>
 <1><2a>: Abbrev Number: 2 (DW_TAG_class_type)
    <2b>   DW_AT_name        : foo
    <2f>   DW_AT_byte_size   : 4
    <30>   DW_AT_decl_file   : 1
    <31>   DW_AT_decl_line   : 1
    <32>   DW_AT_sibling     : <0x44>
...

The DIE at 0x25 contains an intra-CU forward reference, and is deferred during
DIE indexing in the cooked_index, by adding it to m_deferred_entries.

The resulting cooked index entries are:
...
        [25] ((cooked_index_entry *) 0x333b5d0)
        name:       foo
        canonical:  foo
        qualified:  foo
        DWARF tag:  DW_TAG_class_type
        flags:      0x0 []
        DIE offset: 0x2a
        parent:     ((cooked_index_entry *) 0)

        [26] ((cooked_index_entry *) 0x333b630)
        name:       foo
        canonical:  foo
        qualified:  foo::foo
        DWARF tag:  DW_TAG_class_type
        flags:      0x0 []
        DIE offset: 0x25
        parent:     ((cooked_index_entry *) 0x333b5d0) [foo]
...

Notice that 0x2a is the parent of 0x25, and that this is why the qualified
name of 0x25 is "foo::foo", which is incorrect, it's supposed to be "foo".

The parent is set here in cooked_indexer::make_index:
...
  for (const auto &entry : m_deferred_entries)
    {
      void *obj = m_die_range_map.find (entry.spec_offset);
      cooked_index_entry *parent = static_cast<cooked_index_entry *> (obj);
      m_index_storage->add (entry.die_offset, entry.tag, entry.flags,
			    entry.name, parent, m_per_cu);
    }
...
and AFAICT, we store in m_die_range_map the parent of the respective
spec_offset DIE (though that's not clear from the comment describing it).

So, the root cause of this is that when we lookup the parent for DIE 0x25, we get
m_die_range_map.find (0x2a) == 0x2a.

This is an off-by-one error, fixed in cooked_indexer::recurse by:
...
-      CORE_ADDR start = form_addr (parent_entry->die_offset,
+      CORE_ADDR start = form_addr (parent_entry->die_offset + 1,
...
which gives us:
...
    [12] ((cooked_index_entry *) 0x41e21f0)
    name:       foo
    canonical:  foo
    qualified:  foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x25
    parent:     ((cooked_index_entry *) 0)

    [13] ((cooked_index_entry *) 0x41e2190)
    name:       foo
    canonical:  foo
    qualified:  foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x2a
    parent:     ((cooked_index_entry *) 0)
...

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30739
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30739
2023-08-10 21:16:30 +02:00
Tom de Vries
8f258a6c97 [gdb/symtab] Dump qualified name of cooked_index_entry
When doing "maint print objfiles" for the exec of test-case
gdb.dwarf2/pr13961.exp, we get:
...
    [25] ((cooked_index_entry *) 0x37b25d0)
    name:       foo
    canonical:  foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x2a
    parent:     ((cooked_index_entry *) 0)

    [26] ((cooked_index_entry *) 0x37b2630)
    name:       foo
    canonical:  foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x25
    parent:     ((cooked_index_entry *) 0x37b25d0) [foo]
...

By following the parent links in the text, we can conclude that the qualified
name of DIE 0x25 is foo::foo (which is incorrect, that's PR symtab/30739).

But it's not evident, and also hard to verify in a test-case.

Add dumping of the qualified name, such that we have:
...
    [25] ((cooked_index_entry *) 0x333b5d0)
    name:       foo
    canonical:  foo
    qualified:  foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x2a
    parent:     ((cooked_index_entry *) 0)

    [26] ((cooked_index_entry *) 0x333b630)
    name:       foo
    canonical:  foo
    qualified:  foo::foo
    DWARF tag:  DW_TAG_class_type
    flags:      0x0 []
    DIE offset: 0x25
    parent:     ((cooked_index_entry *) 0x333b5d0) [foo]
...

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-10 21:16:30 +02:00
Tom de Vries
62a21046a9 [gdb/symtab] Fix assertion in write_debug_names
When running test-case gdb.dwarf2/pr13961.exp with target-board
cc-with-debug-names, I run into:
...
Running gdb.dwarf2/pr13961.exp ...
gdb compile failed, gdb/dwarf2/index-write.c:1305: internal-error: \
  write_debug_names: Assertion `counter == per_bfd->all_units.size ()' failed.
...

This is a regression since commit 542a33e348 ("Only use the per-BFD object to
 write a DWARF index"), which did:
...
-  gdb_assert (counter == per_objfile->per_bfd->all_comp_units.size ());
+  gdb_assert (counter == per_bfd->all_units.size ());
...

Fix this by reverting to using all_comp_units:
...
  gdb_assert (counter == per_bfd->all_comp_units.size ());
...

Tested on x86_64-linux, using target boards unix and cc-with-debug-names.

PR symtab/30741
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30741
2023-08-10 15:46:30 +02:00
Alan Modra
226f9f4fad Rename bfd_bread and bfd_bwrite
These were renamed from bfd_read and bfd_write back in 2001 when they
lost an unnecessary parameter.  Rename them back, and get rid of a few
casts that are only needed without prototyped functions (K&R C).
2023-08-09 08:48:09 +09:30
Tom de Vries
aaa1d4b8f2 [gdb/build] Fix build breaker with -std=c++11
When building with -std=c++11 I run into:
...
gdb/dwarf2/cooked-index.c: In member function \
  ‘void cooked_index::start_writing_index(dwarf2_per_bfd*)’:
gdb/dwarf2/cooked-index.c:469:10: error: lambda capture initializers only \
  available with -std=c++14 or -std=gnu++14 [-Werror]
          ctx = std::move (ctx)] ()
          ^~~
...

Fix this by capturing a copy instead when using -std=c++11:
...
    = gdb::thread_pool::g_thread_pool->post_task ([this, per_bfd, ctx] ()
...

Tested by building with and without -stdc=++11 on x86_64-linux.

Reported-By: Tom Tromey <tom@tromey.com>
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
2023-08-08 10:08:04 +02:00
Tom de Vries
d06730bc02 [gdb/symtab] Find main language without symtab expansion
When loading an executable using "file a.out", the language is set according
to a.out, which can involve looking up the language of symbol "main", which
will cause the symtab expansion for the containing CU.

Expansion of lto debug info can be slow, so in commit d321419811 ("[gdb] Use
partial symbol table to find language for main") a feature was added to avoid
the symtab expansion.

This feature stopped working after commit 7f4307436fd ("Fix "start" for D,
Rust, etc").

[ The commit addresses problems related to command start, which requires finding
the main function:
- for language D, "main" was found instead of "D main", and
- for Rust, the correct function was found, but attributed the wrong name
  (not fully qualified). ]

Reimplement the feature by adding
cooked_index_functions::lookup_global_symbol_language.

Tested on x86_64-linux.

PR symtab/30661
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30661
2023-08-05 17:57:13 +02:00
Tom Tromey
0ecf440316 Consolidate calls to bfd_set_cacheable
I noticed that some spots in gdb call bfd_set_cacheable after opening
a BFD.

The BFD file cache is a bit odd.  BFDs that are opened locally are
unconditionally registered with the cache, and their underlying file
descriptor will always be closed when bfd_cache_close_all is called.
However, only "cacheable" BFDs will be eligible for reopening when
needed -- and by default BFD decides that if a file descriptor is
passed in, then it should not be cacheable.  If a non-cacheable BFD's
file descriptor is closed, there is no offical way to reopen it.

gdb needs to call bfd_cache_close_all, because some systems cannot
start an executable when it has an open file descriptor referencing
it.

However, gdb also will sometimes passes an open file descriptor to the
various BFD open functions.  And, due to lazy DWARF reading, gdb may
also need to reopen these BFDs.

Rather than having all the callers figure out when exactly to set the
cacheable flag, I think it makes sense to consolidate this logic into
the gdb_bfd.c wrapper functions.  It is ok to do this because gdb
always passes a filename to these open functions, so reopening should
work ok.

Regression tested on x86-64 Fedora 38.

Reviewed-by: John Baldwin <jhb@FreeBSD.org>
2023-08-04 12:05:53 -06:00
Tom de Vries
0961970dea [gdb/symtab] Fix data race on dwarf2_per_cu_data::{files_read,is_debug_types}
With gdb build with -fsanitize=thread, and the exec from test-case
gdb.base/index-cache.exp, I run into:
...
$ rm -f ~/.cache/gdb/*; \
  gdb -q -batch -iex "set index-cache enabled on" index-cache \
    -ex "print foobar"
  ...
WARNING: ThreadSanitizer: data race (pid=25018)
  Write of size 1 at 0x7b200000410d by main thread:
    #0 dw2_get_file_names_reader gdb/dwarf2/read.c:2033 (gdb+0x7ab023)
    #1 dw2_get_file_names gdb/dwarf2/read.c:2130 (gdb+0x7ab023)
    #2 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3105 (gdb+0x7ac6e9)
    #3 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d040f)
    #4 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5b6e)
    #5 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc441d)
    #6 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc4522)
    #7 classify_name gdb/c-exp.y:3083 (gdb+0x61afec)
    #8 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13)
    #9 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e)
    #10 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864)
    #11 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x977245)
    #12 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10b1b)
    #13 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb1112e)
    #14 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf8c)
    #15 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4caaa)
    #16 print_command gdb/printcmd.c:1468 (gdb+0xb4cdda)
    #17 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078)
    #18 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53)
    #19 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a7ea)
    #20 catch_command_errors gdb/main.c:518 (gdb+0xa183fd)
    #21 execute_cmdargs gdb/main.c:617 (gdb+0xa185bf)
    #22 captured_main_1 gdb/main.c:1289 (gdb+0xa1aad8)
    #23 captured_main gdb/main.c:1310 (gdb+0xa1b9da)
    #24 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b9da)
    #25 main gdb/gdb.c:39 (gdb+0x42506a)

  Previous read of size 1 at 0x7b200000410d by thread T2:
    #0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30)
    #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803)
    #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36)
    #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d)
    #4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d)
    #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d)
    #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c)
    #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db)
    #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db)
    #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db)
    #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db)
    #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db)
    #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954)
    #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954)
    #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a)
    #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a)
    #19 pthread_once <null> (libtsan.so.0+0x4457c)
    #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b)
    #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b)
    #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174570d)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174570d)
    #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174570d)
    #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174570d)
    #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x17480c0)
    #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x17480c0)
    #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x17480c0)
    #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x17480c0)
    #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x17480c0)
    #31 <null> <null> (libstdc++.so.6+0xdcac2)
  ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:2033 in dw2_get_file_names_reader
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread writing the index cache, and in the process reading
  dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::files_read.

The two bitfields dwarf2_per_cu_data::files_read and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.

Fix this by making dwarf2_per_cu_data::files_read a packed<bool, 1>.

Tested on x86_64-linux.

PR symtab/30718
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
2023-08-04 15:05:57 +02:00
Tom de Vries
38ef7c3513 [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types}
With gdb build with -fsanitize=thread, and the exec from test-case
gdb.base/index-cache.exp, I run into:
...
$ rm -f ~/.cache/gdb/*; \
  gdb -q -batch -iex "set index-cache enabled on" index-cache \
    -ex "print foobar"
  ...
WARNING: ThreadSanitizer: data race (pid=23970)
  Write of size 1 at 0x7b200000410d by main thread:
    #0 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3077 (gdb+0x7ac54e)
    #1 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d039f)
    #2 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5aee)
    #3 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc439d)
    #4 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc44a2)
    #5 classify_name gdb/c-exp.y:3083 (gdb+0x61afec)
    #6 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13)
    #7 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e)
    #8 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864)
    #9 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x9771c5)
    #10 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10a9b)
    #11 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb110ae)
    #12 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf0c)
    #13 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4ca2a)
    #14 print_command gdb/printcmd.c:1468 (gdb+0xb4cd5a)
    #15 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078)
    #16 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53)
    #17 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a76a)
    #18 catch_command_errors gdb/main.c:518 (gdb+0xa1837d)
    #19 execute_cmdargs gdb/main.c:617 (gdb+0xa1853f)
    #20 captured_main_1 gdb/main.c:1289 (gdb+0xa1aa58)
    #21 captured_main gdb/main.c:1310 (gdb+0xa1b95a)
    #22 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b95a)
    #23 main gdb/gdb.c:39 (gdb+0x42506a)

  Previous read of size 1 at 0x7b200000410d by thread T1:
    #0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30)
    #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803)
    #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36)
    #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d)
    #4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d)
    #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d)
    #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c)
    #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db)
    #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db)
    #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db)
    #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db)
    #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db)
    #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954)
    #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954)
    #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a)
    #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a)
    #19 pthread_once <null> (libtsan.so.0+0x4457c)
    #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b)
    #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b)
    #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174568d)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174568d)
    #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174568d)
    #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174568d)
    #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1748040)
    #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1748040)
    #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1748040)
    #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1748040)
    #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1748040)
    #31 <null> <null> (libstdc++.so.6+0xdcac2)
  ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:3077 in dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>)
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread writing the index cache, and in the process reading
  dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::mark.

The two bitfields dwarf2_per_cu_data::mark and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.

Fix this by making dwarf2_per_cu_data::mark a packed<unsigned int, 1>.

Tested on x86_64-linux.

PR symtab/30718
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
2023-08-04 15:05:57 +02:00
Tom de Vries
edb157dfc6 [gdb/symtab] Fix data race on dwarf2_per_cu_data::{m_header_read_in,is_debug_type}
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp
and target board debug-types, I run into:
...
(gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
==================
WARNING: ThreadSanitizer: data race (pid=9654)
  Write of size 1 at 0x7b200000420d by main thread:
    #0 dwarf2_per_cu_data::get_header() const gdb/dwarf2/read.c:21513 (gdb+0x8d1eee)
    #1 dwarf2_per_cu_data::addr_size() const gdb/dwarf2/read.c:21524 (gdb+0x8d1f4e)
    #2 dwarf2_cu::addr_type() const gdb/dwarf2/cu.c:112 (gdb+0x806327)
    #3 set_die_type gdb/dwarf2/read.c:21932 (gdb+0x8d3870)
    #4 read_base_type gdb/dwarf2/read.c:15448 (gdb+0x8bcacb)
    #5 read_type_die_1 gdb/dwarf2/read.c:19832 (gdb+0x8cc0a5)
    #6 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
    #7 lookup_die_type gdb/dwarf2/read.c:19739 (gdb+0x8cbdc7)
    #8 die_type gdb/dwarf2/read.c:19593 (gdb+0x8cb68a)
    #9 read_subroutine_type gdb/dwarf2/read.c:14648 (gdb+0x8b998e)
    #10 read_type_die_1 gdb/dwarf2/read.c:19792 (gdb+0x8cbf2f)
    #11 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d)
    #12 read_func_scope gdb/dwarf2/read.c:10154 (gdb+0x8a4f36)
    #13 process_die gdb/dwarf2/read.c:6667 (gdb+0x898daa)
    #14 read_file_scope gdb/dwarf2/read.c:7682 (gdb+0x89bad8)
    #15 process_die gdb/dwarf2/read.c:6654 (gdb+0x898ced)
    #16 process_full_comp_unit gdb/dwarf2/read.c:6418 (gdb+0x8981de)
    #17 process_queue gdb/dwarf2/read.c:5690 (gdb+0x894433)
    #18 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1770 (gdb+0x88623a)
    #19 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x886300)
    #20 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88b1f1)
    #21 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16917 (gdb+0x8c228e)
    #22 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf39055)
    #23 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66ab7)
    #24 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf6711b)
    #25 operator() gdb/symtab.c:2562 (gdb+0xf67272)
    #26 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf776b1)
    #27 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77708)
    #28 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3fc97)
    #29 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xecae47)
    #30 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
    #31 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf674fb)
    #32 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf67780)
    #33 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf66d6e)
    #34 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf65cb3)
    #35 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf64dab)
    #36 set_initial_language() gdb/symfile.c:1708 (gdb+0xf43074)
    #37 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf41608)
    #38 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf42faf)
    #39 file_command gdb/exec.c:554 (gdb+0x94ff29)
    #40 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
    #41 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
    #42 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff379c)
    #43 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94b5bc)
    #44 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94bc79)
    #45 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x1034efc)
    #46 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94ab61)
    #47 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11be4ef)
    #48 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a960)
    #49 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94aa21)
    #50 stdin_event_handler gdb/ui.c:155 (gdb+0x10751a0)
    #51 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d95bac)
    #52 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d962e4)
    #53 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d946d0)
    #54 start_event_loop gdb/main.c:412 (gdb+0xb5ab52)
    #55 captured_command_loop gdb/main.c:476 (gdb+0xb5ad41)
    #56 captured_main gdb/main.c:1320 (gdb+0xb5cec1)
    #57 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5cf70)
    #58 main gdb/gdb.c:32 (gdb+0x416776)

  Previous read of size 1 at 0x7b200000420d by thread T11:
    #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x831630)
    #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x832897)
    #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x82db8d)
    #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:645 (gdb+0x7f1d49)
    #4 operator() gdb/dwarf2/cooked-index.c:474 (gdb+0x7f0f31)
    #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2a13)
    #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
    #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
    #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
    #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
    #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660)
    #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c)
    #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
    #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf)
    #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f)
    #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
    #19 pthread_once <null> (libtsan.so.0+0x4457c)
    #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
    #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224)
    #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
    #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dad25a)
    #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dacb7c)
    #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dadc2b)
    #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dad05c)
    #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1db038e)
    #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1db0319)
    #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1db02ce)
    #31 <null> <null> (libstdc++.so.6+0xdcac2)
  ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:21513 in dwarf2_per_cu_data::get_header() const
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread writing the index cache, and in the process reading
   dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::m_header_read_in.

The two bitfields dwarf2_per_cu_data::m_header_read_in and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.

Fix this by making dwarf2_per_cu_data::m_header_read_in a packed<bool, 1>.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30392
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
2023-08-04 15:02:43 +02:00
Tom de Vries
12afdeecc9 [gdb/symtab] Fix race on dwarf2_per_cu_data::{queued,is_debug_type}
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
run into:
...
(gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
==================
WARNING: ThreadSanitizer: data race (pid=24296)
  Write of size 1 at 0x7b200000420d by main thread:
    #0 queue_comp_unit gdb/dwarf2/read.c:5564 (gdb+0x8939ce)
    #1 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1754 (gdb+0x885b96)
    #2 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x885d86)
    #3 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88ac77)
    #4 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16915 (gdb+0x8c1c8a)
    #5 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf389a1)
    #6 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66403)
    #7 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf66a67)
    #8 operator() gdb/symtab.c:2562 (gdb+0xf66bbe)
    #9 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf76ffd)
    #10 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77054)
    #11 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3f5e3)
    #12 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xeca793)
    #13 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
    #14 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf66e47)
    #15 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf670cc)
    #16 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf666ba)
    #17 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf655ff)
    #18 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf646f7)
    #19 set_initial_language() gdb/symfile.c:1708 (gdb+0xf429c0)
    #20 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40f54)
    #21 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf428fb)
    #22 file_command gdb/exec.c:554 (gdb+0x94f875)
    #23 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
    #24 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
    #25 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff3166)
    #26 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94af08)
    #27 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b5c5)
    #28 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x10348c6)
    #29 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a4ad)
    #30 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdf87)
    #31 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a2ac)
    #32 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a36d)
    #33 stdin_event_handler gdb/ui.c:155 (gdb+0x1074b6a)
    #34 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d9502c)
    #35 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d95764)
    #36 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93b50)
    #37 start_event_loop gdb/main.c:412 (gdb+0xb5a49e)
    #38 captured_command_loop gdb/main.c:476 (gdb+0xb5a68d)
    #39 captured_main gdb/main.c:1320 (gdb+0xb5c80d)
    #40 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c8bc)
    #41 main gdb/gdb.c:32 (gdb+0x416776)

  Previous read of size 1 at 0x7b200000420d by thread T12:
    #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x8310c8)
    #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x83232f)
    #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:177 (gdb+0x82d62b)
    #3 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf7)
    #4 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40)
    #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2909)
    #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
    #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
    #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
    #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
    #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660)
    #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c)
    #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
    #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf)
    #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f)
    #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
    #19 pthread_once <null> (libtsan.so.0+0x4457c)
    #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
    #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224)
    #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852)
    #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
    #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac6da)
    #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabffc)
    #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dad0ab)
    #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac4dc)
    #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf80e)
    #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf799)
    #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf74e)
    #31 <null> <null> (libstdc++.so.6+0xdcac2)
 ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:5564 in queue_comp_unit
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread writing the index cache, and in the process reading
  dwarf2_per_cu_data::is_debug_type, and
- the main thread expanding the CU containing main, and in the process setting
  dwarf2_per_cu_data::queued.

The two bitfields dwarf2_per_cu_data::queue and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.

Fix this by making dwarf2_per_cu_data::queued a packed<bool, 1>.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30392
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
2023-08-04 15:02:43 +02:00
Tom de Vries
488b3ff1fc [gdb/symtab] Fix data race on bfd::{cacheable,format}
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
run into:
...
(gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
==================
WARNING: ThreadSanitizer: data race (pid=12261)
  Write of size 4 at 0x7b4400097d08 by main thread:
    #0 bfd_open_file bfd/cache.c:584 (gdb+0x148bb92)
    #1 bfd_cache_lookup_worker bfd/cache.c:261 (gdb+0x148b12a)
    #2 cache_bseek bfd/cache.c:289 (gdb+0x148b324)
    #3 bfd_seek bfd/bfdio.c:459 (gdb+0x1489c31)
    #4 _bfd_generic_get_section_contents bfd/libbfd.c:1069 (gdb+0x14977a4)
    #5 bfd_get_section_contents bfd/section.c:1606 (gdb+0x149cc7c)
    #6 gdb_bfd_scan_elf_dyntag(int, bfd*, unsigned long*, unsigned long*) gdb/solib.c:1601 (gdb+0xed8eca)
    #7 elf_locate_base gdb/solib-svr4.c:705 (gdb+0xec28ac)
    #8 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3430 (gdb+0xeca55d)
    #9 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad)
    #10 find_main_name gdb/symtab.c:6270 (gdb+0xf743a5)
    #11 main_language() gdb/symtab.c:6313 (gdb+0xf74499)
    #12 set_initial_language() gdb/symfile.c:1700 (gdb+0xf4285c)
    #13 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40e2a)
    #14 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf427d1)
    #15 file_command gdb/exec.c:554 (gdb+0x94f74b)
    #16 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528)
    #17 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69)
    #18 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff303c)
    #19 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94adde)
    #20 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b49b)
    #21 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103479c)
    #22 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a383)
    #23 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bde5d)
    #24 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a182)
    #25 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a243)
    #26 stdin_event_handler gdb/ui.c:155 (gdb+0x1074a40)
    #27 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94f02)
    #28 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9563a)
    #29 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93a26)
    #30 start_event_loop gdb/main.c:412 (gdb+0xb5a374)
    #31 captured_command_loop gdb/main.c:476 (gdb+0xb5a563)
    #32 captured_main gdb/main.c:1320 (gdb+0xb5c6e3)
    #33 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c792)
    #34 main gdb/gdb.c:32 (gdb+0x416776)

  Previous read of size 1 at 0x7b4400097d08 by thread T12:
    #0 bfd_check_format_matches bfd/format.c:323 (gdb+0x1492db4)
    #1 bfd_check_format bfd/format.c:94 (gdb+0x1492104)
    #2 build_id_bfd_get(bfd*) gdb/build-id.c:42 (gdb+0x6648f7)
    #3 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:110 (gdb+0x82d205)
    #4 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf1)
    #5 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40)
    #6 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f28f7)
    #7 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
    #8 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
    #9 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
    #10 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
    #11 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660)
    #12 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c)
    #13 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
    #14 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf)
    #15 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f)
    #16 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d)
    #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
    #19 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
    #20 pthread_once <null> (libtsan.so.0+0x4457c)
    #21 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
    #22 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224)
    #23 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852)
    #24 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
    #25 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac5b0)
    #26 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabed2)
    #27 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dacf81)
    #28 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac3b2)
    #29 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf6e4)
    #30 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf66f)
    #31 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf624)
    #32 <null> <null> (libstdc++.so.6+0xdcac2)
  ...
SUMMARY: ThreadSanitizer: data race bfd/cache.c:584 in bfd_open_file
...

The race happens when issuing the "file $exec" command.

The race is between:
- a worker thread getting the build id while writing the index cache, and in
  the process reading bfd::format, and
- the main thread calling find_main_name, and in the process setting
  bfd::cacheable.

The two bitfields bfd::cacheable and bfd::format share the same bitfield
container.

Fix this by capturing the build id in the main thread, and using the captured
value in the worker thread.

Likewise for the dwz build id, which likely suffers from the same issue.

While we're at it, also move the creation of the cache directory to
the index_cache_store_context constructor, to:
- make sure there's no race between subsequent file commands, and
- issue any related warning or error messages during the file command.

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR symtab/30392
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
2023-08-04 15:02:43 +02:00
Tom de Vries
8adc552228 [gdb/symtab] Fix data race on index_cache::m_enabled
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I
run into:
...
(gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache
Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache...
(gdb) show index-cache enabled
The index cache is off.
(gdb) PASS: gdb.base/index-cache.exp: test_basic_stuff: index-cache is disabled by default
set index-cache enabled on
==================
WARNING: ThreadSanitizer: data race (pid=32248)
  Write of size 1 at 0x00000321f540 by main thread:
    #0 index_cache::enable() gdb/dwarf2/index-cache.c:76 (gdb+0x82cfdd)
    #1 set_index_cache_enabled_command gdb/dwarf2/index-cache.c:270 (gdb+0x82d9af)
    #2 bool setting::set<bool>(bool const&) gdb/command.h:353 (gdb+0x6fe5f2)
    #3 do_set_command(char const*, int, cmd_list_element*) gdb/cli/cli-setshow.c:414 (gdb+0x6fcd21)
    #4 execute_command(char const*, int) gdb/top.c:567 (gdb+0xff2e64)
    #5 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94acc0)
    #6 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b37d)
    #7 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103467e)
    #8 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a265)
    #9 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdd3f)
    #10 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a064)
    #11 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a125)
    #12 stdin_event_handler gdb/ui.c:155 (gdb+0x1074922)
    #13 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94de4)
    #14 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9551c)
    #15 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93908)
    #16 start_event_loop gdb/main.c:412 (gdb+0xb5a256)
    #17 captured_command_loop gdb/main.c:476 (gdb+0xb5a445)
    #18 captured_main gdb/main.c:1320 (gdb+0xb5c5c5)
    #19 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c674)
    #20 main gdb/gdb.c:32 (gdb+0x416776)

  Previous read of size 1 at 0x00000321f540 by thread T12:
    #0 index_cache::enabled() const gdb/dwarf2/index-cache.h:48 (gdb+0x82e1a6)
    #1 index_cache::store(dwarf2_per_bfd*) gdb/dwarf2/index-cache.c:94 (gdb+0x82d0bc)
    #2 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:638 (gdb+0x7f1b97)
    #3 operator() gdb/dwarf2/cooked-index.c:468 (gdb+0x7f0f24)
    #4 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f285b)
    #5 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952)
    #6 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0)
    #7 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91)
    #8 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59)
    #9 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660)
    #10 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c)
    #11 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623)
    #12 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf)
    #13 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f)
    #14 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5)
    #15 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d)
    #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2)
    #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2)
    #18 pthread_once <null> (libtsan.so.0+0x4457c)
    #19 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd)
    #20 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224)
    #21 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852)
    #22 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef)
    #23 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac492)
    #24 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabdb4)
    #25 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dace63)
    #26 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac294)
    #27 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf5c6)
    #28 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf551)
    #29 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf506)
    #30 <null> <null> (libstdc++.so.6+0xdcac2)

  Location is global 'global_index_cache' of size 48 at 0x00000321f520 (gdb+0x00000321f540)
  ...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/index-cache.c:76 in index_cache::enable()
...

The race happens when issuing a "file $exec" command followed by a
"set index-cache enabled on" command.

The race is between:
- a worker thread reading index_cache::m_enabled to determine whether an
  index-cache entry for $exec needs to be written
  (due to command "file $exec"), and
- the main thread setting index_cache::m_enabled
  (due to command "set index-cache enabled on").

Fix this by capturing the value of index_cache::m_enabled in the main thread,
and using the captured value in the worker thread.

Tested on x86_64-linux.

PR symtab/30392
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
2023-08-04 15:02:43 +02:00
Tom de Vries
8d76ceb7f1 [gdb/symtab] Remove superfluous handling of Ada main in write_cooked_index
I filed PR29179 about the following FAIL in test-case
gdb.ada/O2_float_param.exp with target board cc-with-gdb-index:
...
(gdb) break increment^M
Function "increment" not defined.^M
Make breakpoint pending on future shared library load? (y or [n]) n^M
(gdb) FAIL: gdb.ada/O2_float_param.exp: scenario=all: gdb_breakpoint: \
  set breakpoint at increment
...

The FAIL was a regression since commit 2cf349be0e ("Do not put linkage names
into .gdb_index").

Before that commit we had:
...
$ readelf -w foo > READELF
$ grep callee.*increment READELF
[1568] callee__increment: 5 [global, function]
[3115] callee.increment: 5 [global, function]
...
but after only:
...
$ grep callee.*increment READELF
[3115] callee.increment: 5 [global, function]
...

The regression was fixed by commit 67e83a0dee ("Fix regression in
c-linkage-name.exp with gdb index"), which got us again:
...
$ grep callee.*increment READELF
[1568] callee__increment: 5 [global, function]
[3115] callee.increment: 5 [global, function]
...

The commit however did not claim that particular PR.  A subsequent commit,
commit 5fea979432 ("Improve Ada support in .gdb_index") did claim to fix it,
together with commit dd05fc7071 ("Change .gdb_index de-duplication
implementation").

The commit 5fea979432 contained the following addition in write_cooked_index:
...
+      if (entry->per_cu->lang () == language_ada)
+	{
+	  /* We want to ensure that the Ada main function's name
+	     appears verbatim in the index.  However, this name will
+	     be of the form "_ada_mumble", and will be rewritten by
+	     ada_decode.  So, recognize it specially here and add it
+	     to the index by hand.  */
+	  if (entry->tag == DW_TAG_subprogram
+	      && strcmp (main_for_ada, name) == 0)
+	    {
+	      /* Leave it alone.  */
+	    }
+	  else
+	    {
+	      /* In order for the index to work when read back into
+		 gdb, it has to use the encoded name, with any
+		 suffixes stripped.  */
+	      std::string encoded = ada_encode (name, false);
+	      name = obstack_strdup (&symtab->m_string_obstack,
+				     encoded.c_str ());
+	    }
+	}
...

The code contains some special handling related to the Ada main function, so
let's look at that one: foo.  Before commit 67e83a0dee we have:
...
$ grep foo.*function READELF
[3733] foo: 7 [global, function]
...
and after:
...
$ grep foo.*function READELF
[2738] _ada_foo: 7 [global, function]
[3733] foo: 7 [global, function]
...
so that looks identical to the callee.increment case.

At commit 5fea979432, we have slightly different index numbers:
...
$ grep foo.*function READELF
[1658] foo: 7 [global, function]
[2738] _ada_foo: 7 [global, function]
...
but otherwise the same result.

If we disable the special handling of the Ada main function like so:
...
-	  if (entry->tag == DW_TAG_subprogram
+	  if (false && entry->tag == DW_TAG_subprogram
...
we still have the exact same result because:
...
(gdb) p main_for_ada
$1 = 0x352e6a0 "_ada_foo"
...
and ada_encode ("_ada_foo", false) == "_ada_foo".

The comment seems to be copied from debug_names::insert, which does indeed use
ada_decode, while the code in write_cooked_index uses ada_encode instead.

Remove the superfluous special handling of Ada main in write_cooked_index.

Tested on x86_64-linux, with target boards unix and cc-with-gdb-index.

Approved-By: Tom Tromey <tom@tromey.com>
2023-08-03 18:35:23 +02:00
Tom Tromey
fe34aba060 Fix bug in fixed-point handling
Alexandre Oliva found a bug in gdb's handling of fixed-point -- a
certain Ada fixed-point type would be misintepreted.  The bug was that
the DW_AT_small looked like:

 <1><13cd>: Abbrev Number: 16 (DW_TAG_constant)
    <13ce>   DW_AT_GNU_numerator: 1
    <13cf>   DW_AT_GNU_denominator: 0x8000000000000000

... but gdb interpreted the denominator as a negative value.
2023-07-31 10:48:00 -06:00
Tom Tromey
4d051f3a4e Fix crash with DW_FORM_implicit_const
Jakub pointed out that using DW_FORM_implicit_const with
DW_AT_bit_size would cause gdb to crash.  This happened because
DW_FORM_implicit_const is not an "unsigned" form, causing as_unsigned
to assert.  This patch fixes the problem.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30651
Approved-By: Andrew Burgess <aburgess@redhat.com>
2023-07-21 14:03:23 -06:00
Tom de Vries
f4c4456eb4 [gdb/symtab] Add optimized out static var to cooked index
Consider the test-case:
...
$ cat main.c
int main (void) { return 0; }
$ cat static-optimized-out.c
static int aaa;
...
compiled like this:
...
$ gcc-12 static-optimized-out.c main.c -g -O2 -flto
...

There's a difference in behaviour depending on symtab expansion state:
...
$ gdb -q -batch a.out -ex "print aaa"
No symbol "aaa" in current context.
$ gdb -q -batch a.out -ex "maint expand-symtab" -ex "print aaa"
$1 = <optimized out>
...

The reason for the difference is that the optimized out variable aaa:
...
 <1><104>: Abbrev Number: 2 (DW_TAG_variable)
    <105>   DW_AT_name        : aaa
    <109>   DW_AT_decl_file   : 1
    <10a>   DW_AT_decl_line   : 18
    <10b>   DW_AT_decl_column : 12
    <10c>   DW_AT_type        : <0x110>
...
is not added to the cooked index because of this clause in abbrev_table::read:
...
     else if (!has_location && !has_specification_or_origin && !has_external
	       && cur_abbrev->tag == DW_TAG_variable)
	cur_abbrev->interesting = false;
...

Fix this inconsistency by making sure that the optimized out variable is added
to the cooked index.

Regression tested on x86_64-linux.

Add two test-cases, a C test-case gdb.opt/static-optimized-out.exp and a dwarf
assembly test-case gdb.dwarf2/static-optimized-out.exp.

Tested gdb.opt/static-optimized-out.exp with gcc-8 to gcc-12, for which we now
consistently get:
...
(gdb) print aaa^M
$1 = <optimized out>^M
...
and with gcc 7.5.0 and clang 13.0.1, for which we still consistently get:
...
(gdb) print aaa^M
No symbol "aaa" in current context.^M
...
due to missing debug info for the variable.

PR symtab/30656
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30656

Approved-By: Tom Tromey <tom@tromey.com>
2023-07-21 08:25:25 +02:00
Tom Tromey
6e27b5eb00 Fix handling of DW_TAG_unspecified_type for Ada
Commit 80eaec735e ("[gdb/symtab] Handle named DW_TAG_unspecified_type
DIE") changed the handling of DW_TAG_unspecified_type.  Before this
change, such types were not entered into the symbol table.

It turns out that, when such a type is in the symtab, it can cause
failures in Ada.  In particular, a private type in another package may
be seen locally as "void".

Now, it would probably be better to fix this via check_typedef.
However, that is somewhat difficult given the state of the DWARF
reader -- in particular with gdb_index, this would require expanding
potentially many CUs to find the correct type.

Instead, this patch changes gdb to not enter a symbol for an
unspecified type -- but only for Ada.
2023-06-28 09:49:22 -06:00
Tom Tromey
6f96f4854f Use gdb::byte_vector in agent_expr
This changes agent_expr to use gdb::byte_vector rather than manually
reimplementing a vector.

Reviewed-by: John Baldwin <jhb@FreeBSD.org>
2023-06-20 11:00:19 -06:00
Kevin Buettner
f3741bbd18 Simplify case DW_OP_GNU_uninit in dwarf_expr_context::execute_stack_op
Tom Tromey pointed out that the test and call to error() for the
DW_OP_GNU_uninit case in dwarf_expr_context::execute_stack_op (in
gdb/dwarf2/expr.c)...

	  if (op_ptr != op_end && *op_ptr != DW_OP_piece
	      && *op_ptr != DW_OP_bit_piece)
	    error (_("DWARF-2 expression error: DW_OP_GNU_uninit must always "
		   "be the very last op in a DWARF expression or "
		   "DW_OP_piece/DW_OP_bit_piece piece."));

...could be replaced by a call to dwarf_expr_require_composition which
performs a similar check and outputs a suitable error message.
2023-06-12 16:02:40 -07:00
Kevin Buettner
d65befc152 Permit DW_OP_GNU_uninit to be used with DW_OP_piece
This commit implements a fix for a bug reported against GDB on
Fedora bugzilla...

https://bugzilla.redhat.com/show_bug.cgi?id=2166796

The test case in that bug report involved running gdb against the 'jq'
program (which is a command-line JSON processor) on Fedora 37.  Since
the debug info is compiler (and compile-time option) dependent, it
won't necessarily show up in other distributions or even past or
future versions of Fedora.  (E.g. when trying the example shown below
on Fedora 38, GDB says that the value of 'value' has been optimized
out.  I.e. it does not demonstrate the same DWARF error that can be
see when using Fedora 37.)

That said, on Fedora 37, the bug could be reproduced as follows:

[kev@f37-1 ~]$ gdb jq -q -ex 'b src/util.c:415' -ex 'r </dev/null'
Reading symbols from jq...

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Reading symbols from /home/kev/.cache/debuginfod_client/9d3c8b4197350a190a74972d481de32abf641aa4/debuginfo...
No source file named src/util.c.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (src/util.c:415) pending.
Starting program: /usr/bin/jq </dev/null
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, jq_util_input_next_input (state=0x55555555d7f0) at src/util.c:416
416	    if (state->parser == NULL) {
(gdb) p value
DWARF-2 expression error: DW_OP_GNU_uninit must always be the very last op.

This is undesirable - rather than output an error about the DWARF
info, we'd prefer to see a value, even if it is uninitialized.

Examination of the debuginfo showed the following:

 <1><468f1>: Abbrev Number: 112 (DW_TAG_subprogram)
    <468f2>   DW_AT_external    : 1
    <468f2>   DW_AT_name        : (indirect string, offset: 0x4781): jq_util_input_next_input
    <468f6>   DW_AT_decl_file   : 10
    <468f6>   DW_AT_decl_line   : 411
    <468f8>   DW_AT_decl_column : 4
    <468f9>   DW_AT_prototyped  : 1
    <468f9>   DW_AT_type        : <0x3f2>
    <468fd>   DW_AT_sibling     : <0x4692e>
...
 <2><46921>: Abbrev Number: 102 (DW_TAG_variable)
    <46922>   DW_AT_name        : (indirect string, offset: 0x8cb): value
    <46926>   DW_AT_decl_file   : 10
    <46926>   DW_AT_decl_line   : 414
    <46928>   DW_AT_decl_column : 6
    <46929>   DW_AT_type        : <0x3f2>

Note that there's no DW_AT_location, so I looked for an abstract origin entry:

 <2><2dfa0>: Abbrev Number: 90 (DW_TAG_variable)
    <2dfa1>   DW_AT_abstract_origin: <0x46921>
    <2dfa5>   DW_AT_location    : 0x27cf1 (location list)
    <2dfa9>   DW_AT_GNU_locviews: 0x27ce1

(Note that the DW_AT_abstract_origin attribute's value is 0x46921 which
is the DIE for the local variable "value".)

Looking at the location list, I see:

    00027cf1 v000000000000000 v000000000000000 views at 00027ce1 for:
             000000000002f8fe 000000000002f92e (DW_OP_reg13 (r13); DW_OP_GNU_uninit; DW_OP_piece: 8; DW_OP_reg12 (r12); DW_OP_GNU_uninit; DW_OP_piece: 8)

While DW_OP_GNU_uninit is not the very last op, it is the last op
prior to DW_OP_piece.  The fix involved changing the DW_OP_GNU_uninit
case in dwarf_expr_context::execute_stack_op in gdb/dwarf2/expr.c so
that DW_OP_GNU_uninit may appear just before DW_OP_piece.

With the fix in place, attempting to print 'value' now looks like
this:

(gdb) p value
$1 =  [uninitialized] {kind_flags = 0 '\000', pad_ = 0 '\000', offset = 0,
  size = 0, u = {ptr = 0x0, number = 0}}

Note that "[uninitialized]" is part of the output.  (But also note
that there's an extra space character.)

I've made a new test case,
gdb.dwarf2/DW_OP_piece_with_DW_OP_GNU_uninit.exp, by adapting an
existing one, gdb.dwarf2/opt-out-not-implptr.exp.  Since it uses the
DWARF assembler, the test case does not depend on a specific compiler
version or compiler options.

Tested on Fedora 37 and Fedora 38.
2023-06-11 15:41:42 -07:00
Tom Tromey
d0516c8e66 Use unrelocated_addr in dwarf2_fde
This changes dwarf2_fde to use the unrelocated_addr type.  This
pointed out a latent bug in dwarf2_frame_cache, where a relocated
address is compared to an unrelocated address.
2023-06-05 09:59:18 -06:00