MIPS/GAS: Use FCSR rather than RA with CFC1/CTC1
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index ac0ee201f25cd7e2d22ee2dd5f58798d8497ce98..460daaa5c0c38bf02e7e093def81ae19d09fe3d5 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf2dbg.c - DWARF2 debug support
-   Copyright (C) 1999-2020 Free Software Foundation, Inc.
+   Copyright (C) 1999-2021 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
 
 #include "as.h"
 #include "safe-ctype.h"
-
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#else
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifndef INT_MAX
-#define INT_MAX (int) (((unsigned) (-1)) >> 1)
-#endif
-#endif
-
 #include "dwarf2dbg.h"
 #include <filenames.h>
 
@@ -211,7 +200,6 @@ struct file_entry
 {
   const char *   filename;
   unsigned int   dir;
-  bfd_boolean    auto_assigned;
   unsigned char  md5[NUM_MD5_BYTES];
 };
 
@@ -219,6 +207,7 @@ struct file_entry
 static struct file_entry *files;
 static unsigned int files_in_use;
 static unsigned int files_allocated;
+static unsigned int num_of_auto_assigned;
 
 /* Table of directories used by .debug_line.  */
 static char **       dirs = NULL;
@@ -226,12 +215,18 @@ static unsigned int  dirs_in_use = 0;
 static unsigned int  dirs_allocated = 0;
 
 /* TRUE when we've seen a .loc directive recently.  Used to avoid
-   doing work when there's nothing to do.  */
-bfd_boolean dwarf2_loc_directive_seen;
+   doing work when there's nothing to do.  Will be reset by
+   dwarf2_consume_line_info.  */
+bool dwarf2_loc_directive_seen;
+
+/* TRUE when we've seen any .loc directive at any time during parsing.
+   Indicates the user wants us to generate a .debug_line section.
+   Used in dwarf2_finish as sanity check.  */
+static bool dwarf2_any_loc_directive_seen;
 
 /* TRUE when we're supposed to set the basic block mark whenever a
    label is seen.  */
-bfd_boolean dwarf2_loc_mark_labels;
+bool dwarf2_loc_mark_labels;
 
 /* Current location as indicated by the most recent .loc directive.  */
 static struct dwarf2_line_info current =
@@ -273,7 +268,7 @@ generic_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
 /* Find or create (if CREATE_P) an entry for SEG+SUBSEG in ALL_SEGS.  */
 
 static struct line_subseg *
