diff mbox

DWARF5 .debug_line{,_str} support

Message ID 20161019233039.GR7282@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Oct. 19, 2016, 11:30 p.m. UTC
Hi!

This patch adds support for DWARF5 .debug_line{,_str} section format,
though only if !DWARF2_ASM_LINE_DEBUG_INFO, because otherwise
.debug_line is emitted by the assembler.  For that we'll need some
coordination with gas, dunno if we want a new as directive for that,
or as command line switch, or perhaps key DWARF5 .debug_line on the
presence of .debug_line_str section (though the last one probably isn't a
good idea, because -gsplit-dwarf doesn't use .debug_line_str).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-10-20  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2out.c (debug_line_str_section): New variable.
	(debug_line_str_hash): Likewise.
	(DEBUG_LINE_STR_SECTION): Define.
	(set_indirect_string): Handle DW_FORM_line_strp like
	DW_FORM_strp.
	(find_string_form): Fix up formatting.
	(size_of_die): Handle DW_FORM_line_strp like DW_FORM_strp.
	Fix up indentation.
	(output_die): Handle DW_FORM_line_strp.
	(output_file_names): Add -gdwarf-5 support.
	(output_line_info): Likewise.
	(init_sections_and_labels): Initialize debug_line_str_section.
	(output_indirect_string): Change 2nd argument from void *
	to enum dwarf_form form, compare with form rather than
	DW_FORM_strp.
	(output_indirect_strings): Pass DW_FORM_strp to
	output_indirect_string traversion.
	(dwarf2out_finish): Output .debug_line_str strings.
	(dwarf2out_c_finalize): Clear debug_line_str_section and
	debug_line_str_hash.


	Jakub

Comments

Jason Merrill Oct. 31, 2016, 3:25 p.m. UTC | #1
On 10/19/2016 07:30 PM, Jakub Jelinek wrote:
> This patch adds support for DWARF5 .debug_line{,_str} section format,
> though only if !DWARF2_ASM_LINE_DEBUG_INFO, because otherwise
> .debug_line is emitted by the assembler.  For that we'll need some
> coordination with gas, dunno if we want a new as directive for that,
> or as command line switch, or perhaps key DWARF5 .debug_line on the
> presence of .debug_line_str section (though the last one probably isn't a
> good idea, because -gsplit-dwarf doesn't use .debug_line_str).

Could gas pay attention to the DWARF version in a unit header?

> +      if (ndirs + idx_offset <= 256)
> +	idx_form = DW_FORM_data1;
> +      else if (ndirs + idx_offset <= 65536)
> +	{
> +	  unsigned HOST_WIDE_INT sum = 1;
> +	  for (i = 0; i < numfiles; i++)
> +	    {
> +	      int file_idx = backmap[i];
> +	      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
> +	      sum += size_of_uleb128 (dir_idx);
> +	    }
> +	  if (sum >= HOST_WIDE_INT_UC (2) * (numfiles + 1))
> +	    idx_form = DW_FORM_data2;
> +	}

Why can we choose DW_FORM_data1 based only on ndirs+idx_offset, but we 
need to look at the files table to choose DW_FORM_data2?  This at least 
needs a comment.

> +	dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
> +			     0, NULL);

It seems that we could use an output_data function that takes a DW_FORM 
as one of its arguments and does the appropriate thing.

> +      if (dwarf_version >= 5 && str_form == DW_FORM_line_strp)
> +	{
> +	  node = find_AT_string_in_table (filename0, debug_line_str_hash);
> +	  set_indirect_string (node);
> +	  node->form = DW_FORM_line_strp;
> +	  dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
> +				 debug_line_str_section,
> +				 "File Entry: %#x: \"%s\"", 0, node->str);
> +	}
> +      else
> +	dw2_asm_output_nstring (filename0, -1, "File Entry: %#x", 0);

Please factor this out into a separate function.

