Bug 32081 - Crash in cooked_indexer::scan_attributes
Summary: Crash in cooked_indexer::scan_attributes
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: 14.1
: P2 normal
Target Milestone: 16.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: 29366
  Show dependency treegraph
 
Reported: 2024-08-13 19:41 UTC by Andreas Schwab
Modified: 2024-08-22 08:00 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Demonstrator patch with dwarf assembly test-case (1.49 KB, patch)
2024-08-15 06:51 UTC, Tom de Vries
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas Schwab 2024-08-13 19:41:38 UTC
peek_die_abbrev can return NULL, but scan_attributes cannot cope.

	  unsigned int bytes_read;
	  const abbrev_info *new_abbrev = peek_die_abbrev (*new_reader,
							   new_info_ptr,
							   &bytes_read);
	  new_info_ptr += bytes_read;

	  if (new_reader->cu == reader->cu && new_info_ptr == watermark_ptr)
	    {
	      /* Self-reference, we're done.  */
	    }
	  else
	    scan_attributes (scanning_per_cu, new_reader, new_info_ptr,
			     new_info_ptr, new_abbrev, name, linkage_name,
			     flags, nullptr, parent_entry, maybe_defer, true);

#4  0x0000002aafcc7862 in handle_sigsegv (sig=11) at ../../gdb/event-top.c:968
#5  <signal handler called>
#6  0x0000002aafcaedbe in cooked_indexer::scan_attributes (
    this=this@entry=0x3fd63fd218, 
    scanning_per_cu=scanning_per_cu@entry=0x2ad6fe83e0, 
    reader=reader@entry=0x2ad859ccd0, watermark_ptr=0x3f693b3a09 "G\325!", 
    info_ptr=0x3f693b3a09 "G\325!", abbrev=0x0, name=name@entry=0x3fd63fce90, 
    linkage_name=linkage_name@entry=0x3fd63fce88, 
    flags=flags@entry=0x3fd63fce68, sibling_offset=sibling_offset@entry=0x0, 
    parent_entry=parent_entry@entry=0x3fd63fce70, 
    maybe_defer=maybe_defer@entry=0x3fd63fce80, 
    for_specification=for_specification@entry=true)
    at ../../gdb/dwarf2/read.c:16330
#7  0x0000002aafcaf320 in cooked_indexer::scan_attributes (
    this=this@entry=0x3fd63fd218, 
    scanning_per_cu=scanning_per_cu@entry=0x2ad6fe83e0, 
    reader=reader@entry=0x2ad859ccd0, 
    watermark_ptr=0x3f693a88cf "\365ً\005&\231v\006T\004\004'z\001\001\005\202\002\2302;\020\003\367\004\002%.", 
    info_ptr=0x3f693a88d4 "\231v\006T\004\004'z\001\001\005\202\002\2302;\020\003\367\004\002%.", abbrev=0x2ad71f6530, name=name@entry=0x3fd63fce90, 
    linkage_name=linkage_name@entry=0x3fd63fce88, 
    flags=flags@entry=0x3fd63fce68, sibling_offset=sibling_offset@entry=0x0, 
    parent_entry=parent_entry@entry=0x3fd63fce70, 
    maybe_defer=maybe_defer@entry=0x3fd63fce80, 
    for_specification=for_specification@entry=true)
    at ../../gdb/dwarf2/read.c:16546
#8  0x0000002aafcaf320 in cooked_indexer::scan_attributes (
    this=this@entry=0x3fd63fd218, 
    scanning_per_cu=scanning_per_cu@entry=0x2ad6fe83e0, 
    reader=reader@entry=0x2ad859ccd0, 
    watermark_ptr=0x3f693b3a32 "\002\345\001څ:\020\0018\005Eg\213\a]\274:\020\021\"\320y\a\002\346\001\2302;\020\021\241\025\210\006\002\346\001\362D:\020\021Z\r\213\a\002\346\001%.", 
    info_ptr=0x3f693b3a3b "\005Eg\213\a]\274:\020\021\"\320y\a\002\346\001\2302;\020\021\241\025\210\006\002\346\001\362D:\020\021Z\r\213\a\002\346\001%.", 
    abbrev=0x2ad71f68c0, name=name@entry=0x3fd63fce90, 
    linkage_name=linkage_name@entry=0x3fd63fce88, 
    flags=flags@entry=0x3fd63fce68, sibling_offset=sibling_offset@entry=0x0, 
    parent_entry=parent_entry@entry=0x3fd63fce70, 
    maybe_defer=maybe_defer@entry=0x3fd63fce80, 
