debug: Fix up DWARF 5 -g -flto -ffat-lto-objects [PR98765]
authorJakub Jelinek <jakub@redhat.com>
Wed, 20 Jan 2021 17:51:04 +0000 (18:51 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 20 Jan 2021 17:51:04 +0000 (18:51 +0100)
As mentioned in the PR, with -gdwarf-5 (or -g now) -flto -ffat-lto-objects,
users can't strip the LTO sections with
strip -p -R .gnu.lto_* -R .gnu.debuglto_* -N __gnu_lto_v1
anymore when GCC is configured against recent binutils.

The problem is that in that case .gnu.debuglto_.debug_line_str section is
then used, which is fine for references to strings in .gnu.debuglto_.*
sections, but not when those references are in .debug_info section too;
those should really reference separate strings in .debug_line_str section.

For .gnu.debuglto_.debug_str vs. .debug_str we handle it right, we
reset_indirect_string the strings and thus force creation of new labels for
the second time.
But for DW_FORM_line_strp as the patch shows, there were multiple problems.
First one was that reset_indirect_string, even when called through traverse
on debug_line_str_hash, didn't do anything at all (fixed by first hunk).
The second bug was that the DW_FORM_line_strp strings, which were supposed
to be only visible through debug_line_str_hash, leaked into debug_str_hash
(second hunk).
And the third thing is that when we reset debug_line_str_hash, we should
still make those strings DW_FORM_line_strp if they are accessed.
One could do it by reinstantiating DW_FORM_line_strp right away in
reset_indirect_string and not clear debug_line_str_hash, but that has the
disadvantage that we then force emitting .debug_line_str strings that aren't
really needed - we need those from the CU DIEs' DW_AT_name and
DW_AT_comp_dir attributes, but when emitting .debug_line section through
assembler, we don't need to emit the strings we only needed for
.gnu.debuglto_.debug_line which is always emitted by the compiler.

2021-01-20  Jakub Jelinek  <jakub@redhat.com>

PR debug/98765
* dwarf2out.c (reset_indirect_string): Also reset indirect strings
with DW_FORM_line_strp form.
(prune_unused_types_update_strings): Don't add into debug_str_hash
indirect strings with DW_FORM_line_strp form.
(adjust_name_comp_dir): New function.
(dwarf2out_finish): Call it on CU DIEs after resetting
debug_line_str_hash.

gcc/dwarf2out.c

index 93e5d15e20ad7f5e1fe260825f387ca507b40474..77ea4948d5ea84d62dab52474f6800c83f89bc6e 100644 (file)
@@ -4733,7 +4733,9 @@ int
 reset_indirect_string (indirect_string_node **h, void *)
 {
   struct indirect_string_node *node = *h;
-  if (node->form == DW_FORM_strp || node->form == dwarf_FORM (DW_FORM_strx))
+  if (node->form == DW_FORM_strp
+      || node->form == DW_FORM_line_strp
+      || node->form == dwarf_FORM (DW_FORM_strx))
     {
       free (node->label);
       node->label = NULL;
@@ -29477,8 +29479,9 @@ prune_unused_types_update_strings (dw_die_ref die)
        s->refcount++;
        /* Avoid unnecessarily putting strings that are used less than
           twice in the hash table.  */
-       if (s->refcount
-           == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+       if (s->form != DW_FORM_line_strp
+           && (s->refcount
+               == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2)))
          {
            indirect_string_node **slot
              = debug_str_hash->find_slot_with_hash (s->str,
@@ -31325,6 +31328,33 @@ reset_dies (dw_die_ref die)
   FOR_EACH_CHILD (die, c, reset_dies (c));
 }
 
+/* reset_indirect_string removed the references coming from DW_AT_name
+   and DW_AT_comp_dir attributes on compilation unit DIEs.  Readd them as
+   .debug_line_str strings again.  */
+
+static void
+adjust_name_comp_dir (dw_die_ref die)
+{
+  for (int i = 0; i < 2; i++)
+    {
+      dwarf_attribute attr_kind = i ? DW_AT_comp_dir : DW_AT_name;
+      dw_attr_node *a = get_AT (die, attr_kind);
+      if (a == NULL || a->dw_attr_val.val_class != dw_val_class_str)
+       continue;
+
+      if (!debug_line_str_hash)
+       debug_line_str_hash
+         = hash_table<indirect_string_hasher>::create_ggc (10);
+
+      struct indirect_string_node *node
+       = find_AT_string_in_table (a->dw_attr_val.v.val_str->str,
+                                  debug_line_str_hash);
+      set_indirect_string (node);
+      node->form = DW_FORM_line_strp;
+      a->dw_attr_val.v.val_str = node;
+    }
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -31398,6 +31428,12 @@ dwarf2out_finish (const char *filename)
        {
          debug_line_str_hash->traverse<void *, reset_indirect_string> (NULL);
          debug_line_str_hash = NULL;
+         if (asm_outputs_debug_line_str ())
+           {
+             adjust_name_comp_dir (comp_unit_die ());
+             for (limbo_die_node *node = cu_die_list; node; node = node->next)
+               adjust_name_comp_dir (node->die);
+           }
        }
     }