> +  if (!DWARF2_ASM_LINE_DEBUG_INFO
> +      && dwarf_version >= 5
> +      && !(DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
> +	   || (DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
> +	      /* FIXME: For now.  */
> +	   || dwarf_split_debug_info))

This should also be a separate function or macro, since it's used more 
than once.  And please elaborate the FIXME comment.

Jason
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2016-10-18 08:17:19.000000000 +0200
+++ gcc/dwarf2out.c	2016-10-19 14:37:23.945841924 +0200
@@ -167,6 +167,7 @@  static GTY(()) section *debug_loc_sectio
 static GTY(()) section *debug_pubnames_section;
 static GTY(()) section *debug_pubtypes_section;
 static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_line_str_section;
 static GTY(()) section *debug_str_dwo_section;
 static GTY(()) section *debug_str_offsets_section;
 static GTY(()) section *debug_ranges_section;
@@ -225,6 +226,8 @@  struct indirect_string_hasher : ggc_ptr_
 
 static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
 
+static GTY (()) hash_table<indirect_string_hasher> *debug_line_str_hash;
+
 /* With split_debug_info, both the comp_dir and dwo_name go in the
    main object file, rather than the dwo, similar to the force_direct
    parameter elsewhere but with additional complications:
@@ -232,8 +235,8 @@  static GTY (()) hash_table<indirect_stri
    1) The string is needed in both the main object file and the dwo.
    That is, the comp_dir and dwo_name will appear in both places.
 
-   2) Strings can use three forms: DW_FORM_string, DW_FORM_strp or
-   DW_FORM_GNU_str_index.
+   2) Strings can use four forms: DW_FORM_string, DW_FORM_strp,
+   DW_FORM_line_strp or DW_FORM_GNU_str_index.
 
    3) GCC chooses the form to use late, depending on the size and
    reference count.
@@ -3554,6 +3557,9 @@  new_addr_loc_descr (rtx addr, enum dtpre
 #ifndef DEBUG_RANGES_SECTION
 #define DEBUG_RANGES_SECTION	".debug_ranges"
 #endif
+#ifndef DEBUG_LINE_STR_SECTION
+#define DEBUG_LINE_STR_SECTION  ".debug_line_str"
+#endif
 
 /* Standard ELF section names for compiled code and data.  */
 #ifndef TEXT_SECTION_NAME
@@ -4131,7 +4137,9 @@  set_indirect_string (struct indirect_str
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
   /* Already indirect is a no op.  */
-  if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+  if (node->form == DW_FORM_strp
+      || node->form == DW_FORM_line_strp
+      || node->form == DW_FORM_GNU_str_index)
     {
       gcc_assert (node->label);
       return;
@@ -4175,7 +4183,7 @@  find_string_form (struct indirect_string
      single module.  */
   if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
       || ((debug_str_section->common.flags & SECTION_MERGE) == 0
-      && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
+	  && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
     return node->form = DW_FORM_string;
 
   set_indirect_string (node);
@@ -8500,10 +8508,10 @@  size_of_die (dw_die_ref die)
 	  break;
 	case dw_val_class_str:
           form = AT_string_form (a);
-          if (form == DW_FORM_strp)
+	  if (form == DW_FORM_strp || form == DW_FORM_line_strp)
 	    size += DWARF_OFFSET_SIZE;
-         else if (form == DW_FORM_GNU_str_index)
-            size += size_of_uleb128 (AT_index (a));
+	  else if (form == DW_FORM_GNU_str_index)
+	    size += size_of_uleb128 (AT_index (a));
 	  else
 	    size += strlen (a->dw_attr_val.v.val_str->str) + 1;
 	  break;
@@ -9458,6 +9466,11 @@  output_die (dw_die_ref die)
                                    a->dw_attr_val.v.val_str->label,
                                    debug_str_section,
                                    "%s: \"%s\"", name, AT_string (a));
+	  else if (a->dw_attr_val.v.val_str->form == DW_FORM_line_strp)
+	    dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+				   a->dw_attr_val.v.val_str->label,
+				   debug_line_str_section,
+				   "%s: \"%s\"", name, AT_string (a));
           else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
             dw2_asm_output_data_uleb128 (AT_index (a),
                                          "%s: \"%s\"", name, AT_string (a));
@@ -10429,8 +10442,18 @@  output_file_names (void)
 
   if (!last_emitted_file)
     {
-      dw2_asm_output_data (1, 0, "End directory table");
-      dw2_asm_output_data (1, 0, "End file name table");
+      if (dwarf_version >= 5)
+	{
+	  dw2_asm_output_data (1, 0, "Directory entry format count");
+	  dw2_asm_output_data_uleb128 (0, "Directories count");
+	  dw2_asm_output_data (1, 0, "File name entry format count");
+	  dw2_asm_output_data_uleb128 (0, "File names count");
+	}
+      else
+	{
+	  dw2_asm_output_data (1, 0, "End directory table");
+	  dw2_asm_output_data (1, 0, "End file name table");
+	}
       return;
     }
 
@@ -10553,13 +10576,71 @@  output_file_names (void)
 
   /* Emit the directory name table.  */
   idx_offset = dirs[0].length > 0 ? 1 : 0;
-  for (i = 1 - idx_offset; i < ndirs; i++)
-    dw2_asm_output_nstring (dirs[i].path,
-			    dirs[i].length
-			     - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
-			    "Directory Entry: %#x", i + idx_offset);
+  enum dwarf_form str_form = DW_FORM_string;
+  enum dwarf_form idx_form = DW_FORM_udata;
+  struct indirect_string_node *node;
+  if (dwarf_version >= 5)
+    {
+      const char *comp_dir = comp_dir_string ();
+      if (comp_dir == NULL)
+	comp_dir = "";
+      str_form = DW_FORM_line_strp;
+      dw2_asm_output_data (1, 1, "Directory entry format count");
+      if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+	  || (debug_str_section->common.flags & SECTION_MERGE) == 0
+	  /* FIXME: For now.  */
+	  || dwarf_split_debug_info)
+	str_form = DW_FORM_string;
+      dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path");
+      dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form));
+      dw2_asm_output_data_uleb128 (ndirs + idx_offset, "Directories count");
+      if (str_form == DW_FORM_string)
+	{
+	  dw2_asm_output_nstring (comp_dir, -1, "Directory Entry: %#x", 0);
+	  for (i = 1 - idx_offset; i < ndirs; i++)
+	    dw2_asm_output_nstring (dirs[i].path,
+				    dirs[i].length
+				    - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+				    "Directory Entry: %#x", i + idx_offset);
+	}
+      else
+	{
+	  if (!debug_line_str_hash)
+	    debug_line_str_hash
+	      = hash_table<indirect_string_hasher>::create_ggc (10);
+
+	  node = find_AT_string_in_table (comp_dir, debug_line_str_hash);
+	  set_indirect_string (node);
+	  node->form = DW_FORM_line_strp;
+	  dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+				 debug_line_str_section,
+				 "Directory Entry: %#x: \"%s\"", 0, node->str);
+	  for (i = 1 - idx_offset; i < ndirs; i++)
+	    {
+	      const char *str
+		= ggc_alloc_string (dirs[i].path,
+				    dirs[i].length
+				    - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR);
+	      node = find_AT_string_in_table (str, debug_line_str_hash);
+	      set_indirect_string (node);
+	      node->form = DW_FORM_line_strp;
+	      dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+				     debug_line_str_section,
+				     "Directory Entry: %#x: \"%s\"",
+				     i + idx_offset, node->str);
+	    }
+	}
+    }
+  else
+    {
+      for (i = 1 - idx_offset; i < ndirs; i++)
+	dw2_asm_output_nstring (dirs[i].path,
+				dirs[i].length
+				- !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+				"Directory Entry: %#x", i + idx_offset);
 
-  dw2_asm_output_data (1, 0, "End directory table");
+      dw2_asm_output_data (1, 0, "End directory table");
+    }
 
   /* We have to emit them in the order of emitted_number since that's
      used in the debug info generation.  To do this efficiently we
@@ -10568,6 +10649,68 @@  output_file_names (void)
   for (i = 0; i < numfiles; i++)
     backmap[files[i].file_idx->emitted_number - 1] = i;
 
+  if (dwarf_version >= 5)
+    {
+      const char *filename0 = get_AT_string (comp_unit_die (), DW_AT_name);
+      if (filename0 == NULL)
+	filename0 = "";
+      if (ndirs + idx_offset <= 256)
+	idx_form = DW_FORM_data1;
+      else if (ndirs + idx_offset <= 65536)
+	{
+	  unsigned HOST_WIDE_INT sum = 1;
+	  for (i = 0; i < numfiles; i++)
+	    {
+	      int file_idx = backmap[i];
+	      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+	      sum += size_of_uleb128 (dir_idx);
+	    }
+	  if (sum >= HOST_WIDE_INT_UC (2) * (numfiles + 1))
+	    idx_form = DW_FORM_data2;
+	}
+#ifdef VMS_DEBUGGING_INFO
+      dw2_asm_output_data (1, 4, "File name entry format count");
+#else
+      dw2_asm_output_data (1, 2, "File name entry format count");
+#endif
+      dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path");
+      dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form));
+      dw2_asm_output_data_uleb128 (DW_LNCT_directory_index,
+				   "DW_LNCT_directory_index");
+      dw2_asm_output_data_uleb128 (idx_form, get_DW_FORM_name (idx_form));
+#ifdef VMS_DEBUGGING_INFO
+      dw2_asm_output_data_uleb128 (DW_LNCT_timestamp, "DW_LNCT_timestamp");
+      dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata");
+      dw2_asm_output_data_uleb128 (DW_LNCT_size, "DW_LNCT_size");
+      dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata");
+#endif
+      dw2_asm_output_data_uleb128 (numfiles + 1, "File names count");
+
+      if (dwarf_version >= 5 && str_form == DW_FORM_line_strp)
+	{
+	  node = find_AT_string_in_table (filename0, debug_line_str_hash);
+	  set_indirect_string (node);
+	  node->form = DW_FORM_line_strp;
+	  dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+				 debug_line_str_section,
+				 "File Entry: %#x: \"%s\"", 0, node->str);
+	}
+      else
+	dw2_asm_output_nstring (filename0, -1, "File Entry: %#x", 0);
+
+      /* Include directory index.  */
+      if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+	dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+			     0, NULL);
+      else
+	dw2_asm_output_data_uleb128 (0, NULL);
+
+#ifdef VMS_DEBUGGING_INFO
+      dw2_asm_output_data_uleb128 (0, NULL);
+      dw2_asm_output_data_uleb128 (0, NULL);
+#endif
+    }
+
   /* Now write all the file names.  */
   for (i = 0; i < numfiles; i++)
     {
@@ -10583,38 +10726,71 @@  output_file_names (void)
       int ver;
       long long cdt;
       long siz;
-      int maxfilelen = strlen (files[file_idx].path)
-			       + dirs[dir_idx].length
-			       + MAX_VMS_VERSION_LEN + 1;
+      int maxfilelen = (strlen (files[file_idx].path)
+			+ dirs[dir_idx].length
+			+ MAX_VMS_VERSION_LEN + 1);
       char *filebuf = XALLOCAVEC (char, maxfilelen);
 
       vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
       snprintf (filebuf, maxfilelen, "%s;%d",
 	        files[file_idx].path + dirs[dir_idx].length, ver);
 
-      dw2_asm_output_nstring
-	(filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
+      if (dwarf_version >= 5 && str_form == DW_FORM_line_strp)
+	{
+	  node = find_AT_string_in_table (filebuf, debug_line_str_hash);
+	  set_indirect_string (node);
+	  node->form = DW_FORM_line_strp;
+	  dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+				 debug_line_str_section,
+				 "File Entry: %#x: \"%s\"", (unsigned) i + 1,
+				 node->str);
+	}
+      else
+	dw2_asm_output_nstring (filebuf, -1, "File Entry: %#x",
+				(unsigned) i + 1);
 
       /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+      if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+	dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+			     dir_idx + idx_offset, NULL);