-get_line_subseg (segT seg, subsegT subseg, bfd_boolean create_p)
+get_line_subseg (segT seg, subsegT subseg, bool create_p)
 {
   struct line_seg *s = seg_info (seg)->dwarf2_line_seg;
   struct line_subseg **pss, *lss;
@@ -498,13 +493,28 @@ dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
 {
   struct line_subseg *lss;
   struct line_entry *e;
+  flagword need_flags = SEC_LOAD | SEC_CODE;
+
+  /* PR 26850: Do not record LOCs in non-executable or non-loaded
+     sections.  SEC_ALLOC isn't tested for non-ELF because obj-coff.c
+     obj_coff_section is careless in setting SEC_ALLOC.  */
+  if (IS_ELF)
+    need_flags |= SEC_ALLOC;
+  if ((now_seg->flags & need_flags) != need_flags)
+    {
+      /* FIXME: Add code to suppress multiple warnings ?  */
+      if (debug_type != DEBUG_DWARF2)
+       as_warn ("dwarf line number information for %s ignored",
+                segment_name (now_seg));
+      return;
+    }
 
   e = XNEW (struct line_entry);
   e->next = NULL;
   e->label = label;
   e->loc = *loc;
 
-  lss = get_line_subseg (now_seg, now_subseg, TRUE);
+  lss = get_line_subseg (now_seg, now_subseg, true);
 
   /* Subseg heads are chained to previous subsegs in
      dwarf2_finish.  */
@@ -530,8 +540,13 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc)
   /* Early out for as-yet incomplete location information.  */
   if (loc->line == 0)
     return;
-  if (loc->filenum == 0 && DWARF2_LINE_VERSION < 5)
-    return;
+  if (loc->filenum == 0)
+    {
+      if (dwarf_level < 5)
+       dwarf_level = 5;
+      if (DWARF2_LINE_VERSION < 5)
+       return;
+    }
 
   /* Don't emit sequences of line symbols for the same line when the
      symbols apply to assembler code.  It is necessary to emit
@@ -576,9 +591,9 @@ get_basename (const char * pathname)
 }
 
 static unsigned int
-get_directory_table_entry (const char *  dirname,
-                          size_t        dirlen,
-                          bfd_boolean   can_use_zero)
+get_directory_table_entry (const char *dirname,
+                          size_t dirlen,
+                          bool can_use_zero)
 {
   unsigned int d;
 
@@ -626,8 +641,8 @@ get_directory_table_entry (const char *  dirname,
   return d;  
 }
 
-static bfd_boolean
-assign_file_to_slot (unsigned long i, const char *file, unsigned int dir, bfd_boolean auto_assign)
+static bool
+assign_file_to_slot (unsigned long i, const char *file, unsigned int dir)
 {
   if (i >= files_allocated)
     {
@@ -638,7 +653,7 @@ assign_file_to_slot (unsigned long i, const char *file, unsigned int dir, bfd_bo
       if (files_allocated <= old)
        {
          as_bad (_("file number %lu is too big"), (unsigned long) i);
-         return FALSE;
+         return false;
        }
 
       files = XRESIZEVEC (struct file_entry, files, files_allocated);
@@ -647,13 +662,12 @@ assign_file_to_slot (unsigned long i, const char *file, unsigned int dir, bfd_bo
 
   files[i].filename = file;
   files[i].dir = dir;
-  files[i].auto_assigned = auto_assign;
   memset (files[i].md5, 0, NUM_MD5_BYTES);
 
   if (files_in_use < i + 1)
     files_in_use = i + 1;
 
-  return TRUE;
+  return true;
 }
 
 /* Get a .debug_line file number for PATHNAME.  If there is a
@@ -697,7 +711,7 @@ allocate_filenum (const char * pathname)
   file = get_basename (pathname);
   dir_len = file - pathname;
 
-  dir = get_directory_table_entry (pathname, dir_len, FALSE);
+  dir = get_directory_table_entry (pathname, dir_len, false);
 
   /* Do not use slot-0.  That is specifically reserved for use by
      the '.file 0 "name"' directive.  */
@@ -711,9 +725,11 @@ allocate_filenum (const char * pathname)
        return i;
       }
 
-  if (!assign_file_to_slot (i, file, dir, TRUE))
+  if (!assign_file_to_slot (i, file, dir))
     return -1;
 
+  num_of_auto_assigned++;
+
   last_used = i;
   last_used_dir_len = dir_len;
 
@@ -726,11 +742,11 @@ allocate_filenum (const char * pathname)
    if WITH_MD5 is TRUE then there is a md5 value in generic_bignum.
    Returns TRUE if allocation succeeded, FALSE otherwise.  */
 
