gas: Don't error when .debug_line already exists, unless .loc was used
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index 9fdb34f209b918a1436fff6ec0916598904b8e73..1c21d58c5913fd36cf2041d6cd02f6c6f248dccd 100644 (file)
 #define DWARF2_LINE_VERSION (dwarf_level > 3 ? dwarf_level : 3)
 #endif
 
+/* The .debug_rnglists has only been in DWARF version 5. */
+#ifndef DWARF2_RNGLISTS_VERSION
+#define DWARF2_RNGLISTS_VERSION 5
+#endif
+
 #include "subsegs.h"
 
 #include "dwarf2.h"
@@ -221,9 +226,15 @@ 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.  */
+   doing work when there's nothing to do.  Will be reset by
+   dwarf2_consume_line_info.  */
 bfd_boolean 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 bfd_boolean 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;
@@ -546,10 +557,10 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc)
       /* Use a non-fake name for the line number location,
         so that it can be referred to by relocations.  */
       sprintf (name, ".Loc.%u.%u", line, filenum);
-      sym = symbol_new (name, now_seg, ofs, frag_now);
+      sym = symbol_new (name, now_seg, frag_now, ofs);
     }
   else
-    sym = symbol_temp_new (now_seg, ofs, frag_now);
+    sym = symbol_temp_new (now_seg, frag_now, ofs);
   dwarf2_gen_line_info_1 (sym, loc);
 }
 
@@ -1014,7 +1025,7 @@ dwarf2_emit_label (symbolS *label)
 char *
 dwarf2_directive_filename (void)
 {
-  bfd_boolean with_md5 = TRUE;
+  bfd_boolean with_md5 = FALSE;
   valueT num;
   char *filename;
   const char * dirname = NULL;
@@ -1245,8 +1256,8 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
                sym = force_reset_view;
              else
                {
-                 sym = symbol_temp_new (absolute_section, value,
-                                        &zero_address_frag);
+                 sym = symbol_temp_new (absolute_section, &zero_address_frag,
+                                        value);
                  if (force_reset)
                    force_reset_view = sym;
                }
@@ -1285,7 +1296,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.  */
@@ -1962,15 +1973,37 @@ process_entries (segT seg, struct line_entry *e)
     out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
   else
     {
-      lab = symbol_temp_new (seg, frag_ofs, frag);
+      lab = symbol_temp_new (seg, frag, frag_ofs);
       relax_inc_line_addr (INT_MAX, lab, last_lab);
     }
 }
 
+/* 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;
@@ -1979,37 +2012,69 @@ out_dir_and_file_list (void)
   bfd_boolean emit_md5 = FALSE;
   bfd_boolean emit_timestamps = TRUE;
   bfd_boolean emit_filesize = TRUE;
+  segT line_str_seg = NULL;
+  symbolS *line_strp;
 
   /* Output the Directory Table.  */
-
   if (DWARF2_LINE_VERSION >= 5)
     {
+      /* We only have one column in the directory table.  */
       out_byte (1);
+
+      /* 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);
-      out_uleb128 (dirs_in_use);
+      /* 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
+        "working directory".  */
+      if (dirs_in_use == 0 && files_in_use > 0)
+       out_uleb128 (1);
+      else
+       out_uleb128 (dirs_in_use);
     }
       
   /* Emit directory list.  */
-  if (DWARF2_LINE_VERSION >= 5)
-    {
-      if (dirs[0] == NULL)
-       dir = remap_debug_filename (".");
-      else
+  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.
+        Otherwise use pwd as main file directory.  */
+      if (dirs_in_use > 0 && dirs != NULL && dirs[0] != NULL)
        dir = remap_debug_filename (dirs[0]);
-       
-      size = strlen (dir) + 1;
-      cp = frag_more (size);
-      memcpy (cp, dir, size);
+      else if (dirs_in_use > 1 && dirs != NULL && dirs[1] != NULL)
+       dir = remap_debug_filename (dirs[1]);
+      else
+       dir = remap_debug_filename (getpwd ());
+
+      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)
@@ -2017,7 +2082,6 @@ out_dir_and_file_list (void)
     out_byte ('\0');
 
   /* Output the File Name Table.  */
-
   if (DWARF2_LINE_VERSION >= 5)
     {
       unsigned int columns = 4;
@@ -2045,12 +2109,11 @@ out_dir_and_file_list (void)
       
       /* The number of format entries to follow.  */
       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);
@@ -2087,8 +2150,14 @@ out_dir_and_file_list (void)
 
       if (files[i].filename == NULL)
        {
-         /* Prevent a crash later, particularly for file 1.  */
-         files[i].filename = "";
+         /* Prevent a crash later, particularly for file 1.  DWARF5
+            uses slot zero, but that is only set explicitly using a
+            .file 0 directive.  If that isn't used, but file 1 is,
+            then use that as main file name.  */
+         if (DWARF2_LINE_VERSION >= 5 && i == 0 && files_in_use >= 1)
+             files[0].filename = files[1].filename;
+         else
+           files[i].filename = "";
          if (DWARF2_LINE_VERSION < 5 || i != 0)
            {
              as_bad (_("unassigned file number %ld"), (long) i);
@@ -2098,9 +2167,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);
@@ -2258,7 +2336,7 @@ 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);
 