+      else
+	dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
 
       /* Modification time.  */
-      dw2_asm_output_data_uleb128
-        ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
-	  ? cdt : 0,
-	 NULL);
+      dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path,
+							 &cdt, 0, 0, 0) == 0)
+				   ? cdt : 0, NULL);
 
       /* File length in bytes.  */
-      dw2_asm_output_data_uleb128
-        ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
-      	  ? siz : 0,
-	 NULL);
+      dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path,
+							 0, &siz, 0, 0) == 0)
+				   ? siz : 0, NULL);
 #else
-      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-			      "File Entry: %#x", (unsigned) i + 1);
+      if (dwarf_version >= 5 && str_form == DW_FORM_line_strp)
+	{
+	  node = find_AT_string_in_table (files[file_idx].path
+					  + dirs[dir_idx].length,
+					  debug_line_str_hash);
+	  set_indirect_string (node);
+	  node->form = DW_FORM_line_strp;
+	  dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+				 debug_line_str_section,
+				 "File Entry: %#x: \"%s\"", (unsigned) i + 1,
+				 node->str);
+	}
+      else
+	dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length,
+				-1, "File Entry: %#x", (unsigned) i + 1);
 
       /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+      if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+	dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+			     dir_idx + idx_offset, NULL);
+      else
+	dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+      if (dwarf_version >= 5)
+	continue;
 
       /* Modification time.  */
       dw2_asm_output_data_uleb128 (0, NULL);