--Type <RET> for more, q to quit, c to continue without paging--c
    for_specification=for_specification@entry=true)
    at ../../gdb/dwarf2/read.c:16546
#9  0x0000002aafcaf320 in cooked_indexer::scan_attributes (
    this=this@entry=0x3fd63fd218, scanning_per_cu=0x2ad6fe83e0, 
    reader=reader@entry=0x3fd63fd278, 
    watermark_ptr=0x3f693ad804 "=7;\020P%\204\002", 
    info_ptr=0x3f693ad814 "\024_", abbrev=abbrev@entry=0x2ad85136a0, 
    name=name@entry=0x3fd63fce90, 
    linkage_name=linkage_name@entry=0x3fd63fce88, 
    flags=flags@entry=0x3fd63fce68, 
    sibling_offset=sibling_offset@entry=0x3fd63fce78, 
    parent_entry=parent_entry@entry=0x3fd63fce70, 
    maybe_defer=maybe_defer@entry=0x3fd63fce80, 
    for_specification=for_specification@entry=false)
    at ../../gdb/dwarf2/read.c:16546
#10 0x0000002aafcaf828 in cooked_indexer::index_dies (
    this=this@entry=0x3fd63fd218, reader=reader@entry=0x3fd63fd278, 
    info_ptr=<optimized out>, 
    info_ptr@entry=0x3f693aca21 "Y\354\353S\tEg\213\aͤuX\354S\t:9y\003\002]\2240\204\001\002\221(\346\371{\003\002\201~GU\261\354S\t7Hx\003\002^\200{U\344\354S\t\253\351\224\a\002_\216}_*\355S\t}\335|\003\002`x'\016", 
    parent_entry=parent_entry@entry=0x2ad8594850, fully=true)
    at ../../gdb/dwarf2/read.c:16709
#11 0x0000002aafcaffd0 in cooked_indexer::recurse (
    this=this@entry=0x3fd63fd218, reader=reader@entry=0x3fd63fd278, 
    info_ptr=info_ptr@entry=0x3f693aca21 "Y\354\353S\tEg\213\aͤuX\354S\t:9y\003\002]\2240\204\001\002\221(\346\371{\003\002\201~GU\261\354S\t7Hx\003\002^\200{U\344\354S\t\253\351\224\a\002_\216}_*\355S\t}\335|\003\002`x'\016", 
    parent_entry=parent_entry@entry=0x2ad8594850, fully=<optimized out>)
    at ../../gdb/dwarf2/read.c:16644
#12 0x0000002aafcafba6 in cooked_indexer::index_dies (this=<optimized out>, 
    reader=0x3fd63fd278, 
    info_ptr=0x3f693aca21 "Y\354\353S\tEg\213\aͤuX\354S\t:9y\003\002]\2240\204\001\002\221(\346\371{\003\002\201~GU\261\354S\t7Hx\003\002^\200{U\344\354S\t\253\351\224\a\002_\216}_*\355S\t}\335|\003\002`x'\016", parent_entry=0x0, 
    fully=false) at ../../gdb/dwarf2/read.c:16813
#13 0x0000002aafc97db2 in process_psymtab_comp_unit (storage=0x3fd63fd1f0, 
    per_objfile=<optimized out>, this_cu=0x2ad6fe83e0)
    at ../../gdb/dwarf2/read.c:4904
#14 operator() (__closure=0x3fd63fd3e0, iter=..., 
    end=std::unique_ptr<dwarf2_per_cu_data> = {...})
    at ../../gdb/dwarf2/read.c:5197
#15 0x0000002ab014ad64 in operator() (__closure=0x3fd63fd3e0)
    at ../../gdb/../gdbsupport/parallel-for.h:298
#16 operator() (ecall=..., __closure=0x0)
    at ../../gdb/../gdbsupport/function-view.h:305
#17 _FUN () at ../../gdb/../gdbsupport/function-view.h:299
#18 gdb::function_view<std::pair<std::unique_ptr<cooked_index_shard, std::default_delete<cooked_index_shard> >, std::vector<gdb_exception, std::allocator<gdb_exception> > > ()>::operator()() const (this=<synthetic pointer>)
    at ../../gdb/../gdbsupport/function-view.h:289