@@ -2284,7 +2362,7 @@ out_debug_line (segT line_seg)
 }
 
 static void
-out_debug_ranges (segT ranges_seg)
+out_debug_ranges (segT ranges_seg, symbolS **ranges_sym)
 {
   unsigned int addr_size = sizeof_address;
   struct line_seg *s;
@@ -2294,6 +2372,10 @@ out_debug_ranges (segT ranges_seg)
   memset (&exp, 0, sizeof exp);
   subseg_set (ranges_seg, 0);
 
+  /* For DW_AT_ranges to point at (there is no header, so really start
+     of section, but see out_debug_rnglists).  */
+  *ranges_sym = symbol_temp_new_now_octets ();
+
   /* Base Address Entry.  */
   for (i = 0; i < addr_size; i++)
     out_byte (0xff);
@@ -2307,11 +2389,11 @@ out_debug_ranges (segT ranges_seg)
       symbolS *beg, *end;
 
       frag = first_frag_for_seg (s->seg);
-      beg = symbol_temp_new (s->seg, 0, frag);
+      beg = symbol_temp_new (s->seg, frag, 0);
       s->text_start = beg;
 
       frag = last_frag_for_seg (s->seg);
-      end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
+      end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
       s->text_end = end;
 
       exp.X_op = O_symbol;
@@ -2332,6 +2414,57 @@ out_debug_ranges (segT ranges_seg)
     out_byte (0);
 }
 
+static void
+out_debug_rnglists (segT ranges_seg, symbolS **ranges_sym)
+{
+  expressionS exp;
+  symbolS *ranges_end;
+  struct line_seg *s;
+
+  /* Unit length.  */
+  memset (&exp, 0, sizeof exp);
+  out_header (ranges_seg, &exp);
+  ranges_end = exp.X_add_symbol;
+
+  out_two (DWARF2_RNGLISTS_VERSION);
+  out_byte (sizeof_address);
+  out_byte (0); /* Segment Selector size.  */
+  out_four (0); /* Offset entry count.  */
+
+  /* For DW_AT_ranges to point at (must be after the header).   */
+  *ranges_sym = symbol_temp_new_now_octets ();
+
+  for (s = all_segs; s; s = s->next)
+    {
+      fragS *frag;
+      symbolS *beg, *end;
+
+      out_byte (DW_RLE_start_length);
+
+      frag = first_frag_for_seg (s->seg);
+      beg = symbol_temp_new (s->seg, frag, 0);
+      s->text_start = beg;
+
+      frag = last_frag_for_seg (s->seg);
+      end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
+      s->text_end = end;
+
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = beg;
+      exp.X_add_number = 0;
+      emit_expr (&exp, sizeof_address);
+
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = end;
+      exp.X_add_number = 0;
+      emit_leb128_expr (&exp, 0);
+    }
+
+  out_byte (DW_RLE_end_of_list);
+
+  symbol_set_value_now (ranges_end);
+}
+
 /* Emit data for .debug_aranges.  */
 
 static void
@@ -2376,11 +2509,11 @@ out_debug_aranges (segT aranges_seg, segT info_seg)
       symbolS *beg, *end;
 
       frag = first_frag_for_seg (s->seg);
-      beg = symbol_temp_new (s->seg, 0, frag);
+      beg = symbol_temp_new (s->seg, frag, 0);
       s->text_start = beg;
 
       frag = last_frag_for_seg (s->seg);
-      end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
+      end = symbol_temp_new (s->seg, frag, get_frag_fix (frag, s->seg));
       s->text_end = end;
 
       exp.X_op = O_symbol;
