2012-10-26 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index 41fd01493eb0a34b809e1f8799a3416fffaf52e0..2fa6d51cb0ba7a02a5f952a99fca1cf380842020 100644 (file)
 #define DWARF2_VERSION 2
 #endif
 
+/* The .debug_aranges version has been 2 in DWARF version 2, 3 and 4. */
+#ifndef DWARF2_ARANGES_VERSION
+#define DWARF2_ARANGES_VERSION 2
+#endif
+
+/* This implementation output version 2 .debug_line information. */
+#ifndef DWARF2_LINE_VERSION
+#define DWARF2_LINE_VERSION 2
+#endif
+
 #include "subsegs.h"
 
 #include "dwarf2.h"
    opcodes and variable-length operands cannot be used.  If this macro is
    nonzero, use the DW_LNS_fixed_advance_pc opcode instead.  */
 #ifndef DWARF2_USE_FIXED_ADVANCE_PC
-# define DWARF2_USE_FIXED_ADVANCE_PC   0
+# define DWARF2_USE_FIXED_ADVANCE_PC   linkrelax
 #endif
 
 /* First special line opcde - leave room for the standard opcodes.
@@ -207,6 +217,10 @@ static struct dwarf2_line_info current = {
   0
 };
 
+/* Lines that are at the same location as CURRENT, and which are waiting
+   for a label.  */
+static struct line_entry *pending_lines, **pending_lines_tail = &pending_lines;
+
 /* The size of an address on the target.  */
 static unsigned int sizeof_address;
 \f
@@ -280,22 +294,47 @@ get_line_subseg (segT seg, subsegT subseg)
   return lss;
 }
 
-/* Record an entry for LOC occurring at LABEL.  */
+/* Push LOC onto the pending lines list.  */
 
 static void
-dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
+dwarf2_push_line (struct dwarf2_line_info *loc)
 {
-  struct line_subseg *lss;
   struct line_entry *e;
 
   e = (struct line_entry *) xmalloc (sizeof (*e));
   e->next = NULL;
-  e->label = label;
+  e->label = NULL;
   e->loc = *loc;
 
-  lss = get_line_subseg (now_seg, now_subseg);
-  *lss->ptail = e;
-  lss->ptail = &e->next;
+  *pending_lines_tail = e;
+  pending_lines_tail = &(*pending_lines_tail)->next;
+}
+
+/* Emit all pending line information.  LABEL is the label with which the
+   lines should be associated, or null if they should be associated with
+   the current position.  */
+
+static void
+dwarf2_flush_pending_lines (symbolS *label)
+{
+  if (pending_lines)
+    {
+      struct line_subseg *lss;
+      struct line_entry *e;
+
+      if (!label)
+       label = symbol_temp_new_now ();
+
+      for (e = pending_lines; e; e = e->next)
+       e->label = label;
+
+      lss = get_line_subseg (now_seg, now_subseg);
+      *lss->ptail = pending_lines;
+      lss->ptail = pending_lines_tail;
+
+      pending_lines = NULL;
+      pending_lines_tail = &pending_lines;
+    }
 }
 
 /* Record an entry for LOC occurring at OFS within the current fragment.  */
@@ -306,8 +345,6 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc)
   static unsigned int line = -1;
   static unsigned int filenum = -1;
 
-  symbolS *sym;
-
   /* Early out for as-yet incomplete location information.  */
   if (loc->filenum == 0 || loc->line == 0)
     return;
@@ -323,8 +360,18 @@ dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc)
   line = loc->line;
   filenum = loc->filenum;
 
-  sym = symbol_temp_new (now_seg, ofs, frag_now);
-  dwarf2_gen_line_info_1 (sym, loc);
+  dwarf2_push_line (loc);
+  if (linkrelax)
+    {
+      char name[120];
+
+      /* 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);
+      dwarf2_flush_pending_lines (symbol_new (name, now_seg, ofs, frag_now));
+    }
+  else
+    dwarf2_flush_pending_lines (symbol_temp_new (now_seg, ofs, frag_now));
 }
 
 /* Returns the current source information.  If .file directives have
@@ -385,6 +432,11 @@ dwarf2_emit_insn (int size)
 void
 dwarf2_consume_line_info (void)
 {
+  /* If the consumer has stashed the current location away for later use,
+     assume that any earlier location information should be associated
+     with ".".  */
+  dwarf2_flush_pending_lines (NULL);
+
   /* Unless we generate DWARF2 debugging information for each
      assembler line, we only emit one line symbol for one LOC.  */
   dwarf2_loc_directive_seen = FALSE;
@@ -416,7 +468,8 @@ dwarf2_emit_label (symbolS *label)
 
   loc.flags |= DWARF2_FLAG_BASIC_BLOCK;
 
-  dwarf2_gen_line_info_1 (label, &loc);
+  dwarf2_push_line (&loc);
+  dwarf2_flush_pending_lines (label);
   dwarf2_consume_line_info ();
 }
 
@@ -576,7 +629,7 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
   /* If we see two .loc directives in a row, force the first one to be
      output now.  */
   if (dwarf2_loc_directive_seen)
-    dwarf2_emit_insn (0);
+    dwarf2_push_line (&current);
 
   filenum = get_absolute_expression ();
   SKIP_WHITESPACE ();
