Bug 26327 - GDB hangs in get_builder() due to recursive ancestor pointers
Summary: GDB hangs in get_builder() due to recursive ancestor pointers
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 11.1
Assignee: Not yet assigned to anyone
URL: http://51.15.138.76/patch/37038/
Keywords:
Depends on:
Blocks:
 
Reported: 2020-07-31 23:54 UTC by d.c.ddcc
Modified: 2021-06-16 10:51 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2020-08-01 00:00:00


Attachments
447.dealII, hangs on reading symbols in GDB (1.99 MB, application/octet-stream)
2020-08-01 21:58 UTC, d.c.ddcc
Details

Note You need to log in before you can comment on or make changes to this bug.
Description d.c.ddcc 2020-07-31 23:54:48 UTC
With recent versions of gdb (somewhere around 8.x to 10.0.50.20200731-git), I've noticed that GDB sometimes hangs when debugging C++ programs compiled with Clang/LLVM 10.0.1. This can occur either initially when reading symbols, or during debugging after a breakpoint fires.

I noticed a workaround was sent previously: "Fixing get_builder() function in dwarf2/read.c", which appears to be for the same problem. I don't know what the correct solution is wrt parsing DWARF symbols, but I'm experiencing similar symptoms, and my stacktrace looks similar to the second one sent out by Slava.

I can provide the binary (~9MB), but not the direct source (it's 447.dealII from SPEC CPU2006).
Comment 1 Tom de Vries 2020-08-01 09:16:32 UTC
(In reply to d.c.ddcc from comment #0)
> I noticed a workaround was sent previously: "Fixing get_builder() function
> in dwarf2/read.c"

https://sourceware.org/pipermail/gdb-patches/2020-June/169471.html
Comment 2 Simon Marchi 2020-08-01 12:52:53 UTC
Like I said in the original report, a reproducer program or at least binary would be useful so we can analyze the problem and make sure we fix the problem the right way, and not only cover up the problem.
Comment 3 d.c.ddcc 2020-08-01 21:58:22 UTC
Created attachment 12737 [details]
447.dealII, hangs on reading symbols in GDB

#0  0x0000560a5ab7e27c in dwarf2_cu::get_builder (this=0x560a5eb32060) at ../../gdb/dwarf2/read.c:606
    dwarf2_name(die, cu) = 0x7f9fe022b8d3 "arg_list"
#1  new_symbol (die=0x560a5f391500, type=0x0, cu=0x560a5eb32060, space=<optimized out>)
    at ../../gdb/dwarf2/read.c:21225
    dwarf2_name(die, cu) = 0x7f9fe022b8d3 "arg_list"
#2  0x0000560a5ab881a1 in process_die (die=0x560a5f391500, cu=0x560a5eb32060)
    at ../../gdb/dwarf2/read.c:10214
    dwarf2_name(die, cu) = 0x560a5f3b7200 "do_call<void (*)(std::vector<DataOutBase::Patch<3, 3>, std::allocator<DataOutBase::Patch<3, 3> > > const&, Table<2, double>&), boost::tuples::tuple<std::vector<DataOutBase::Patch<3, 3>, std::allocator<DataOutBase::Patch<3, 3> > > const&, Table<2, double>&, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type> >"
#3  0x0000560a5ab86930 in inherit_abstract_dies (die=0x560a5d66ab00, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13132
#4  0x0000560a5ab86d83 in read_func_scope (die=0x560a5d66ab00, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13260
#5  0x0000560a5ab88239 in process_die (die=0x560a5d66ab00, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#6  0x0000560a5ab86d1b in read_func_scope (die=0x560a5d66aa30, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#7  0x0000560a5ab88239 in process_die (die=0x560a5d66aa30, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#8  0x0000560a5ab86d1b in read_func_scope (die=0x560a5d66a950, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#9  0x0000560a5ab88239 in process_die (die=0x560a5d66a950, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#10 0x0000560a5ab86d1b in read_func_scope (die=0x560a5d66a7e0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#11 0x0000560a5ab88239 in process_die (die=0x560a5d66a7e0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#12 0x0000560a5ab86d1b in read_func_scope (die=0x560a5d6683e0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#13 0x0000560a5ab88239 in process_die (die=0x560a5d6683e0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#14 0x0000560a5ab86d1b in read_func_scope (die=0x560a5d6682c0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#15 0x0000560a5ab88239 in process_die (die=0x560a5d6682c0, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#16 0x0000560a5ab86d1b in read_func_scope (die=0x560a5d668100, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#17 0x0000560a5ab88239 in process_die (die=0x560a5d668100, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#18 0x0000560a5ab8b8cb in read_lexical_block_scope (die=0x560a5d65d420, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13391
#19 0x0000560a5ab89222 in process_die (die=0x560a5d65d420, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10141
#20 0x0000560a5ab86d1b in read_func_scope (die=0x560a5d60a830, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:13255
#21 0x0000560a5ab88239 in process_die (die=0x560a5d60a830, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10136
#22 0x0000560a5ab8b4a9 in read_file_scope (die=0x560a5d457e90, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:11112
#23 0x0000560a5ab89190 in process_die (die=0x560a5d457e90, cu=0x560a5d479a30)
    at ../../gdb/dwarf2/read.c:10123
#24 0x0000560a5ab8bf03 in process_full_comp_unit (pretend_language=<optimized out>,
    cu=0x560a5d479a30) at ../../gdb/dwarf2/read.c:9893
#25 process_queue (per_objfile=0x560a5d231940) at ../../gdb/dwarf2/read.c:9134
#26 dw2_do_instantiate_symtab (per_cu=per_cu@entry=0x560a5d470180,
    per_objfile=per_objfile@entry=0x560a5d231940, skip_partial=skip_partial@entry=false)
    at ../../gdb/dwarf2/read.c:2411