#19 gdb::detail::par_for_accumulator<std::pair<std::unique_ptr<cooked_index_shard, std::default_delete<cooked_index_shard> >, std::vector<gdb_exception, std::allocator<gdb_exception> > > >::finish(gdb::function_view<std::pair<std::unique_ptr<cooked_index_shard, std::default_delete<cooked_index_shard> >, std::vector<gdb_exception, std::allocator<gdb_exception> > > ()>) (task=..., 
    this=<synthetic pointer>) at ../../gdb/../gdbsupport/parallel-for.h:65
#20 gdb::parallel_for_each<__gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, dwarf2_build_psymtabs_hard(dwarf2_per_objfile*)::{lambda(__gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >)#1}>(unsigned int, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, dwarf2_build_psymtabs_hard(dwarf2_per_objfile*)::{lambda(__gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >, __gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >)#1}, gdb::function_view<unsigned long (__gnu_cxx::__normal_iterator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>*, std::vector<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter>, std::allocator<std::unique_ptr<dwarf2_per_cu_data, dwarf2_per_cu_data_deleter> > > >)>) [clone .constprop.0] (first=..., 
    last=std::unique_ptr<dwarf2_per_cu_data> = {...}, callback=..., 
    callback@entry=..., task_size=..., n=1)
    at ../../gdb/../gdbsupport/parallel-for.h:299
#21 0x0000002aafc989a2 in dwarf2_build_psymtabs_hard (per_objfile=0x2ad7438350)
    at ../../gdb/dwarf2/read.c:5185
#22 0x0000002aafcb014e in dwarf2_build_psymtabs (objfile=0x2ad60d4c00)
    at ../../gdb/dwarf2/read.c:3464
#23 cooked_index_functions::read_partial_symbols (this=<optimized out>, 
    objfile=0x2ad60d4c00) at ../../gdb/dwarf2/read.c:16907
#24 0x0000002aaff4ee3a in objfile::require_partial_symbols (
    this=this@entry=0x2ad60d4c00, verbose=verbose@entry=false)
    at ../../gdb/symfile-debug.c:551
#25 0x0000002aaff558c8 in read_symbols (objfile=objfile@entry=0x2ad60d4c00, 
    add_flags=..., add_flags@entry=...) at ../../gdb/symfile.c:794
#26 0x0000002aaff551a0 in syms_from_objfile_1 (add_flags=..., 
    addrs=0x3fd63fd950, objfile=0x2ad60d4c00) at ../../gdb/symfile.c:966
#27 syms_from_objfile (add_flags=..., addrs=0x3fd63fd7e0, objfile=0x2ad60d4c00)
    at ../../gdb/symfile.c:983
#28 symbol_file_add_with_addrs (abfd=..., 
    name=name@entry=0x3f90382f80 "/usr/lib/debug/usr/lib64/libLLVM.so.18.1.debug", add_flags=add_flags@entry=..., addrs=addrs@entry=0x3fd63fd950, flags=..., 
    parent=parent@entry=0x2ad5e1c4e0) at ../../gdb/symfile.c:1086
#29 0x0000002aaff557d0 in symbol_file_add_separate (bfd=..., 
    name=0x3f90382f80 "/usr/lib/debug/usr/lib64/libLLVM.so.18.1.debug", 
    symfile_flags=..., objfile=0x2ad5e1c4e0) at ../../gdb/symfile.c:1145
#30 0x0000002aafcc2e1e in elf_symfile_read_dwarf2 (symfile_flags=..., 
    objfile=0x2ad5e1c4e0) at ../../gdb/elfread.c:1237
#31 elf_symfile_read (objfile=0x2ad5e1c4e0, symfile_flags=...)
    at ../../gdb/elfread.c:1369
#32 0x0000002aaff55870 in read_symbols (objfile=objfile@entry=0x2ad5e1c4e0, 
    add_flags=add_flags@entry=...) at ../../gdb/symfile.c:772
#33 0x0000002aaff551a0 in syms_from_objfile_1 (add_flags=..., 
    addrs=0x3fd63fdd30, objfile=0x2ad5e1c4e0) at ../../gdb/symfile.c:966
#34 syms_from_objfile (add_flags=..., addrs=<optimized out>, 
    objfile=0x2ad5e1c4e0) at ../../gdb/symfile.c:983