-static bfd_boolean
-allocate_filename_to_slot (const char *  dirname,
-                          const char *  filename,
-                          unsigned int  num,
-                          bfd_boolean   with_md5)
+static bool
+allocate_filename_to_slot (const char *dirname,
+                          const char *filename,
+                          unsigned int num,
+                          bool with_md5)
 {
   const char *file;
   size_t dirlen;
@@ -742,7 +758,7 @@ allocate_filename_to_slot (const char *  dirname,
     {
       const char * dir = NULL;
 
-      if (dirs)
+      if (dirs != NULL)
        dir = dirs[files[num].dir];
 
       if (with_md5
@@ -760,9 +776,17 @@ allocate_filename_to_slot (const char *  dirname,
          /* If the filenames match, but the directory table entry was
             empty, then fill it with the provided directory name.  */
          if (dir == NULL)
-           dirs[files[num].dir] = xmemdup0 (dirname, strlen (dirname));
+           {
+             if (dirs == NULL)
+               {
+                 dirs_allocated = files[num].dir + 32;
+                 dirs = XCNEWVEC (char *, dirs_allocated);
+               }
+             
+             dirs[files[num].dir] = xmemdup0 (dirname, strlen (dirname));
+           }
            
-         return TRUE;
+         return true;
        }
       else if (dir != NULL) 
        {
@@ -770,46 +794,39 @@ allocate_filename_to_slot (const char *  dirname,
          if (filename_ncmp (filename, dir, dirlen) == 0
              && IS_DIR_SEPARATOR (filename [dirlen])
              && filename_cmp (filename + dirlen + 1, files[num].filename) == 0)
-           return TRUE;
+           return true;
        }
       else /* dir == NULL  */
        {
          file = get_basename (filename);
          if (filename_cmp (file, files[num].filename) == 0)
            {
+             /* The filenames match, but the directory table entry is empty.
+                Fill it with the provided directory name.  */
              if (file > filename)
-               /* The filenames match, but the directory table entry is empty.
-                  Fill it with the provided directory name.  */
-               dirs[files[num].dir] = xmemdup0 (filename, file - filename);
-             return TRUE;
+               {
+                 if (dirs == NULL)
+                   {
+                     dirs_allocated = files[num].dir + 32;
+                     dirs = XCNEWVEC (char *, dirs_allocated);
+                   }
+
+                 dirs[files[num].dir] = xmemdup0 (filename, file - filename);
+               }
+             return true;
            }
        }
 
     fail:
-      /* If NUM was previously allocated automatically then
-        choose another slot for it, so that we can reuse NUM.  */
-      if (files[num].auto_assigned)
-       {
-         /* Find an unused slot.  */
-         for (i = 1; i < files_in_use; ++i)
-           if (files[i].filename == NULL)
-             break;
-         if (! assign_file_to_slot (i, files[num].filename, files[num].dir, TRUE))
-           return FALSE;
-         files[num].filename = NULL;
-       }
-      else
-       {
-         as_bad (_("file table slot %u is already occupied by a different file (%s%s%s vs %s%s%s)"),
-                 num,
-                 dir == NULL ? "" : dir,
-                 dir == NULL ? "" : "/",
-                 files[num].filename,
-                 dirname == NULL ? "" : dirname,
-                 dirname == NULL ? "" : "/",
-                 filename);
-         return FALSE;
-       }
+      as_bad (_("file table slot %u is already occupied by a different file (%s%s%s vs %s%s%s)"),
+             num,
+             dir == NULL ? "" : dir,
+             dir == NULL ? "" : "/",
+             files[num].filename,
+             dirname == NULL ? "" : dirname,
+             dirname == NULL ? "" : "/",
+             filename);
+      return false;
     }
 
   if (dirname == NULL)
@@ -827,8 +844,8 @@ allocate_filename_to_slot (const char *  dirname,
   d = get_directory_table_entry (dirname, dirlen, num == 0);
   i = num;
 
-  if (! assign_file_to_slot (i, file, d, FALSE))
-    return FALSE;
+  if (! assign_file_to_slot (i, file, d))
+    return false;
 
   if (with_md5)
     {
@@ -880,7 +897,7 @@ allocate_filename_to_slot (const char *  dirname,
   else
     memset (files[i].md5, 0, NUM_MD5_BYTES);
 
-  return TRUE;
+  return true;
 }
 
 /* Returns the current source information.  If .file directives have
@@ -953,7 +970,7 @@ dwarf2_move_insn (int delta)
   if (delta == 0)
     return;
 
-  lss = get_line_subseg (now_seg, now_subseg, FALSE);
+  lss = get_line_subseg (now_seg, now_subseg, false);
   if (!lss)
     return;
 
@@ -976,7 +993,7 @@ dwarf2_consume_line_info (void)
 {
   /* Unless we generate DWARF2 debugging information for each
      assembler line, we only emit one line symbol for one LOC.  */
-  dwarf2_loc_directive_seen = FALSE;
+  dwarf2_loc_directive_seen = false;
 
   current.flags &= ~(DWARF2_FLAG_BASIC_BLOCK
                     | DWARF2_FLAG_PROLOGUE_END
@@ -1019,11 +1036,12 @@ dwarf2_emit_label (symbolS *label)
 char *
 dwarf2_directive_filename (void)
 {
-  bfd_boolean with_md5 = FALSE;
+  bool with_md5 = false;
   valueT num;
   char *filename;
   const char * dirname = NULL;
   int filename_len;
+  unsigned int i;
 
   /* Continue to accept a bare string and pass it off.  */
   SKIP_WHITESPACE ();
@@ -1035,11 +1053,16 @@ dwarf2_directive_filename (void)
 
   num = get_absolute_expression ();
 
-  if ((offsetT) num < 1 && DWARF2_LINE_VERSION < 5)
+  if ((offsetT) num < 1)
     {
-      as_bad (_("file number less than one"));
-      ignore_rest_of_line ();
-      return NULL;
+      if (num == 0 && dwarf_level < 5)
+       dwarf_level = 5;
+      if ((offsetT) num < 0 || DWARF2_LINE_VERSION < 5)
+       {
+         as_bad (_("file number less than one"));
+         ignore_rest_of_line ();
+         return NULL;
+       }
     }
 
   /* FIXME: Should we allow ".file <N>\n" as an expression meaning
@@ -1063,7 +1086,7 @@ dwarf2_directive_filename (void)
          SKIP_WHITESPACE ();
        }
 
-      if (strncmp (input_line_pointer, "md5", 3) == 0)
+      if (startswith (input_line_pointer, "md5"))
        {
          input_line_pointer += 3;
          SKIP_WHITESPACE ();
@@ -1073,7 +1096,7 @@ dwarf2_directive_filename (void)
          if (exp.X_op != O_big)
            as_bad (_("md5 value too small or not a constant"));
          else
-           with_md5 = TRUE;
+           with_md5 = true;
        }
     }
 
@@ -1090,6 +1113,18 @@ dwarf2_directive_filename (void)
       return NULL;
     }
 
+  if (num_of_auto_assigned)
+    {
+      /* Clear slots auto-assigned before the first .file <NUMBER>
+        directive was seen.  */
+      if (files_in_use != (num_of_auto_assigned + 1))
+       abort ();
+      for (i = 1; i < files_in_use; i++)
+       files[i].filename = NULL;
+      files_in_use = 0;
+      num_of_auto_assigned = 0;
+    }
+
   if (! allocate_filename_to_slot (dirname, filename, (unsigned int) num,
                                   with_md5))
     return NULL;
@@ -1122,14 +1157,16 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
 
   if (filenum < 1)
     {
-      if (filenum != 0 || DWARF2_LINE_VERSION < 5)
+      if (filenum == 0 && dwarf_level < 5)
+       dwarf_level = 5;
+      if (filenum < 0 || DWARF2_LINE_VERSION < 5)
        {
          as_bad (_("file number less than one"));
          return;
        }
     }
 
-  if (filenum >= (int) files_in_use || files[filenum].filename == NULL)
+  if ((valueT) filenum >= files_in_use || files[filenum].filename == NULL)
     {
       as_bad (_("unassigned file number %ld"), (long) filenum);
       return;
@@ -1238,7 +1275,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
          if (ISDIGIT (*input_line_pointer)
              || *input_line_pointer == '-')
            {
-             bfd_boolean force_reset = *input_line_pointer == '-';
+             bool force_reset = *input_line_pointer == '-';
 
              value = get_absolute_expression ();
              if (value != 0)
@@ -1290,7 +1327,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
     }
 
   demand_empty_rest_of_line ();
-  dwarf2_loc_directive_seen = TRUE;
+  dwarf2_any_loc_directive_seen = dwarf2_loc_directive_seen = true;
   debug_type = DEBUG_NONE;
 
   /* If we were given a view id, emit the row right away.  */
@@ -1861,13 +1898,13 @@ process_entries (segT seg, struct line_entry *e)
       if (strcmp (sec_name, ".text") != 0)
        {
          name = concat (".debug_line", sec_name, (char *) NULL);
-         subseg_set (subseg_get (name, FALSE), 0);
+         subseg_set (subseg_get (name, false), 0);
        }
       else
        /* Don't create a .debug_line.text section -
           that is redundant.  Instead just switch back to the
           normal .debug_line section.  */
-       subseg_set (subseg_get (".debug_line", FALSE), 0);
+       subseg_set (subseg_get (".debug_line", false), 0);
     }
 
   do
@@ -1972,18 +2009,42 @@ process_entries (segT seg, struct line_entry *e)
     }
 }
 
+/* Switch to LINE_STR_SEG and output the given STR.  Return the
+   symbol pointing to the new string in the section.  */
+
+static symbolS *
+add_line_strp (segT line_str_seg, const char *str)
+{
+  char *cp;
+  size_t size;
+  symbolS *sym;
+
+  subseg_set (line_str_seg, 0);
+
+  sym = symbol_temp_new_now_octets ();
+
+  size = strlen (str) + 1;
+  cp = frag_more (size);
+  memcpy (cp, str, size);
+
+  return sym;
+}
+
+
 /* Emit the directory and file tables for .debug_line.  */
 
 static void
-out_dir_and_file_list (void)
+out_dir_and_file_list (segT line_seg, int sizeof_offset)
 {
   size_t size;
   const char *dir;
   char *cp;
   unsigned int i;
-  bfd_boolean emit_md5 = FALSE;
-  bfd_boolean emit_timestamps = TRUE;
-  bfd_boolean emit_filesize = TRUE;
+  bool emit_md5 = false;
+  bool emit_timestamps = true;
+  bool emit_filesize = true;
+  segT line_str_seg = NULL;
+  symbolS *line_strp;
 
   /* Output the Directory Table.  */
   if (DWARF2_LINE_VERSION >= 5)
@@ -1993,9 +2054,9 @@ out_dir_and_file_list (void)
 
       /* Describe the purpose and format of the column.  */
       out_uleb128 (DW_LNCT_path);
-      /* FIXME: it would be better to store these strings in
-        the .debug_line_str section and reference them here.  */
-      out_uleb128 (DW_FORM_string);
+      /* Store these strings in the .debug_line_str section so they
+        can be shared.  */
+      out_uleb128 (DW_FORM_line_strp);
 
       /* Now state how many rows there are in the table.  We need at
         least 1 if there is one or more file names to store the
@@ -2009,6 +2070,12 @@ out_dir_and_file_list (void)
   /* Emit directory list.  */
   if (DWARF2_LINE_VERSION >= 5 && (dirs_in_use > 0 || files_in_use > 0))
     {
+      line_str_seg = subseg_new (".debug_line_str", 0);
+      bfd_set_section_flags (line_str_seg,
+                            SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS
+                            | SEC_MERGE | SEC_STRINGS);
+      line_str_seg->entsize = 1;
+
       /* DWARF5 uses slot zero, but that is only set explicitly
         using a .file 0 directive.  If that isn't used, but dir
         one is used, then use that as main file directory.
@@ -2020,16 +2087,25 @@ out_dir_and_file_list (void)
       else
        dir = remap_debug_filename (getpwd ());
 
-      size = strlen (dir) + 1;
-      cp = frag_more (size);
-      memcpy (cp, dir, size);
+      line_strp = add_line_strp (line_str_seg, dir);
+      subseg_set (line_seg, 0);
+      TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
     }
   for (i = 1; i < dirs_in_use; ++i)
     {
       dir = remap_debug_filename (dirs[i]);
-      size = strlen (dir) + 1;
-      cp = frag_more (size);
-      memcpy (cp, dir, size);
+      if (DWARF2_LINE_VERSION < 5)
+       {
+         size = strlen (dir) + 1;
+         cp = frag_more (size);
+         memcpy (cp, dir, size);
+       }
+      else
+       {
+         line_strp = add_line_strp (line_str_seg, dir);
+         subseg_set (line_seg, 0);
+         TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
+       }
     }
 
   if (DWARF2_LINE_VERSION < 5)
@@ -2043,13 +2119,13 @@ out_dir_and_file_list (void)
 
       if (((unsigned long) DWARF2_FILE_TIME_NAME ("", "")) == -1UL)
        {
-         emit_timestamps = FALSE;
+         emit_timestamps = false;
          -- columns;
        }
 
       if (DWARF2_FILE_SIZE_NAME ("", "") == -1)
        {
-         emit_filesize = FALSE;
+         emit_filesize = false;
          -- columns;
        }
 
@@ -2058,7 +2134,7 @@ out_dir_and_file_list (void)
          break;
       if (i < files_in_use)
        {
-         emit_md5 = TRUE;
+         emit_md5 = true;
          ++ columns;
        }
       
@@ -2066,9 +2142,9 @@ out_dir_and_file_list (void)
       out_byte (columns);
       /* The format of the file name.  */
       out_uleb128 (DW_LNCT_path);
-      /* FIXME: it would be better to store these strings in
-        the .debug_line_str section and reference them here.  */
-      out_uleb128 (DW_FORM_string);
+      /* Store these strings in the .debug_line_str section so they
+        can be shared.  */
+      out_uleb128 (DW_FORM_line_strp);
 
       /* The format of the directory index.  */
       out_uleb128 (DW_LNCT_directory_index);
@@ -2122,9 +2198,18 @@ out_dir_and_file_list (void)
 
       fullfilename = DWARF2_FILE_NAME (files[i].filename,
                                       files[i].dir ? dirs [files [i].dir] : "");
-      size = strlen (fullfilename) + 1;
-      cp = frag_more (size);
-      memcpy (cp, fullfilename, size);
+      if (DWARF2_LINE_VERSION < 5)
+       {
+         size = strlen (fullfilename) + 1;
+         cp = frag_more (size);
+         memcpy (cp, fullfilename, size);
+       }
+      else
+       {
+         line_strp = add_line_strp (line_str_seg, fullfilename);
+         subseg_set (line_seg, 0);
+         TC_DWARF2_EMIT_OFFSET (line_strp, sizeof_offset);
+       }
 
       /* Directory number.  */
       out_uleb128 (files[i].dir);
@@ -2282,17 +2367,16 @@ out_debug_line (segT line_seg)
      matches up to the opcode base value we have been using.  */
   gas_assert (DWARF2_LINE_OPCODE_BASE == 13);
 
-  out_dir_and_file_list ();
+  out_dir_and_file_list (line_seg, sizeof_offset);
 
   symbol_set_value_now (prologue_end);
 
   /* For each section, emit a statement program.  */
   for (s = all_segs; s; s = s->next)
+    /* Paranoia - this check should have already have
+       been handled in dwarf2_gen_line_info_1().  */
     if (SEG_NORMAL (s->seg))
       process_entries (s->seg, s->head->head);
-    else
-      as_warn ("dwarf line number information for %s ignored",
-              segment_name (s->seg));
 
   if (flag_dwarf_sections)
     /* We have to switch to the special .debug_line_end section
@@ -2302,7 +2386,7 @@ out_debug_line (segT line_seg)
        This section contains the line_end symbol which is used to
        compute the size of the linked .debug_line section, as seen
        in the DWARF Line Number header.  */
-    subseg_set (subseg_get (".debug_line_end", FALSE), 0);
+    subseg_set (subseg_get (".debug_line_end", false), 0);
 
   symbol_set_value_now (line_end);
 }
@@ -2687,9 +2771,8 @@ dwarf2_init (void)
     flag_dwarf_cie_version = 1;
 }
 
-
 /* Finish the dwarf2 debug sections.  We emit .debug.line if there
-   were any .file/.loc directives, or --gdwarf2 was given, or if the
+   were any .file/.loc directives, or --gdwarf2 was given, and if the
    file has a non-empty .debug_info section and an empty .debug_line
    section.  If we emit .debug_line, and the .debug_info section is
    empty, we also emit .debug_info, .debug_aranges and .debug_abbrev.
@@ -2713,8 +2796,10 @@ dwarf2_finish (void)
   empty_debug_line = line_seg == NULL || !seg_not_empty_p (line_seg);
 
   /* We can't construct a new debug_line section if we already have one.
-     Give an error.  */
-  if (all_segs && !empty_debug_line)
+     Give an error if we have seen any .loc, otherwise trust the user
+     knows what they are doing and want to generate the .debug_line
+     (and all other debug sections) themselves.  */
+  if (all_segs && !empty_debug_line && dwarf2_any_loc_directive_seen)
     as_fatal ("duplicate .debug_line sections");
 
   if ((!all_segs && emit_other_sections)
@@ -2728,8 +2813,12 @@ dwarf2_finish (void)
   sizeof_address = DWARF2_ADDR_SIZE (stdoutput);
 
   /* Create and switch to the line number section.  */
-  line_seg = subseg_new (".debug_line", 0);
-  bfd_set_section_flags (line_seg, SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
+  if (empty_debug_line)
+    {
+      line_seg = subseg_new (".debug_line", 0);
+      bfd_set_section_flags (line_seg,
+                            SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
+    }
 
   /* For each subsection, chain the debug entries together.  */
   for (s = all_segs; s; s = s->next)
@@ -2755,7 +2844,8 @@ dwarf2_finish (void)
        }
     }
 
-  out_debug_line (line_seg);
+  if (empty_debug_line)
+    out_debug_line (line_seg);
 
   /* If this is assembler generated line info, and there is no
      debug_info already, we need .debug_info, .debug_abbrev and
This page took 0.032611 seconds and 4 git commands to generate.