diff mbox

DWARF5 .debug_line{,_str} support

Message ID 20161031183809.GK3541@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Oct. 31, 2016, 6:38 p.m. UTC
On Mon, Oct 31, 2016 at 11:25:26AM -0400, Jason Merrill wrote:
> 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?

Maybe.  Guess it needs to be decided in binutils and then we adjust
gcc if any changes are needed.

> >+      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.

I'll add a comment.  The reason is that DW_FORM_data1, if it can be used,
is always more compact than (or as compact as) DW_FORM_udata.  While the
choice in between DW_FORM_data2 and DW_FORM_udata if we have 256 to 65535
directories needs to be decided by computing both the size it would take
for all the uleb128s and compare that to the size it takes to encode all
as data2.

> >+	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.

Had a brief look at this, but it seems hard without big changes in
dwarf2asm.[ch] or lots of duplication.  The problem is that
dw2_asm_output_data* are varargs functions, so if we add some wrapper
that picks what to call based on a enum dwarf_form argument, we'd need to
convert all of them to take va_list instead, and add various further
wrappers.  Is this ok to leave this part out?

> >+      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.

So like
static void
output_line_string (enum dwarf_form form, const char *str,
                    const char *entry_kind, unsigned int idx)
in the patch below?

> >+  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.

Like DWARF5_USE_DEBUG_LINE_STR macro in the patch below?

For -gsplit-dwarf, the problem is I'm really not familiar with what tools
are used post assembly for this (and likely the tools need adjustment
for DWARF5 anyway), so what is in the patches is just partial support what
appeared to be easily done by myself.  For the rest I've been hoping Cary
or somebody else could finish it up.

	Jakub
2016-10-31  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.
	(DWARF5_USE_DEBUG_LINE_STR): Define.
	(output_line_string): New function.
	(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.

Comments

Jason Merrill Oct. 31, 2016, 6:45 p.m. UTC | #1
On 10/31/2016 02:38 PM, Jakub Jelinek wrote:
> On Mon, Oct 31, 2016 at 11:25:26AM -0400, Jason Merrill wrote:
>> 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?
>
> Maybe.  Guess it needs to be decided in binutils and then we adjust
> gcc if any changes are needed.
>
>>> +      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.
>
> I'll add a comment.  The reason is that DW_FORM_data1, if it can be used,
> is always more compact than (or as compact as) DW_FORM_udata.  While the
> choice in between DW_FORM_data2 and DW_FORM_udata if we have 256 to 65535
> directories needs to be decided by computing both the size it would take
> for all the uleb128s and compare that to the size it takes to encode all
> as data2.
>
>>> +	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.
>
> Had a brief look at this, but it seems hard without big changes in
> dwarf2asm.[ch] or lots of duplication.  The problem is that
> dw2_asm_output_data* are varargs functions, so if we add some wrapper
> that picks what to call based on a enum dwarf_form argument, we'd need to
> convert all of them to take va_list instead, and add various further
> wrappers.  Is this ok to leave this part out?
>
>>> +      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.
>
> So like
> static void
> output_line_string (enum dwarf_form form, const char *str,
>                     const char *entry_kind, unsigned int idx)
> in the patch below?
>
>>> +  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.
>
> Like DWARF5_USE_DEBUG_LINE_STR macro in the patch below?
>
> For -gsplit-dwarf, the problem is I'm really not familiar with what tools
> are used post assembly for this (and likely the tools need adjustment
> for DWARF5 anyway), so what is in the patches is just partial support what
> appeared to be easily done by myself.  For the rest I've been hoping Cary
> or somebody else could finish it up.

OK.

Jason
diff mbox

Patch

--- gcc/dwarf2out.c.jj	2016-10-31 18:18:09.446409870 +0100
+++ gcc/dwarf2out.c	2016-10-31 19:30:54.142262711 +0100
@@ -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.
@@ -3687,6 +3690,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
@@ -4266,7 +4272,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;
@@ -4310,7 +4318,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);
@@ -8824,10 +8832,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;
@@ -9820,6 +9828,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));
@@ -10652,6 +10665,15 @@  output_ranges (void)
     }
 }
 