#35 symbol_file_add_with_addrs (abfd=..., 
    name=0x2ad4cc13f0 "/lib64/lp64d/libLLVM.so.18.1", add_flags=..., 
    addrs=<optimized out>, flags=..., parent=<optimized out>)
    at ../../gdb/symfile.c:1086
#36 0x0000002aaff1c4de in symbol_file_add_from_bfd (parent=0x0, flags=..., 
    addrs=0x3fd63fdd30, add_flags=..., 
    name=0x2ad4cc13f0 "/lib64/lp64d/libLLVM.so.18.1", abfd=...)
    at ../../gdb/solib.c:721
#37 solib_read_symbols (so=so@entry=0x2ad4cc11e0, flags=flags@entry=...)
    at ../../gdb/solib.c:721
#38 0x0000002aaff1fd36 in solib_add (pattern=0x0, from_tty=0, readsyms=1)
    at ../../gdb/solib.c:1048
#39 0x0000002aafd56c00 in post_create_inferior (from_tty=1)
    at ../../gdb/infcmd.c:291
#40 0x0000002aafc3673a in core_target_open (
    arg=<error reading variable: value has been optimized out>, 
    from_tty=<error reading variable: value has been optimized out>)
    at ../../gdb/corelow.c:737
#41 0x0000002aafdc8740 in catch_command_errors (command=<optimized out>, 
    arg=<optimized out>, from_tty=<optimized out>, do_bp_actions=false)
    at ../../gdb/main.c:513
#42 0x0000002ab0169902 in captured_main_1(captured_main_args*) [clone .constprop.0] (context=context@entry=0x3fd63fe550) at ../../gdb/main.c:1226
#43 0x0000002aafaf8206 in captured_main (data=0x3fd63fe550)
    at ../../gdb/gdb.c:39
#44 gdb_main (args=0x3fd63fe550) at ../../gdb/main.c:1343
#45 main (argc=4, argv=0x3fd63fe728) at ../../gdb/gdb.c:39
Comment 1 Tom de Vries 2024-08-14 06:39:02 UTC
Can you provide a download link for the debug package /usr/lib/debug/usr/lib64/libLLVM.so.18.1.debug that can be used to reproduce the problem ?
Comment 3 Hannes Domani 2024-08-14 09:27:32 UTC
I think this is the same issue as PR31478.
Comment 4 Andreas Schwab 2024-08-14 09:41:41 UTC
But the debuginfo file is fully intact.
Comment 5 Tom de Vries 2024-08-14 10:01:39 UTC
Reproduced on openSUSE Tumbleweed x86_64 with gdb 14.2 based system gdb.

Reproduced on openSUSE Leap 15.5 x86_64 with O0 build from sources from aforementioned system gdb.

Didn't reproduce with similar build from gdb 14.2 sources.
Comment 6 Tom de Vries 2024-08-14 11:21:34 UTC
Using this patch:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 8f2d7a34aef..afcb78e7b17 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -5199,6 +5199,8 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
 	      }
 	    catch (gdb_exception &except)
 	      {
+		if (gdb::thread_pool::g_thread_pool->thread_count () == 0)
+		  throw;
 		errors.push_back (std::move (except));
 	      }
 	  }
...
I get this instead of a crash:
...
$ gdb -q -iex "maint set worker-threads 0" -batch ./usr/lib/debug/usr/lib64/libLLVM.so.18.1.debug
DW_FORM_strp pointing outside of .debug_str section [in module /data/vries/gdb/usr/lib/debug/usr/lib64/libLLVM.so.18.1.debug]
...

The problem is that we're trying to read string offset 0x8819e807 while reading an attribute at 0x624cc2.

Using readelf, we can see the context:
...
 <3><624cbe>: Abbrev Number: 29 (DW_TAG_subprogram)
    <624cbf>   DW_AT_linkage_name: (indirect string, offset: 0x745c691): _ZNK4llvm9StringRef17find_first_not_ofES0_m
    <624cc3>   DW_AT_name        : (indirect string, offset: 0x68819e8): find_first_not_of
...

The attribute is actually at 624cc3, so we're one byte off, and consequently the string offset is wrong (though containing 3 of correct bytes at the wrong location).

That can be explained by the fact that the first attribute is DW_FORM_ref_udata instead of DW_FORM_strp:
...
(gdb) p abbrev->attrs[0]
$28 = {name = DW_AT_type, form = DW_FORM_ref_udata, implicit_const = -1}
(gdb) p abbrev->attrs[1]
$29 = {name = DW_AT_name, form = DW_FORM_strp, implicit_const = -1}
...