@@ -2410,31 +2543,32 @@ out_debug_abbrev (segT abbrev_seg,
                  segT info_seg ATTRIBUTE_UNUSED,
                  segT line_seg ATTRIBUTE_UNUSED)
 {
+  int secoff_form;
   subseg_set (abbrev_seg, 0);
 
   out_uleb128 (1);
   out_uleb128 (DW_TAG_compile_unit);
   out_byte (DW_CHILDREN_no);
-  if (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit)
-    out_abbrev (DW_AT_stmt_list, DW_FORM_data4);
+  if (DWARF2_VERSION < 4)
+    {
+      if (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit)
+       secoff_form = DW_FORM_data4;
+      else
+       secoff_form = DW_FORM_data8;
+    }
   else
-    out_abbrev (DW_AT_stmt_list, DW_FORM_data8);
+    secoff_form = DW_FORM_sec_offset;
+  out_abbrev (DW_AT_stmt_list, secoff_form);
   if (all_segs->next == NULL)
     {
       out_abbrev (DW_AT_low_pc, DW_FORM_addr);
       if (DWARF2_VERSION < 4)
        out_abbrev (DW_AT_high_pc, DW_FORM_addr);
       else
-       out_abbrev (DW_AT_high_pc, (sizeof_address == 4
-                                   ? DW_FORM_data4 : DW_FORM_data8));
+       out_abbrev (DW_AT_high_pc, DW_FORM_udata);
     }
   else
-    {
-      if (DWARF2_FORMAT (info_seg) == dwarf2_format_32bit)
-       out_abbrev (DW_AT_ranges, DW_FORM_data4);
-      else
-       out_abbrev (DW_AT_ranges, DW_FORM_data8);
-    }
+    out_abbrev (DW_AT_ranges, secoff_form);
   out_abbrev (DW_AT_name, DW_FORM_strp);
   out_abbrev (DW_AT_comp_dir, DW_FORM_strp);
   out_abbrev (DW_AT_producer, DW_FORM_strp);
@@ -2448,8 +2582,9 @@ out_debug_abbrev (segT abbrev_seg,
 /* Emit a description of this compilation unit for .debug_info.  */
 
 static void
-out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg,
-               symbolS *name_sym, symbolS *comp_dir_sym, symbolS *producer_sym)
+out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg,
+               symbolS *ranges_sym, symbolS *name_sym,
+               symbolS *comp_dir_sym, symbolS *producer_sym)
 {
   expressionS exp;
   symbolS *info_end;
@@ -2462,12 +2597,26 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg,
   /* DWARF version.  */
   out_two (DWARF2_VERSION);
 
-  /* .debug_abbrev offset */
-  TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+  if (DWARF2_VERSION < 5)
+    {
+      /* .debug_abbrev offset */
+      TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+    }
+  else
+    {
+      /* unit (header) type */
+      out_byte (DW_UT_compile);
+    }
 
   /* Target address size.  */
   out_byte (sizeof_address);
 
+  if (DWARF2_VERSION >= 5)
+    {
+      /* .debug_abbrev offset */
+      TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset);
+    }
+
   /* DW_TAG_compile_unit DIE abbrev */
   out_uleb128 (1);
 
@@ -2495,13 +2644,16 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg,
        }
       exp.X_add_symbol = all_segs->text_end;
       exp.X_add_number = 0;
-      emit_expr (&exp, sizeof_address);
+      if (DWARF2_VERSION < 4)
+       emit_expr (&exp, sizeof_address);
+      else
+       emit_leb128_expr (&exp, 0);
     }
   else
     {
       /* This attribute is emitted if the code is disjoint.  */
       /* DW_AT_ranges.  */
-      TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset);
+      TC_DWARF2_EMIT_OFFSET (ranges_sym, sizeof_offset);
     }
 
   /* DW_AT_name, DW_AT_comp_dir and DW_AT_producer.  Symbols in .debug_str
@@ -2591,7 +2743,7 @@ dwarf2_init (void)
 
 
 /* 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.
@@ -2615,8 +2767,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)
@@ -2630,8 +2784,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)
@@ -2657,7 +2815,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
@@ -2666,9 +2825,8 @@ dwarf2_finish (void)
     {
       segT abbrev_seg;
       segT aranges_seg;
-      segT ranges_seg;
       segT str_seg;
-      symbolS *name_sym, *comp_dir_sym, *producer_sym;
+      symbolS *name_sym, *comp_dir_sym, *producer_sym, *ranges_sym;
 
       gas_assert (all_segs);
 
@@ -2691,20 +2849,32 @@ dwarf2_finish (void)
       record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1);
 
       if (all_segs->next == NULL)
-       ranges_seg = NULL;
+       ranges_sym = NULL;
       else
        {
-         ranges_seg = subseg_new (".debug_ranges", 0);
-         bfd_set_section_flags (ranges_seg,
-                                SEC_READONLY | SEC_DEBUGGING | SEC_OCTETS);
-         record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
-         out_debug_ranges (ranges_seg);
+         if (DWARF2_VERSION < 5)
+           {
+             segT ranges_seg = subseg_new (".debug_ranges", 0);
+             bfd_set_section_flags (ranges_seg, (SEC_READONLY
+                                                 | SEC_DEBUGGING
+                                                 | SEC_OCTETS));
+             record_alignment (ranges_seg, ffs (2 * sizeof_address) - 1);
+             out_debug_ranges (ranges_seg, &ranges_sym);
+           }
+         else
+           {
+             segT rnglists_seg = subseg_new (".debug_rnglists", 0);
+             bfd_set_section_flags (rnglists_seg, (SEC_READONLY
+                                                   | SEC_DEBUGGING
+                                                   | SEC_OCTETS));
+             out_debug_rnglists (rnglists_seg, &ranges_sym);
+           }
        }
 
       out_debug_aranges (aranges_seg, info_seg);
       out_debug_abbrev (abbrev_seg, info_seg, line_seg);
       out_debug_str (str_seg, &name_sym, &comp_dir_sym, &producer_sym);
-      out_debug_info (info_seg, abbrev_seg, line_seg, ranges_seg,
+      out_debug_info (info_seg, abbrev_seg, line_seg, ranges_sym,
                      name_sym, comp_dir_sym, producer_sym);
     }
 }
This page took 0.030573 seconds and 4 git commands to generate.