#27 0x0000560a5ab8c457 in dw2_instantiate_symtab (per_cu=0x560a5d470180, per_objfile=0x560a5d231940,
    skip_partial=<optimized out>) at ../../gdb/dwarf2/read.c:2434
#28 0x0000560a5ab8d10c in dw2_lookup_symbol (objfile=<optimized out>, block_index=GLOBAL_BLOCK,
    name=0x560a5d3feaa0 "main", domain=VAR_DOMAIN) at ../../gdb/dwarf2/read.c:3623
#29 0x0000560a5ad420fb in lookup_symbol_via_quick_fns (domain=VAR_DOMAIN,
    name=0x560a5d3feaa0 "main", block_index=GLOBAL_BLOCK, objfile=0x560a5d3fe3e0)
    at ../../gdb/symtab.c:2373
#30 lookup_symbol_in_objfile (objfile=0x560a5d3fe3e0, block_index=GLOBAL_BLOCK,
    name=0x560a5d3feaa0 "main", domain=VAR_DOMAIN) at ../../gdb/symtab.c:2522
#31 0x0000560a5ad42344 in lookup_symbol_global_or_static_iterator_cb (objfile=<optimized out>,
    cb_data=0x7ffea086f6f0) at ../../gdb/symtab.c:2596
#32 0x0000560a5ad0b744 in svr4_iterate_over_objfiles_in_search_order (gdbarch=<optimized out>,
    cb=0x560a5ad42320 <lookup_symbol_global_or_static_iterator_cb(objfile*, void*)>,
    cb_data=0x7ffea086f6f0, current_objfile=0x0) at ../../gdb/solib-svr4.c:3248
#33 0x0000560a5ad3c4be in lookup_global_or_static_symbol (name=0x560a5d3feaa0 "main",
    block_index=GLOBAL_BLOCK, objfile=0x0, domain=VAR_DOMAIN) at ../../gdb/symtab.c:2641
#34 0x0000560a5ad41b6d in lookup_global_symbol (name=0x560a5d3feaa0 "main", block=<optimized out>,
    domain=VAR_DOMAIN) at ../../gdb/symtab.c:2691