@@ -10624,7 +10800,8 @@  output_file_names (void)
 #endif /* VMS_DEBUGGING_INFO */
     }
 
-  dw2_asm_output_data (1, 0, "End file name table");
+  if (dwarf_version < 5)
+    dw2_asm_output_data (1, 0, "End file name table");
 }
 
 
@@ -10748,8 +10925,6 @@  output_line_info (bool prologue_only)
   static unsigned int generation;
   char l1[MAX_ARTIFICIAL_LABEL_BYTES], l2[MAX_ARTIFICIAL_LABEL_BYTES];
   char p1[MAX_ARTIFICIAL_LABEL_BYTES], p2[MAX_ARTIFICIAL_LABEL_BYTES];
-  /* We don't support DWARFv5 line tables yet.  */
-  int ver = dwarf_version < 5 ? dwarf_version : 4;
   bool saw_one = false;
   int opc;
 
@@ -10769,7 +10944,12 @@  output_line_info (bool prologue_only)
 
   ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  dw2_asm_output_data (2, ver, "DWARF Version");
+  dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+  if (dwarf_version >= 5)
+    {
+      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
+      dw2_asm_output_data (1, 0, "Segment Size");
+    }
   dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
   ASM_OUTPUT_LABEL (asm_out_file, p1);
 
