Bug 29381 - [gdb, debug-types, debug-names] read.h:309: internal-error: set_length: Assertion `m_length == length' failed.
Summary: [gdb, debug-types, debug-names] read.h:309: internal-error: set_length: Asser...
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 13.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-07-19 07:59 UTC by Tom de Vries
Modified: 2022-08-01 12:04 UTC (History)
0 users

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


Attachments
Tentative patch for the misleading warning (2.15 KB, patch)
2022-07-19 13:14 UTC, Tom de Vries
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2022-07-19 07:59:09 UTC
When running test-case gdb.cp/cpexprs-debug-types/cpexprs-debug-types with target board cc-with-debug-names on a system with gcc 12.1.1 (defaulting to dwarf 5), I run into:
...
(gdb) file /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-debug-types/cpexprs-debug-types^M
Reading symbols from /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-debug-types/cpexprs-debug-types...^M
warning: Section .debug_aranges in /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-debug-types/cpexprs-debug-types has duplicate debug_info_offset 0x0, ignoring .debug_aranges.^M
/data/vries/gdb_versions/devel/src/gdb/dwarf2/read.h:309: internal-error: set_length: Assertion `m_length == length' failed.^M
A problem internal to GDB has been detected,^M
further debugging may prove unreliable.^M
----- Backtrace -----^M
ERROR: Couldn't load cpexprs-debug-types into GDB (GDB internal error).
... 

The problem is three-fold.

1.
The .debug_names index is rejected in dwarf2_read_debug_names because:
...
  if (map->tu_count != 0)
    {
      /* We can only handle a single .debug_types when we have an
         index.  */
      if (per_bfd->types.size () != 1)
        return false;
...
there are TUs so the tu_count is > 0 but there's no .debug_types section (dwarf 5 puts the TUs in the .debug_info section) so the "per_bfd->types.size () != 1" test fails.

2.
After the index is rejected, we fall back to the cooked index, part of which is building up all_comp_units.  The assumption there is that we start from scratch, but in fact all_comp_units already has some elements, added when reading the index.  This leads to the complaints and eventually the assert.

3.
The complaint is misleading.  It's issued during read_addrmap_from_aranges, but the actual code does this:
...
  std::unordered_map<sect_offset,
                     dwarf2_per_cu_data *,
                     gdb::hash_enum<sect_offset>>
    debug_info_offset_to_per_cu;
  for (const auto &per_cu : per_bfd->all_comp_units)
    {
      /* A TU will not need aranges, and skipping them here is an easy
         way of ignoring .debug_types -- and possibly seeing a
         duplicate section offset -- entirely.  The same applies to
         units coming from a dwz file.  */
      if (per_cu->is_debug_types || per_cu->is_dwz)
        continue;

      const auto insertpair
        = debug_info_offset_to_per_cu.emplace (per_cu->sect_off,
                                               per_cu.get ());
      if (!insertpair.second)
        {
          warning (_("Section .debug_aranges in %s has duplicate "
                     "debug_info_offset %s, ignoring .debug_aranges."),
                   objfile_name (objfile), sect_offset_str (per_cu->sect_off));
          return false;
        }
    }
...

What the code really does is find duplicate offsets for CUs in all_comp_units.

Which I suppose also means that duplicate debug_info_offsets in .debug_aranges are not actually detected.  Not sure if that is a big problem.

Note that the variable, debug_info_offset_to_per_cu is used in this complaint:
...
      const auto per_cu_it
        = debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset));
      if (per_cu_it == debug_info_offset_to_per_cu.cend ())
        {
          warning (_("Section .debug_aranges in %s entry at offset %s "
                     "debug_info_offset %s does not exists, "
                     "ignoring .debug_aranges."),
                   objfile_name (objfile),
                   plongest (entry_addr - section->buffer),
                   pulongest (debug_info_offset));
          return false;
        }