In fact, the used abbrev is wrong:
...
(gdb) p *abbrev
$27 = {number = 29, tag = DW_TAG_typedef, has_children = false, interesting = true, size_if_constant = 0, 
  sibling_offset = 65535, num_attrs = 4, attrs = {{name = DW_AT_type, form = DW_FORM_ref_udata, 
      implicit_const = -1}}}
...
it's a DW_TAG_typedef instead of a DW_TAG_subprogram.

Both have the same abbrev number though: 29.

So, the problem seems to be that gdb is using the abbrev table from a different CU than intended.
Comment 7 Tom de Vries 2024-08-14 13:46:02 UTC
This is the relevant part of the debug info:
...
Compilation Unit @ offset 0x61f6a8:
Abbrev Offset: 0x11c3c

 <4><620ac8>: Abbrev Number: 37 (DW_TAG_inlined_subroutine)
    <620ac9>   DW_AT_abstract_origin: <0x638578>

 <3><624cbe>: Abbrev Number: 29 (DW_TAG_subprogram)

Compilation Unit @ offset 0x63648b:
Abbrev Offset: 0x12640

Compilation Unit @ offset 0x637b59:
Abbrev Offset: 0x30afaa

Compilation Unit @ offset 0x638332:
Abbrev Offset: 0x2079

 <1><638578>: Abbrev Number: 68 (DW_TAG_subprogram)
    <638580>   DW_AT_specification: <0x624cbe>

Compilation Unit @ offset 0x6386a7:
Abbrev Offset: 0x3ac1c
...

The following happens:
- gdb comes across DIE 0x620ac8 (in CU@0x61f6a8), 
- follows a reference to DIE 0x638578 (in CU@0x638332), and from there
- follows a reference to DIE 0x624cbe (back in CU@0x61f6a8).

GDB uses a cutu reader for each of these 3 levels.

It creates a cutu reader for the top level, and then uses cooked_indexer::ensure_cu_exists for the following 2 levels.

For the 3rd level, this bit in cooked_indexer::ensure_cu_exists triggers:
...
  if (per_cu == m_per_cu)
    return reader;
...
and it reuses the reader from level two, which points to CU@0x638332, which uses abbrev offset 0x2079 while the CU that is required is CU@0x61f6a8 with abbrev offset 0x11c3c.

Indeed the correct abbrev number 29 we find at 0x11c3c:
...
   29      DW_TAG_subprogram    [has children]
...
while the incorrect abbrev number 29 is found at 0x2079:
...
   29      DW_TAG_typedef    [no children]
...
Comment 8 Tom de Vries 2024-08-14 14:02:18 UTC
This fixes it (though this may be too severe for an actual fix):
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index eb7c93357c4..32690f66b9b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -16282,8 +16282,6 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader,
       if (!per_cu->scanned.compare_exchange_strong (nope, true))
 	return nullptr;
     }
-  if (per_cu == m_per_cu)
-    return reader;
 
   cutu_reader *result = m_index_storage->get_reader (per_cu);
   if (result == nullptr)