@@ -10783,7 +10963,7 @@  output_line_info (bool prologue_only)
      and don't let the target override.  */
   dw2_asm_output_data (1, 1, "Minimum Instruction Length");
 
-  if (ver >= 4)
+  if (dwarf_version >= 4)
     dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
 			 "Maximum Operations Per Instruction");
   dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
@@ -25686,6 +25866,10 @@  init_sections_and_labels (void)
 					SECTION_DEBUG, NULL);
   debug_str_section = get_section (DEBUG_STR_SECTION,
 				   DEBUG_STR_SECTION_FLAGS, NULL);
+  if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+    debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
+					  DEBUG_STR_SECTION_FLAGS, NULL);
+
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
 				      SECTION_DEBUG, NULL);
   debug_frame_section = get_section (DEBUG_FRAME_SECTION,
@@ -25862,12 +26046,12 @@  output_index_string (indirect_string_nod
    htab_traverse.  Emit one queued .debug_str string.  */
 
 int
-output_indirect_string (indirect_string_node **h, void *)
+output_indirect_string (indirect_string_node **h, enum dwarf_form form)
 {
   struct indirect_string_node *node = *h;
 
   node->form = find_string_form (node);
-  if (node->form == DW_FORM_strp && node->refcount > 0)
+  if (node->form == form && node->refcount > 0)
     {
       ASM_OUTPUT_LABEL (asm_out_file, node->label);
       assemble_string (node->str, strlen (node->str) + 1);
@@ -25883,13 +26067,15 @@  output_indirect_strings (void)
 {
   switch_to_section (debug_str_section);
   if (!dwarf_split_debug_info)
-    debug_str_hash->traverse<void *, output_indirect_string> (NULL);
+    debug_str_hash->traverse<enum dwarf_form,
+			     output_indirect_string> (DW_FORM_strp);
   else
     {
       unsigned int offset = 0;
       unsigned int cur_idx = 0;
 
-      skeleton_debug_str_hash->traverse<void *, output_indirect_string> (NULL);
+      skeleton_debug_str_hash->traverse<enum dwarf_form,
+					output_indirect_string> (DW_FORM_strp);
 
       switch_to_section (debug_str_offsets_section);
       debug_str_hash->traverse_noresize
@@ -28209,6 +28395,13 @@  dwarf2out_finish (const char *)
   /* If we emitted any indirect strings, output the string table too.  */
   if (debug_str_hash || skeleton_debug_str_hash)
     output_indirect_strings ();
+  if (debug_line_str_hash)
+    {
+      switch_to_section (debug_line_str_section);
+      const enum dwarf_form form = DW_FORM_line_strp;
+      debug_line_str_hash->traverse<enum dwarf_form,
+				    output_indirect_string> (form);
+    }
 }
 
 /* Perform any cleanups needed after the early debug generation pass
@@ -28240,6 +28433,37 @@  dwarf2out_early_finish (const char *file
 	add_comp_dir_attribute (comp_unit_die ());
     }
 
+  /* When emitting DWARF5 .debug_line_str, move DW_AT_name and
+     DW_AT_comp_dir into .debug_line_str section.  */
+  if (!DWARF2_ASM_LINE_DEBUG_INFO
+      && dwarf_version >= 5
+      && !(DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+	   || (DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
+	      /* FIXME: For now.  */
+	   || dwarf_split_debug_info))
+    {
+      for (int i = 0; i < 2; i++)
+	{
+	  dw_attr_node *a = get_AT (comp_unit_die (),
+				    i ? DW_AT_comp_dir : DW_AT_name);
+	  if (a == NULL
+	      || AT_class (a) != dw_val_class_str
+	      || strlen (AT_string (a)) + 1 <= DWARF_OFFSET_SIZE)
+	    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 (AT_string (a), debug_line_str_hash);
+	  set_indirect_string (node);
+	  node->form = DW_FORM_line_strp;
+	  a->dw_attr_val.v.val_str->refcount--;
+	  a->dw_attr_val.v.val_str = node;
+	}
+    }
+
   /* With LTO early dwarf was really finished at compile-time, so make
      sure to adjust the phase after annotating the LTRANS CU DIE.  */
   if (in_lto_p)
@@ -28345,12 +28569,14 @@  dwarf2out_c_finalize (void)
   debug_pubnames_section = NULL;
   debug_pubtypes_section = NULL;
   debug_str_section = NULL;
+  debug_line_str_section = NULL;
   debug_str_dwo_section = NULL;
   debug_str_offsets_section = NULL;
   debug_ranges_section = NULL;
   debug_frame_section = NULL;
   fde_vec = NULL;
   debug_str_hash = NULL;
+  debug_line_str_hash = NULL;
   skeleton_debug_str_hash = NULL;
   dw2_string_counter = 0;
   have_multiple_function_sections = false;