#35 0x0000560a5ad417d4 in lookup_symbol_aux (name=0x560a5d3feaa0 "main",
    match_type=match_type@entry=symbol_name_match_type::FULL, block=block@entry=0x0,
    domain=domain@entry=VAR_DOMAIN, language=language@entry=language_c,
    is_a_field_of_this=is_a_field_of_this@entry=0x0) at ../../gdb/symtab.c:2089
#36 0x0000560a5ad41934 in lookup_symbol_in_language (name=<optimized out>, block=block@entry=0x0,
    domain=domain@entry=VAR_DOMAIN, lang=lang@entry=language_c,
    is_a_field_of_this=is_a_field_of_this@entry=0x0) at ../../gdb/symtab.c:1881
#37 0x0000560a5ad2cf9c in set_initial_language () at ../../gdb/symfile.c:1683
#38 0x0000560a5ac41840 in catch_command_errors (command=<optimized out>, arg=<optimized out>,
    from_tty=<optimized out>) at ../../gdb/main.c:457
#39 0x0000560a5ac435cd in captured_main_1 (context=<optimized out>) at ../../gdb/main.c:1123
#40 0x0000560a5ac4381f in captured_main (data=0x7ffea086fba0) at ../../gdb/main.c:1243
#41 gdb_main (args=args@entry=0x7ffea086fbc0) at ../../gdb/main.c:1268
#42 0x0000560a5aa57640 in main (argc=<optimized out>, argv=<optimized out>) at ../../gdb/gdb.c:32
Comment 4 d.c.ddcc 2020-08-01 22:02:07 UTC
I've added a problematic binary as an attachment, plus a stack trace, and the result of manually calling `dwarf2_die(die, cu)` on a couple of the top stack frames. Let me know if you need anything else; I could also supply a packed rr trace of GDB loading the file, if that's useful. Note that this binary is using musl libc with a custom loader path, so it may not be directly executable.
Comment 5 Simon Marchi 2020-08-01 22:20:34 UTC
Thanks!

The infinite can be triggered without running the binary, with:

  ./gdb -nx -readnow 447.dealII

Note that I made GDB crash in other fun ways with this binary

1. Create breakpoint on main

$./gdb -nx ~/Downloads/447.dealII 
(gdb) b main
[1]    1054570 abort (core dumped)  ./gdb -nx ~/Downloads/447.dealII

2. With the index-cache

Populate the index-cache for this binary:

$ ./gdb -nx -iex "set index-cache on" ~/Downloads/447.dealII -batch

It should create this file:

~/.cache/gdb/ad3eca2473ddcca165529cecf211308a2e8f5291.gdb-index

Then, starting GDB again crashes:

$./gdb -nx -iex "set index-cache on" ~/Downloads/447.dealII -batch
[1]    1054856 abort (core dumped)  ./gdb -nx -iex "set index-cache on" ~/Downloads/447.dealII -batch
Comment 6 Tom de Vries 2020-10-19 12:21:22 UTC
Tentative patch, prevents introducing cycles in ancestor chain:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 37409c5c3f..72e5446b8b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -22947,7 +22947,19 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz,
   temp_die.sect_off = sect_off;
 
   if (target_cu != cu)