+/* Non-zero if .debug_line_str should be used for .debug_line section
+   strings or strings that are likely shareable with those.  */
+#define DWARF5_USE_DEBUG_LINE_STR \
+  (!DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET		\
+   && (DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) != 0		\
+   /* FIXME: there is no .debug_line_str.dwo section,		\
+      for -gsplit-dwarf we should use DW_FORM_strx instead.  */	\
+   && !dwarf_split_debug_info)
+
 /* Data structure containing information about input files.  */
 struct file_info
 {
@@ -10764,6 +10786,37 @@  file_name_acquire (dwarf_file_data **slo
   return 1;
 }
 
+/* Helper function for output_file_names.  Emit a FORM encoded
+   string STR, with assembly comment start ENTRY_KIND and
+   index IDX */
+
+static void
+output_line_string (enum dwarf_form form, const char *str,
+		    const char *entry_kind, unsigned int idx)
+{
+  switch (form)
+    {
+    case DW_FORM_string:
+      dw2_asm_output_nstring (str, -1, "%s: %#x", entry_kind, idx);
+      break;
+    case DW_FORM_line_strp:
+      if (!debug_line_str_hash)
+	debug_line_str_hash
+	  = hash_table<indirect_string_hasher>::create_ggc (10);
+
+      struct indirect_string_node *node;
+      node = find_AT_string_in_table (str, debug_line_str_hash);
+      set_indirect_string (node);
+      node->form = form;
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+			     debug_line_str_section, "%s: %#x: \"%s\"",
+			     entry_kind, 0, node->str);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Output the directory table and the file name table.  We try to minimize
    the total amount of memory needed.  A heuristic is used to avoid large
    slowdowns with many input files.  */
@@ -10784,8 +10837,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;
     }
 
@@ -10908,13 +10971,52 @@  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;
+  if (dwarf_version >= 5)
+    {
+      const char *comp_dir = comp_dir_string ();
+      if (comp_dir == NULL)
+	comp_dir = "";
+      dw2_asm_output_data (1, 1, "Directory entry format count");
+      if (DWARF5_USE_DEBUG_LINE_STR)
+	str_form = DW_FORM_line_strp;
+      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
+	{
+	  output_line_string (str_form, comp_dir, "Directory Entry", 0);
+	  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);
+	      output_line_string (str_form, str, "Directory Entry",
+				  (unsigned) i + idx_offset);
+	    }
+	}
+    }
+  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
@@ -10923,6 +11025,70 @@  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 = "";
+      /* DW_LNCT_directory_index can use DW_FORM_udata, DW_FORM_data1 and
+	 DW_FORM_data2.  Choose one based on the number of directories
+	 and how much space would they occupy in each encoding.
+	 If we have at most 256 directories, all indexes fit into
+	 a single byte, so DW_FORM_data1 is most compact (if there
+	 are at most 128 directories, DW_FORM_udata would be as
+	 compact as that, but not shorter and slower to decode).  */
+      if (ndirs + idx_offset <= 256)
+	idx_form = DW_FORM_data1;
+      /* If there are more than 65536 directories, we have to use
+	 DW_FORM_udata, DW_FORM_data2 can't refer to them.
+	 Otherwise, compute what space would occupy if all the indexes
+	 used DW_FORM_udata - sum - and compare that to how large would
+	 be DW_FORM_data2 encoding, and pick the more efficient one.  */
+      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");
+
+      output_line_string (str_form, filename0, "File Entry", 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++)
     {
@@ -10938,38 +11104,47 @@  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);
+      output_line_string (str_form, filebuf, "File Entry", (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);
+      output_line_string (str_form,
+			  files[file_idx].path + dirs[dir_idx].length,
+			  "File Entry", (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);
@@ -10979,7 +11154,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");
 }
 
 
@@ -11103,8 +11279,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;
 
@@ -11124,7 +11298,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);
 
@@ -11138,7 +11317,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,
@@ -26080,6 +26259,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,
@@ -26254,12 +26437,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);
@@ -26275,13 +26458,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
@@ -28630,6 +28815,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
@@ -28653,6 +28845,34 @@  dwarf2out_early_finish (const char *file
   add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
   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
+      && DWARF5_USE_DEBUG_LINE_STR)
+    {
+      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)
@@ -28758,12 +28978,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;