...
and its usage here matches what we store in the variable.
Comment 1 Tom de Vries 2022-07-19 08:36:35 UTC
This addresses problem 2, both for .debug_names and .gdb_index:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index bcd01107377..3b4409fa8ca 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2696,7 +2696,10 @@ dwarf2_read_gdb_index
       /* We can only handle a single .debug_types when we have an
         index.  */
       if (per_bfd->types.size () != 1)
-       return 0;
+       {
+         per_bfd->all_comp_units.clear ();
+         return 0;
+       }
 
       dwarf2_section_info *section = &per_bfd->types[0];
 
@@ -4701,7 +4704,10 @@ dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)

       /* We can only handle a single .debug_types when we have an
         index.  */
       if (per_bfd->types.size () != 1)
-       return false;
+       {
+         per_bfd->all_comp_units.clear ();
+         return false;
+       }
 
       dwarf2_section_info *section = &per_bfd->types[0];
 
@@ -7206,6 +7212,7 @@ static void
 create_all_comp_units (dwarf2_per_objfile *per_objfile)
 {
   htab_up types_htab;
+  gdb_assert (per_objfile->per_bfd->all_comp_units.empty ());
 
   read_comp_units_from_section (per_objfile, &per_objfile->per_bfd->info,
                                &per_objfile->per_bfd->abbrev, 0,
...

Also adds an assert to detect the problem asap.  A similar assert is already present in create_cus_from_index and create_cus_from_debug_names.
Comment 2 Tom de Vries 2022-07-19 10:02:43 UTC
Zooming in on the actual assert, we have:
...
#6  0x0000000000714063 in dwarf2_per_cu_data::set_length (this=0x2cf2cd0, length=34, 
    strict_p=true) at /home/vries/gdb_versions/devel/src/gdb/dwarf2/read.h:309
309           gdb_assert (m_length == length);
(gdb) p m_length
$5 = 12611
(gdb) p this->sect_off
$7 = (unknown: 0x6d)
...

So initially, during index reading we assign length 12611 to the CU at 0x6d, but during create_all_comp_units we find that it's actually 34, which looks correct given the TU at offset 0x8f
...
CU table:
[  0] 0x0
[  1] 0x2e
[  2] 0x6d
[  3] 0x31b0
[  4] 0x7d53
[  5] 0x7f0b

TU table:
[  0] 0x8f
[  1] 0x1eb
[  2] 0x371
[  3] 0x4b0
[  4] 0x4f6
[  5] 0x53c
...

The initial 12611 length corresponds to 0x31b0 - 0x6d.

So that looks like another bug, which normally doesn't surface because we reject the .debug_names index if it has TUs in the .debug_info section.
Comment 3 Tom de Vries 2022-07-19 10:24:11 UTC
(In reply to Tom de Vries from comment #2)
> Zooming in on the actual assert, we have:

This fixes the length discrepancy:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 143bcfb5374..490cc3dd0b2 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -4590,7 +4590,8 @@ create_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd,
                                  dwarf2_section_info &section,
                                  bool is_dwz)
 {
-  if (!map.augmentation_is_gdb)
+  if (!map.augmentation_is_gdb
+      || (map.tu_count > 0 && per_bfd->types.size () == 0))
     {
       for (uint32_t i = 0; i < map.cu_count; ++i)
        {
...
and makes the assert disappear.

But in combination with the "[gdbsupport] Use task size in parallel_for_each" patch we run instead into:
...
/home/vries/gdb_versions/devel/src/gdb/dwarf2/read.h:298: internal-error: length: Assertion `m_length != 0' failed.
...
because we still have those duplicates.
Comment 4 Tom de Vries 2022-07-19 11:34:59 UTC
(In reply to Tom de Vries from comment #0)
> When running test-case gdb.cp/cpexprs-debug-types/cpexprs-debug-types with
> target board cc-with-debug-names on a system with gcc 12.1.1 (defaulting to
> dwarf 5), I run into:
> ...
> (gdb) file
> /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-
> debug-types/cpexprs-debug-types^M
> Reading symbols from
> /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-
> debug-types/cpexprs-debug-types...^M
> warning: Section .debug_aranges in
> /data/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.cp/cpexprs-
> debug-types/cpexprs-debug-types has duplicate debug_info_offset 0x0,
> ignoring .debug_aranges.^M
> /data/vries/gdb_versions/devel/src/gdb/dwarf2/read.h:309: internal-error:
> set_length: Assertion `m_length == length' failed.^M
> A problem internal to GDB has been detected,^M
> further debugging may prove unreliable.^M
> ----- Backtrace -----^M
> ERROR: Couldn't load cpexprs-debug-types into GDB (GDB internal error).
> ... 
> 
> The problem is three-fold.
> 
> 1.
> The .debug_names index is rejected in dwarf2_read_debug_names because:
> ...
>   if (map->tu_count != 0)
>     {
>       /* We can only handle a single .debug_types when we have an
>          index.  */
>       if (per_bfd->types.size () != 1)
>         return false;
> ...
> there are TUs so the tu_count is > 0 but there's no .debug_types section
> (dwarf 5 puts the TUs in the .debug_info section) so the
> "per_bfd->types.size () != 1" test fails.
> 

Filed as PR29385.
Comment 5 Tom de Vries 2022-07-19 13:14:56 UTC
Created attachment 14222 [details]
Tentative patch for the misleading warning
Comment 6 Tom de Vries 2022-07-19 16:50:49 UTC
(In reply to Tom de Vries from comment #1)
> This addresses problem 2, both for .debug_names and .gdb_index:
> ...
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index bcd01107377..3b4409fa8ca 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -2696,7 +2696,10 @@ dwarf2_read_gdb_index
>        /* We can only handle a single .debug_types when we have an
>          index.  */
>        if (per_bfd->types.size () != 1)
> -       return 0;
> +       {
> +         per_bfd->all_comp_units.clear ();
> +         return 0;
> +       }
>  
>        dwarf2_section_info *section = &per_bfd->types[0];
>  
> @@ -4701,7 +4704,10 @@ dwarf2_read_debug_names (dwarf2_per_objfile
> *per_objfile)
> 
>        /* We can only handle a single .debug_types when we have an
>          index.  */
>        if (per_bfd->types.size () != 1)
> -       return false;
> +       {
> +         per_bfd->all_comp_units.clear ();
> +         return false;
> +       }
>  
>        dwarf2_section_info *section = &per_bfd->types[0];
>  
> @@ -7206,6 +7212,7 @@ static void
>  create_all_comp_units (dwarf2_per_objfile *per_objfile)
>  {
>    htab_up types_htab;
> +  gdb_assert (per_objfile->per_bfd->all_comp_units.empty ());
>  
>    read_comp_units_from_section (per_objfile, &per_objfile->per_bfd->info,
>                                 &per_objfile->per_bfd->abbrev, 0,
> ...
> 
> Also adds an assert to detect the problem asap.  A similar assert is already
> present in create_cus_from_index and create_cus_from_debug_names.

https://sourceware.org/pipermail/gdb-patches/2022-July/190891.html
Comment 7 Tom de Vries 2022-07-19 17:36:34 UTC
(In reply to Tom de Vries from comment #5)
> Created attachment 14222 [details]
> Tentative patch for the misleading warning

https://sourceware.org/pipermail/gdb-patches/2022-July/190894.html
Comment 9 Tom de Vries 2022-08-01 12:04:08 UTC
(In reply to Tom de Vries from comment #7)
> (In reply to Tom de Vries from comment #5)
> > Created attachment 14222 [details]
> > Tentative patch for the misleading warning
> 
> https://sourceware.org/pipermail/gdb-patches/2022-July/190894.html

https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=75337cbc1476b7eb403fe0e73c52bf080b5996c8