...
Comment 9 Tom de Vries 2024-08-14 14:24:38 UTC
(In reply to Hannes Domani from comment #3)
> I think this is the same issue as PR31478.

AFAIU PR31478 is triggered indeed, but there's a different root cause.

In the case of PR31478, there's incorrect debug info.

In this case, gdb reads correct debug info incorrectly, which then looks like incorrect debug info to gdb, which triggers PR31478.
Comment 10 Tom de Vries 2024-08-15 06:51:13 UTC
Created attachment 15668 [details]
Demonstrator patch with dwarf assembly test-case

Reproduced on trunk with dwarf assembly test-case.
Comment 11 Tom de Vries 2024-08-15 09:20:43 UTC
(In reply to Tom de Vries from comment #8)
> This fixes it (though this may be too severe for an actual fix):
> ...
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index eb7c93357c4..32690f66b9b 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -16282,8 +16282,6 @@ cooked_indexer::ensure_cu_exists (cutu_reader
> *reader,
>        if (!per_cu->scanned.compare_exchange_strong (nope, true))
>  	return nullptr;
>      }
> -  if (per_cu == m_per_cu)
> -    return reader;
>  
>    cutu_reader *result = m_index_storage->get_reader (per_cu);
>    if (result == nullptr)
> ...

I think I now understand what that code is trying to do.

If we remove that code, a reader is created for m_per_cu which is a duplicate of the reader that is passed as argument to make_index.

I'm currently testing a fix that avoids that.
Comment 13 Sourceware Commits 2024-08-22 07:59:38 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=573d8bb08bfff4638405add40a6a61868af1f2a4

commit 573d8bb08bfff4638405add40a6a61868af1f2a4
Author: Tom de Vries <tdevries@suse.de>
Date:   Thu Aug 22 10:00:27 2024 +0200

    [gdb/symtab] Return correct reader for top-level CU in cooked_indexer::ensure_cu_exists
    
    With the test-case included in this patch, we run into:
    ...
    $ gdb -q -batch $exec
    Dwarf Error: Could not find abbrev number 3 in CU at offset 0xdb \
      [in module $exec]
    ...
    
    The debug info consists of two CUs:
    ...
      Compilation Unit @ offset 0xb2:
       Length:        0x25 (32-bit)
       Version:       4
       Abbrev Offset: 0x6c
       Pointer Size:  8
     <0><bd>: Abbrev Number: 1 (DW_TAG_compile_unit)
        <be>   DW_AT_language    : 2        (non-ANSI C)
     <1><bf>: Abbrev Number: 2 (DW_TAG_subprogram)
        <c0>   DW_AT_low_pc      : 0x4004a7
        <c8>   DW_AT_high_pc     : 0x4004b2
        <d0>   DW_AT_specification: <0xe8>
     <1><d4>: Abbrev Number: 3 (DW_TAG_subprogram)
        <d5>   DW_AT_name        : main
     <1><da>: Abbrev Number: 0
      Compilation Unit @ offset 0xdb:
       Length:        0xf (32-bit)
       Version:       4
       Abbrev Offset: 0x86
       Pointer Size:  8
     <0><e6>: Abbrev Number: 1 (DW_TAG_compile_unit)
        <e7>   DW_AT_language    : 2        (non-ANSI C)
     <1><e8>: Abbrev Number: 2 (DW_TAG_subprogram)
        <e9>   DW_AT_specification: <0xd4>
     <1><ed>: Abbrev Number: 0
    ...
    where:
    - DIE 0xbf in CU@0xb2 contains an inter-CU reference to
    - DIE 0xe8 in CU@0xdb, which contains an inter-CU reference to
    - DIE 0xd4 back in CU@0xb2.
    
    The dwarf error is caused by this bit of code in
    cooked_indexer::ensure_cu_exists:
    ...
      if (per_cu == m_per_cu)
        return reader;
    ...
    
    The dwarf error happens as follows:
    - a cutu_reader A is created for CU@0xb2
    - using cutu_reader A, the cooked index reader starts indexing dies, with
      m_per_cu set to CU@0xb2
    - while indexing it scans the attributes of DIE 0xbf and encounters the
      inter-CU reference to DIE 0xe8
    - it calls cooked_indexer::ensure_cu_exists, which creates a cutu_reader B for
      CU@0xdb and returns it
    - using cutu_reader B, it continues scanning attributes of DIE 0xe8 and
      encounters the inter-CU reference to DIE 0xd4
    - it calls cooked_indexer::ensure_cu_exists, the problematic bit is triggered
      and cutu_reader B is returned
    - using cutu_reader B, it continues scanning attributes of DIE 0xd4
    - this goes wrong because:
      - the attributes of the DIE are encoded using the abbreviation table at
        offset 0x6c, while
      - the decoding is done using cutu_reader B which uses the abbreviation table
        at offset 0x86.
    
    Fix this by removing the problematic if clause.
    
    Since cutu_reader A is not preserved in m_index_storage,
    cooked_indexer::ensure_cu_exists cannot find it there and creates a duplicate
    cutu_reader C for CU@0xb2.  Fix this in process_psymtab_comp_unit by preserving
    the cutu_reader A as well in m_index_storage.
    
    Tested on x86_64-linux and aarch64-linux.
    
    PR symtab/32081
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32081
    
    Approved-By: Tom Tromey <tom@tromey.com>
    Reported-By: Andreas Schwab <schwab@linux-m68k.org>
Comment 14 Tom de Vries 2024-08-22 08:00:10 UTC
Fixed.