@@ -829,24 +882,22 @@ out_set_addr (symbolS *sym)
   emit_expr (&exp, sizeof_address);
 }
 
-#if DWARF2_LINE_MIN_INSN_LENGTH > 1
 static void scale_addr_delta (addressT *);
 
 static void
 scale_addr_delta (addressT *addr_delta)
 {
   static int printed_this = 0;
-  if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0)
+  if (DWARF2_LINE_MIN_INSN_LENGTH > 1)
     {
-      if (!printed_this)
-       as_bad("unaligned opcodes detected in executable segment");
-      printed_this = 1;
+      if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0  && !printed_this)
+        {
+         as_bad("unaligned opcodes detected in executable segment");
+          printed_this = 1;
+        }
+      *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
     }
-  *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
 }
-#else
-#define scale_addr_delta(A)
-#endif
 
 /* Encode a pair of line and address skips as efficiently as possible.
    Note that the line skip is signed, whereas the address skip is unsigned.
@@ -1021,6 +1072,7 @@ out_inc_line_addr (int line_delta, addressT addr_delta)
    line and address information, but it is required if linker relaxation
    could change the code offsets.  The following two routines *must* be
    kept in sync.  */
+#define ADDR_DELTA_LIMIT 50000
 
 static int
 size_fixed_inc_line_addr (int line_delta, addressT addr_delta)
@@ -1031,7 +1083,7 @@ size_fixed_inc_line_addr (int line_delta, addressT addr_delta)
   if (line_delta != INT_MAX)
     len = 1 + sizeof_leb128 (line_delta, 1);
 
-  if (addr_delta > 50000)
+  if (addr_delta > ADDR_DELTA_LIMIT)
     {
       /* DW_LNS_extended_op */
       len += 1 + sizeof_leb128 (sizeof_address + 1, 0);
@@ -1079,7 +1131,7 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
      which this function would not be used) could change the operand by
      an unknown amount.  If the address increment is getting close to
      the limit, just reset the address.  */
-  if (addr_delta > 50000)
+  if (addr_delta > ADDR_DELTA_LIMIT)
     {
       symbolS *to_sym;
       expressionS exp;
@@ -1188,7 +1240,24 @@ dwarf2dbg_convert_frag (fragS *frag)
 {
   offsetT addr_diff;
 
-  addr_diff = resolve_symbol_value (frag->fr_symbol);
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    {
+      /* If linker relaxation is enabled then the distance bewteen the two
+        symbols in the frag->fr_symbol expression might change.  Hence we
+        cannot rely upon the value computed by resolve_symbol_value.
+        Instead we leave the expression unfinalized and allow
+        emit_fixed_inc_line_addr to create a fixup (which later becomes a
+        relocation) that will allow the linker to correctly compute the
+        actual address difference.  We have to use a fixed line advance for
+        this as we cannot (easily) relocate leb128 encoded values.  */
+      int saved_finalize_syms = finalize_syms;
+
+      finalize_syms = 0;
+      addr_diff = resolve_symbol_value (frag->fr_symbol);
+      finalize_syms = saved_finalize_syms;
+    }
+  else
+    addr_diff = resolve_symbol_value (frag->fr_symbol);
 
   /* fr_var carries the max_chars that we created the fragment with.
      fr_subtype carries the current expected length.  We must, of
@@ -1424,7 +1493,7 @@ out_debug_line (segT line_seg)
   line_end = exp.X_add_symbol;
 
   /* Version.  */
-  out_two (DWARF2_VERSION);
+  out_two (DWARF2_LINE_VERSION);
 
   /* Length of the prologue following this length.  */
   prologue_end = symbol_temp_make ();
@@ -1459,7 +1528,11 @@ out_debug_line (segT line_seg)
 
   /* For each section, emit a statement program.  */
   for (s = all_segs; s; s = s->next)
-    process_entries (s->seg, s->head->head);
+    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));
 
   symbol_set_value_now (line_end);
 }
@@ -1528,7 +1601,7 @@ out_debug_aranges (segT aranges_seg, segT info_seg)
   aranges_end = exp.X_add_symbol;
 
   /* Version.  */
-  out_two (DWARF2_VERSION);
+  out_two (DWARF2_ARANGES_VERSION);
 
   /* Offset to .debug_info.  */
   TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), sizeof_offset);
@@ -1594,7 +1667,11 @@ out_debug_abbrev (segT abbrev_seg,
   if (all_segs->next == NULL)
     {
       out_abbrev (DW_AT_low_pc, DW_FORM_addr);
-      out_abbrev (DW_AT_high_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));
     }
   else
     {
@@ -1657,7 +1734,13 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
       emit_expr (&exp, sizeof_address);
 
       /* DW_AT_high_pc */
-      exp.X_op = O_symbol;
+      if (DWARF2_VERSION < 4)
+       exp.X_op = O_symbol;
+      else
+       {
+         exp.X_op = O_subtract;
+         exp.X_op_symbol = all_segs->text_start;
+       }
       exp.X_add_symbol = all_segs->text_end;
       exp.X_add_number = 0;
       emit_expr (&exp, sizeof_address);
This page took 0.046976 seconds and 4 git commands to generate.