Testcase a.i: # 0 "a.c" # 1 "/var/tmp//" # 0 "<built-in>" # 0 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 0 "<command-line>" 2 # 1 "a.c" # 1 "a.h" 1 int foo (void) { return 0; } # 2 "a.c" 2 int bar (void) { return 0; } With gcc configured against latest binutils: gcc -S -g -flto -ffat-lto-objects a.i gcc -c a.s -o a.o strip -p -R .gnu.lto_* -R .gnu.debuglto_* -N __gnu_lto_v1 a.o strip: st3FEz69: symbol `.gnu.debuglto_.debug_line_str' required but not present strip: st3FEz69: no symbols
Seems to be a gcc bug to me: .section .gnu.debuglto_.debug_info,"e",@progbits ... .long .LASF0 # DW_AT_name: "a.c" .long .LASF1 # DW_AT_comp_dir: "/var/tmp" .long .Ldebug_line0 # DW_AT_stmt_list ... .section .gnu.debuglto_.debug_line,"e",@progbits .Ldebug_line0: ... .uleb128 0x3 # File names count .long .LASF0 # File Entry: 0: "a.c" .byte 0 .long .LASF0 # File Entry: 0: "a.c" .byte 0 ... .section .gnu.debuglto_.debug_line_str,"eMS",@progbits,1 .LASF0: .string "a.c" ... .section .debug_info,"",@progbits .Ldebug_info1: .long .LASF0 # DW_AT_name: "a.c" .long .LASF1 # DW_AT_comp_dir: "/var/tmp" .quad .Ltext0 # DW_AT_low_pc .quad .Letext0-.Ltext0 # DW_AT_high_pc .long .Ldebug_line1 # DW_AT_stmt_list The references in .debug_info to .LASF0/.LASF1 labels from .gnu.debuglto_.debug_line_str is what is incorrect.
--- gcc/dwarf2out.c.jj 2021-01-20 08:32:09.612958930 +0100 +++ gcc/dwarf2out.c 2021-01-20 13:49:42.367772872 +0100 @@ -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; fixes it but the string is then emitted into .debug_str rather than .debug_line_str in the non-.gnu.debuglto_* case.
--- gcc/dwarf2out.c.jj 2021-01-20 08:32:09.612958930 +0100 +++ gcc/dwarf2out.c 2021-01-20 14:15:14.735459774 +0100 @@ -4733,12 +4733,20 @@ 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)) { + bool line_strp = node->form == DW_FORM_line_strp; free (node->label); node->label = NULL; node->form = (dwarf_form) 0; node->index = 0; + if (line_strp) + { + set_indirect_string (node); + node->form = DW_FORM_line_strp; + } } return 1; } @@ -31395,10 +31403,7 @@ dwarf2out_finish (const char *filename) /* Remove indirect string decisions. */ debug_str_hash->traverse<void *, reset_indirect_string> (NULL); if (debug_line_str_hash) - { - debug_line_str_hash->traverse<void *, reset_indirect_string> (NULL); - debug_line_str_hash = NULL; - } + debug_line_str_hash->traverse<void *, reset_indirect_string> (NULL); } #if ENABLE_ASSERT_CHECKING emits them in .debug_line_str, but emits also strings that aren't really needed.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:27c792895bd809115c1f70672835b7fdff74d318 commit r11-6820-g27c792895bd809115c1f70672835b7fdff74d318 Author: Jakub Jelinek <jakub@redhat.com> Date: Wed Jan 20 18:51:04 2021 +0100 debug: Fix up DWARF 5 -g -flto -ffat-lto-objects [PR98765] 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.
Fixed.