-    target_cu->ancestor = cu;
+    {
+      bool cycle_p = false;
+      for (struct dwarf2_cu *tmp = cu->ancestor; tmp; tmp = tmp->ancestor)
+       {
+         if (tmp != target_cu)
+           continue;
+
+         cycle_p = true;
+         break;
+       }
+      if (!cycle_p)
+       target_cu->ancestor = cu;
+    }
 
   return (struct die_info *) htab_find_with_hash (target_cu->die_hash,
                                                  &temp_die,
@@ -24256,7 +24268,8 @@ dwarf2_cu::dwarf2_cu (dwarf2_per_cu_data *per_cu,
     producer_is_icc (false),
     producer_is_icc_lt_14 (false),
     producer_is_codewarrior (false),
-    processing_has_namespace_info (false)
+    processing_has_namespace_info (false),
+    ancestor (nullptr)
 {
 }
 
...
Comment 7 Tom de Vries 2020-10-29 14:42:48 UTC
(In reply to Tom de Vries from comment #6)
> Tentative patch, prevents introducing cycles in ancestor chain:

Which fixes the hang.  But not the "./gdb -nx -readnow 447.dealII" crash.

This fixes the crash:
...
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index e1c528f44d..64f2ba0ee0 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -21632,15 +21632,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2
_cu *cu,
          break;
        case DW_TAG_formal_parameter:
          {
-           /* If we are inside a function, mark this as an argument.  If
-              not, we might be looking at an argument to an inlined function
-              when we do not have enough information to show inlined frames;
-              pretend it's a local variable in that case so that the user can
-              still see it.  */
-           struct context_stack *curr
-             = cu->get_builder ()->get_current_context_stack ();
-           if (curr != nullptr && curr->name != nullptr)
-             SYMBOL_IS_ARGUMENT (sym) = 1;
+           SYMBOL_IS_ARGUMENT (sym) = 1;
            attr = dwarf2_attr (die, DW_AT_location, cu);
            if (attr != nullptr)
              {
...
Comment 8 d.c.ddcc 2020-11-07 21:43:09 UTC
Is this the to-be-committed fix, or a workaround? I'm not familiar with DWARF internals, and whether this handling of inlined function arguments is necessary?
Comment 9 Mike Crowe 2021-04-14 14:25:27 UTC
I ran into this debugging a core dump from a GCC-9.3-compiled application linked to a Clang-10.0.1-compiled shared library with gdb 9.1. The thread I was attempting to backtrace was in the Clang-compiled shared library.

Applying the patches from comment 6 and comment 7 appeared to resolve the problem and I was able to see what looked like a correct backtrace.
Comment 10 Richard Biener 2021-05-05 12:46:43 UTC
(In reply to Tom de Vries from comment #6)
> Tentative patch, prevents introducing cycles in ancestor chain:
> ...
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 37409c5c3f..72e5446b8b 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -22947,7 +22947,19 @@ follow_die_offset (sect_offset sect_off, int
> offset_in_dwz,
>    temp_die.sect_off = sect_off;
>  
>    if (target_cu != cu)
> -    target_cu->ancestor = cu;
> +    {
> +      bool cycle_p = false;
> +      for (struct dwarf2_cu *tmp = cu->ancestor; tmp; tmp = tmp->ancestor)

of course that loop looks quite expensive - what prevents target_cu
from having multiple ancestors?  The above just overwrites the old.
For example with GCC LTO a LTRANS CU can refer to multiple compile CUs
via abstract origins.  And indeed I don't think DWARF forbids cycles here
(but at least I think GCC shouldn't create those).

Will the CU with m_builder ever have an ancestor?  Thus, how about recording
the ultimate ancestor only (which then should have the builder):

  if (target_cu != cu)
    { 
      gcc_assert (!target_cu->m_builder);
      target_cu->ancestor = cu->ancestor;
      gcc_assert (target_cu->ancestor->m_builder);
    }

and removing the recursion in get_builder?

> +       {
> +         if (tmp != target_cu)
> +           continue;
> +
> +         cycle_p = true;
> +         break;
> +       }
> +      if (!cycle_p)
> +       target_cu->ancestor = cu;
> +    }
>  
>    return (struct die_info *) htab_find_with_hash (target_cu->die_hash,
>                                                   &temp_die,
> @@ -24256,7 +24268,8 @@ dwarf2_cu::dwarf2_cu (dwarf2_per_cu_data *per_cu,
>      producer_is_icc (false),
>      producer_is_icc_lt_14 (false),
>      producer_is_codewarrior (false),
> -    processing_has_namespace_info (false)
> +    processing_has_namespace_info (false),
> +    ancestor (nullptr)
>  {
>  }
>  
> ...
Comment 11 Richard Biener 2021-05-05 12:49:41 UTC
(In reply to Richard Biener from comment #10)
> (In reply to Tom de Vries from comment #6)
> > Tentative patch, prevents introducing cycles in ancestor chain:
> > ...
> > diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> > index 37409c5c3f..72e5446b8b 100644
> > --- a/gdb/dwarf2/read.c
> > +++ b/gdb/dwarf2/read.c
> > @@ -22947,7 +22947,19 @@ follow_die_offset (sect_offset sect_off, int
> > offset_in_dwz,
> >    temp_die.sect_off = sect_off;
> >  
> >    if (target_cu != cu)
> > -    target_cu->ancestor = cu;
> > +    {
> > +      bool cycle_p = false;
> > +      for (struct dwarf2_cu *tmp = cu->ancestor; tmp; tmp = tmp->ancestor)
> 
> of course that loop looks quite expensive - what prevents target_cu
> from having multiple ancestors?  The above just overwrites the old.
> For example with GCC LTO a LTRANS CU can refer to multiple compile CUs
> via abstract origins.  And indeed I don't think DWARF forbids cycles here
> (but at least I think GCC shouldn't create those).
> 
> Will the CU with m_builder ever have an ancestor?  Thus, how about recording
> the ultimate ancestor only (which then should have the builder):
> 
>   if (target_cu != cu)
>     { 
>       gcc_assert (!target_cu->m_builder);
>       target_cu->ancestor = cu->ancestor;
>       gcc_assert (target_cu->ancestor->m_builder);
>     }
> 
> and removing the recursion in get_builder?

And since all this is only relevant in the "full symbols are being read"
case not set ->ancestor at all when cu->ancestor->m_builder is NULL.

> > +       {
> > +         if (tmp != target_cu)
> > +           continue;
> > +
> > +         cycle_p = true;
> > +         break;
> > +       }
> > +      if (!cycle_p)
> > +       target_cu->ancestor = cu;
> > +    }
> >  
> >    return (struct die_info *) htab_find_with_hash (target_cu->die_hash,
> >                                                   &temp_die,
> > @@ -24256,7 +24268,8 @@ dwarf2_cu::dwarf2_cu (dwarf2_per_cu_data *per_cu,
> >      producer_is_icc (false),
> >      producer_is_icc_lt_14 (false),
> >      producer_is_codewarrior (false),
> > -    processing_has_namespace_info (false)
> > +    processing_has_namespace_info (false),
> > +    ancestor (nullptr)
> >  {
> >  }
> >  
> > ...
Comment 12 Tom de Vries 2021-05-05 15:51:30 UTC
Hmm, this survives a build & regression test on Leap 15.2:
...
$ git diff
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 5796cf1730b..c889c1c15af 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -695,9 +695,11 @@ struct dwarf2_cu
     if (m_builder != nullptr)
       return m_builder.get ();
 
+#if 0
     /* Otherwise, search ancestors for a valid builder.  */
     if (ancestor != nullptr)
       return ancestor->get_builder ();
+#endif
 
     return nullptr;
   }
@@ -22045,15 +22047,7 @@ new_symbol (struct die_info *die, struct type *type, struct d
warf2_cu *cu,
          break;
        case DW_TAG_formal_parameter:
          {
-           /* If we are inside a function, mark this as an argument.  If
-              not, we might be looking at an argument to an inlined function
-              when we do not have enough information to show inlined frames;
-              pretend it's a local variable in that case so that the user can
-              still see it.  */
-           struct context_stack *curr
-             = cu->get_builder ()->get_current_context_stack ();
-           if (curr != nullptr && curr->name != nullptr)
-             SYMBOL_IS_ARGUMENT (sym) = 1;
+           SYMBOL_IS_ARGUMENT (sym) = 1;
            attr = dwarf2_attr (die, DW_AT_location, cu);
            if (attr != nullptr)
              {
...
Comment 13 Tom de Vries 2021-05-05 16:59:22 UTC
(In reply to Tom de Vries from comment #12)
> Hmm, this survives a build & regression test on Leap 15.2:

Same on Tumbleweed.
Comment 14 Richard Biener 2021-05-06 08:11:09 UTC
So what I meant is record the builder by means of recording its CU rather than
trying to be too clever walking the "ancestor chain" (which we don't do properly anyway).
Comment 15 Tom de Vries 2021-05-06 12:16:31 UTC
(In reply to Tom de Vries from comment #13)
> (In reply to Tom de Vries from comment #12)
> > Hmm, this survives a build & regression test on Leap 15.2:
> 
> Same on Tumbleweed.

Patch submitted: https://sourceware.org/pipermail/gdb-patches/2021-May/178547.html
Comment 16 Sourceware Commits 2021-05-07 10:13:18 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=4cf88725da1cb503be04d3237354105ec170bc86

commit 4cf88725da1cb503be04d3237354105ec170bc86
Author: Tom de Vries <tdevries@suse.de>
Date:   Fri May 7 12:13:05 2021 +0200

    [gdb/symtab] Fix infinite recursion in dwarf2_cu::get_builder()
    
    With the test-case attached in PR26327, gdb aborts:
    ...
    $ gdb -q -batch 447.dealII -ex "b main"
    Aborted (core dumped)
    ...
    when running out of stack due to infinite recursion:
    ...
     #8  0x00000000006aaba6 in dwarf2_cu::get_builder (this=0x35e4b40)
         at src/gdb/dwarf2/read.c:700
     #9  0x00000000006aaba6 in dwarf2_cu::get_builder (this=0x22ee2c0)
         at src/gdb/dwarf2/read.c:700
     #10 0x00000000006aaba6 in dwarf2_cu::get_builder (this=0x35e4b40)
         at src/gdb/dwarf2/read.c:700
     #11 0x00000000006aaba6 in dwarf2_cu::get_builder (this=0x22ee2c0)
         at src/gdb/dwarf2/read.c:700
    ...
    
    We're recursing in this code in dwarf2_cu::get_builder():
    ...
         /* Otherwise, search ancestors for a valid builder.  */
         if (ancestor != nullptr)
           return ancestor->get_builder ();
    ...
    due to the fact that the ancestor chain is a cycle.
    
    Higher up in the call stack, we find some code that is responsible for
    triggering this, in new_symbol:
    ...
           case DW_TAG_formal_parameter:
             {
               /* If we are inside a function, mark this as an argument.  If
                  not, we might be looking at an argument to an inlined function
                  when we do not have enough information to show inlined frames;
                  pretend it's a local variable in that case so that the user can
                  still see it.  */
               struct context_stack *curr
                 = cu->get_builder ()->get_current_context_stack ();
               if (curr != nullptr && curr->name != nullptr)
                 SYMBOL_IS_ARGUMENT (sym) = 1;
    ...
    
    This is code that was added to support pre-4.1 gcc, to be able to show
    arguments of inlined functions as locals, in the absense of sufficiently
    correct debug information.
    
    Removing this code (that is, doing SYMBOL_IS_ARGUMENT (sym) = 1
    unconditially), fixes the crash.  The ancestor variable also seems to have
    been added specifically to deal with fallout from this code, so remove that as
    well.
    
    Tested on x86_64-linux:
    - openSUSE Leap 15.2 with gcc 7.5.0, and
    - openSUSE Tumbleweed with gcc 10.3.0.
    
    gdb/ChangeLog:
    
    2021-05-07  Tom de Vries  <tdevries@suse.de>
    
            PR symtab/26327
            * dwarf2/read.c (struct dwarf2_cu): Remove ancestor.
            (dwarf2_cu::get_builder): Remove ancestor-related code.
            (new_symbol): Remove code supporting pre-4.1 gcc that show arguments
            of inlined functions as locals.
            (follow_die_offset, follow_die_sig_1): Remove setting of ancestor.
    
    gdb/doc/ChangeLog:
    
    2021-05-07  Tom de Vries  <tdevries@suse.de>
    
            PR symtab/26327
            * gdb.texinfo (Inline Functions): Update.
Comment 17 Tom de Vries 2021-05-07 10:14:27 UTC
Patch committed, marking resolved-fixed.
Comment 18 Tom de Vries 2021-05-12 14:04:27 UTC
Patch reverted due to regression, reopening.
Comment 19 Christopher Yeleighton 2021-05-21 16:13:29 UTC
(In reply to Tom de Vries from comment #12)
> +#if 0
>      /* Otherwise, search ancestors for a valid builder.  */
>      if (ancestor != nullptr)
>        return ancestor->get_builder ();
> +#endif

The problem is not that we search ancestors, the problem is that we allow ancestors to form a loop.  See detailed investigation at <URL: https://bugzilla.opensuse.org/show_bug.cgi?id=1185800 >.  Your fix looks more like a band-aid to me.

As a side note, I have captured a situation when the ancestor is a random non-pointer because cu constructor does not bother to clear it.  Not nice.
Comment 21 Sourceware Commits 2021-06-16 10:44:36 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=8457e5ecc45295bc9550c4f705a276d5ca90d908

commit 8457e5ecc45295bc9550c4f705a276d5ca90d908
Author: Tom de Vries <tdevries@suse.de>
Date:   Wed Jun 16 12:44:30 2021 +0200

    [gdb/symtab] Fix infinite recursion in dwarf2_cu::get_builder(), again
    
    This is another attempt at fixing the problem described in commit 4cf88725da1
    "[gdb/symtab] Fix infinite recursion in dwarf2_cu::get_builder()", which was
    reverted in commit 3db19b2d724.
    
    First off, some context.
    
    A DWARF CU can be viewed as a symbol table: toplevel children of a CU DIE
    represent symbol table entries for that CU.  Furthermore, there is a
    hierarchy: a symbol table entry such as a function itself has a symbol table
    containing parameters and local variables.
    
    The dwarf reader maintains a notion of current symbol table (that is: the
    symbol table a new symbol needs to be entered into) in dwarf2_cu member
    list_in_scope.
    
    A problem then presents itself when reading inter-CU references:
    - a new symbol read from a CU B needs to be entered into the symbol table of
      another CU A.
    - the notion of current symbol table is tracked on a per-CU basis.
    This is addressed in inherit_abstract_dies by temporarily overwriting the
    list_in_scope for CU B with the one for CU A.
    
    The current symbol table is one aspect of the current dwarf reader context
    that is tracked, but there are more, f.i. ones that are tracked via the
    dwarf2_cu member m_builder, f.i. m_builder->m_local_using_directives.
    
    A similar problem exists in relation to inter-CU references, but a different
    solution was chosen:
    - to keep track of an ancestor field in dwarf2_cu, which is updated
      when traversing inter-CU references, and
    - to use the ancestor field in dwarf2_cu::get_builder to return the m_builder
      in scope.
    
    There is no actual concept of a CU having an ancestor, it just marks the most
    recent CU from which a CU was inter-CU-referenced.  Consequently, when
    following inter-CU references from a CU A to another CU B and back to CU A,
    the ancestors form a cycle, which causes dwarf2_cu::get_builder to hang or
    segfault, as reported in PR26327.
    
    ISTM that the ancestor implementation is confusing and fragile, and should
    go.  Furthermore, it seems that keeping track of the m_builder in scope can be
    handled simply with a per-objfile variable.
    
    Fix the hang / segfault by:
    - keeping track of the m_builder in scope using a new variable
      per_obj->sym_cu, and
    - using it in dwarf2_cu::get_builder.
    
    Tested on x86_64-linux (openSUSE Leap 15.2), no regressions for config:
    - using default gcc version 7.5.0
      (with 5 unexpected FAILs)
    - gcc 10.3.0 and target board
      unix/-flto/-O0/-flto-partition=none/-ffat-lto-objects
      (with 1000 unexpected FAILs)
    
    gdb/ChangeLog:
    
    2021-06-16  Tom de Vries  <tdevries@suse.de>
    
            PR symtab/26327
            * dwarf2/cu.h (dwarf2_cu::ancestor): Remove.
            (dwarf2_cu::get_builder): Declare and move ...
            * dwarf2/cu.c (dwarf2_cu::get_builder): ... here.  Use sym_cu instead
            of ancestor.  Assert return value is non-null.
            * dwarf2/read.c (read_file_scope): Set per_objfile->sym_cu.
            (follow_die_offset, follow_die_sig_1): Remove setting of ancestor.
            (dwarf2_per_objfile): Add sym_cu field.
Comment 22 Tom de Vries 2021-06-16 10:51:10 UTC
Patch committed, marking resolved-fixed, again.