PR gas/5134
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index 22dde6a0194dd56f9025a1cbda7072baa39b906e..39e434c012fea69c0eb0314c606db26a40dfae81 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf2dbg.c - DWARF2 debug support
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
@@ -7,7 +7,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 #define DL_FILES       1
 #define DL_BODY                2
 
+/* If linker relaxation might change offsets in the code, the DWARF special
+   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
+#endif
+
 /* First special line opcde - leave room for the standard opcodes.
    Note: If you want to change this, you'll have to update the
    "standard_opcode_lengths" table that is emitted below in
@@ -191,11 +198,13 @@ static void out_two (int);
 static void out_four (int);
 static void out_abbrev (int, int);
 static void out_uleb128 (addressT);
+static void out_sleb128 (addressT);
 static offsetT get_frag_fix (fragS *, segT);
 static void out_set_addr (symbolS *);
 static int size_inc_line_addr (int, addressT);
 static void emit_inc_line_addr (int, addressT, char *, int);
 static void out_inc_line_addr (int, addressT);
+static void out_fixed_inc_line_addr (int, symbolS *, symbolS *);
 static void relax_inc_line_addr (int, symbolS *, symbolS *);
 static void process_entries (segT, struct line_entry *);
 static void out_file_list (void);
@@ -561,6 +570,11 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
 {
   offsetT filenum, line;
 
+  /* If we see two .loc directives in a row, force the first one to be
+     output now.  */
+  if (loc_directive_seen)
+    dwarf2_emit_insn (0);
+
   filenum = get_absolute_expression ();
   SKIP_WHITESPACE ();
   line = get_absolute_expression ();
@@ -744,6 +758,14 @@ out_uleb128 (addressT value)
   output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0);
 }
 
+/* Emit a signed "little-endian base 128" number.  */
+
+static void
+out_sleb128 (addressT value)
+{
+  output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1);
+}
+
 /* Emit a tuple for .debug_abbrev.  */
 
 static inline void
@@ -977,6 +999,45 @@ out_inc_line_addr (int line_delta, addressT addr_delta)
   emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len);
 }
 
+/* Write out an alternative form of line and address skips using
+   DW_LNS_fixed_advance_pc opcodes.  This uses more space than the default
+   line and address information, but it helps support linker relaxation that
+   changes the code offsets.  */
+
+static void
+out_fixed_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
+{
+  expressionS expr;
+
+  /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
+  if (line_delta == INT_MAX)
+    {
+      out_opcode (DW_LNS_fixed_advance_pc);
+      expr.X_op = O_subtract;
+      expr.X_add_symbol = to_sym;
+      expr.X_op_symbol = from_sym;
+      expr.X_add_number = 0;
+      emit_expr (&expr, 2);
+
+      out_opcode (DW_LNS_extended_op);
+      out_byte (1);
+      out_opcode (DW_LNE_end_sequence);
+      return;
+    }
+
+  out_opcode (DW_LNS_advance_line);
+  out_sleb128 (line_delta);
+
+  out_opcode (DW_LNS_fixed_advance_pc);
+  expr.X_op = O_subtract;
+  expr.X_add_symbol = to_sym;
+  expr.X_op_symbol = from_sym;
+  expr.X_add_number = 0;
+  emit_expr (&expr, 2);
+
+  out_opcode (DW_LNS_copy);
+}
+
 /* Generate a variant frag that we can use to relax address/line
    increments between fragments of the target segment.  */
 
@@ -1127,6 +1188,8 @@ process_entries (segT seg, struct line_entry *e)
          out_set_addr (lab);
          out_inc_line_addr (line_delta, 0);
        }
+      else if (DWARF2_USE_FIXED_ADVANCE_PC)
+       out_fixed_inc_line_addr (line_delta, lab, last_lab);
       else if (frag == last_frag)
        out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs);
       else
@@ -1146,7 +1209,12 @@ process_entries (segT seg, struct line_entry *e)
   /* Emit a DW_LNE_end_sequence for the end of the section.  */
   frag = last_frag_for_seg (seg);
   frag_ofs = get_frag_fix (frag, seg);
-  if (frag == last_frag)
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    {
+      lab = symbol_temp_new (seg, frag_ofs, frag);
+      out_fixed_inc_line_addr (INT_MAX, lab, last_lab);
+    }
+  else if (frag == last_frag)
     out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
   else
     {
@@ -1161,15 +1229,17 @@ static void
 out_file_list (void)
 {
   size_t size;
+  const char *dir;
   char *cp;
   unsigned int i;
 
   /* Emit directory list.  */
   for (i = 1; i < dirs_in_use; ++i)
     {
-      size = strlen (dirs[i]) + 1;
+      dir = remap_debug_filename (dirs[i]);
+      size = strlen (dir) + 1;
       cp = frag_more (size);
-      memcpy (cp, dirs[i], size);
+      memcpy (cp, dir, size);
     }
   /* Terminate it.  */
   out_byte ('\0');
@@ -1451,7 +1521,8 @@ static void
 out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
 {
   char producer[128];
-  char *comp_dir;
+  const char *comp_dir;
+  const char *dirname;
   expressionS expr;
   symbolS *info_start;
   symbolS *info_end;
@@ -1528,13 +1599,9 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
     }
   else
     {
-      /* This attributes is emitted if the code is disjoint.  */
-      
-      /* DW_AT_ranges */
-      expr.X_op = O_symbol;
-      expr.X_add_symbol = section_symbol (ranges_seg);
-      expr.X_add_number = 0;
-      emit_expr (&expr, sizeof_address);
+      /* This attribute is emitted if the code is disjoint.  */
+      /* DW_AT_ranges.  */
+      TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset);
     }
 
   /* DW_AT_name.  We don't have the actual file name that was present
@@ -1545,9 +1612,10 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
     abort ();
   if (files[1].dir)
     {
-      len = strlen (dirs[files[1].dir]);
+      dirname = remap_debug_filename (dirs[files[1].dir]);
+      len = strlen (dirname);
       p = frag_more (len + 1);
-      memcpy (p, dirs[files[1].dir], len);
+      memcpy (p, dirname, len);
       INSERT_DIR_SEPARATOR (p, len);
     }
   len = strlen (files[1].filename) + 1;
@@ -1555,7 +1623,7 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg)
   memcpy (p, files[1].filename, len);
 
   /* DW_AT_comp_dir */
-  comp_dir = getpwd ();
+  comp_dir = remap_debug_filename (getpwd ());
   len = strlen (comp_dir) + 1;
   p = frag_more (len);
   memcpy (p, comp_dir, len);
This page took 0.025054 seconds and 4 git commands to generate.