gas/
authorBob Wilson <bob.wilson@acm.org>
Wed, 9 Jan 2008 17:30:59 +0000 (17:30 +0000)
committerBob Wilson <bob.wilson@acm.org>
Wed, 9 Jan 2008 17:30:59 +0000 (17:30 +0000)
* dwarf2dbg.c (out_sleb128): Delete.
(size_fixed_inc_line_addr, emit_fixed_inc_line_addr): New.
(out_fixed_inc_line_addr): Delete.
(relax_inc_line_addr, dwarf2dbg_estimate_size_before_relax): Call new
size_fixed_inc_line_addr if DWARF2_USE_FIXED_ADVANCE_PC is set.
(dwarf2dbg_convert_frag): Likewise for emit_fixed_inc_line_addr.
(process_entries): Remove calls to out_fixed_inc_line_addr.  When
DWARF2_USE_FIXED_ADVANCE_PC is set, call relax_inc_line_addr.
* read.h (emit_expr_fix): New prototype.
* read.c (emit_expr): Move code to emit_expr_fix and use it here.
(emit_expr_fix): New.
testsuite/
* gas/lns/lns.exp: Run new lns-big-delta test for targets that set
DWARF2_USE_FIXED_ADVANCE_PC.
* gas/lns/lns-big-delta.s: New.
* gas/lns/lns-big-delta.d: New.

gas/ChangeLog
gas/dwarf2dbg.c
gas/read.c
gas/read.h
gas/testsuite/ChangeLog
gas/testsuite/gas/lns/lns-big-delta.d [new file with mode: 0644]
gas/testsuite/gas/lns/lns-big-delta.s [new file with mode: 0644]
gas/testsuite/gas/lns/lns.exp

index 331727f2e40b30e90228c8ae7a3f3c3b8ea967f7..46f36be80593fefd786a4274546cc461af4577c1 100644 (file)
@@ -1,3 +1,17 @@
+2008-01-09  Bob Wilson  <bob.wilson@acm.org>
+       
+       * dwarf2dbg.c (out_sleb128): Delete.
+       (size_fixed_inc_line_addr, emit_fixed_inc_line_addr): New.
+       (out_fixed_inc_line_addr): Delete.
+       (relax_inc_line_addr, dwarf2dbg_estimate_size_before_relax): Call new
+       size_fixed_inc_line_addr if DWARF2_USE_FIXED_ADVANCE_PC is set.
+       (dwarf2dbg_convert_frag): Likewise for emit_fixed_inc_line_addr.
+       (process_entries): Remove calls to out_fixed_inc_line_addr.  When
+       DWARF2_USE_FIXED_ADVANCE_PC is set, call relax_inc_line_addr.
+       * read.h (emit_expr_fix): New prototype.
+       * read.c (emit_expr): Move code to emit_expr_fix and use it here.
+       (emit_expr_fix): New.
+       
 2008-01-09  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/tc-i386.c (match_template): Check register size
index 8befbd028c7a71e48fa8a3bc10ee1fcd3b21a5d7..615d64431f9c7fb01272e683c9423cdaa02577da 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf2dbg.c - DWARF2 debug support
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
@@ -198,13 +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 int size_fixed_inc_line_addr (int, addressT);
+static void emit_fixed_inc_line_addr (int, addressT, fragS *, 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);
@@ -762,14 +762,6 @@ 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
@@ -1005,41 +997,103 @@ out_inc_line_addr (int line_delta, addressT addr_delta)
 
 /* 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.  */
+   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.  */
 
-static void
-out_fixed_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
+static int
+size_fixed_inc_line_addr (int line_delta, addressT addr_delta)
 {
-  expressionS expr;
+  int len = 0;
 
   /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.  */
+  if (line_delta != INT_MAX)
+    len = 1 + sizeof_leb128 (line_delta, 1);
+
+  if (addr_delta > 50000)
+    {
+      /* DW_LNS_extended_op */
+      len += 1 + sizeof_leb128 (sizeof_address + 1, 0);
+      /* DW_LNE_set_address */
+      len += 1 + sizeof_address;
+    }
+  else
+    /* DW_LNS_fixed_advance_pc */
+    len += 3;
+
   if (line_delta == INT_MAX)
+    /* DW_LNS_extended_op + DW_LNE_end_sequence */
+    len += 3;
+  else
+    /* DW_LNS_copy */
+    len += 1;
+
+  return len;
+}
+
+static void
+emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
+                         char *p, int len)
+{
+  expressionS *exp;
+  segT line_seg;
+  char *end = p + len;
+
+  /* Line number sequences cannot go backward in addresses.  This means
+     we've incorrectly ordered the statements in the sequence.  */
+  assert ((offsetT) addr_delta >= 0);
+
+  /* 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;
+      *p++ = DW_LNS_advance_line;
+      p += output_leb128 (p, line_delta, 1);
+    }
+
+  exp = symbol_get_value_expression (frag->fr_symbol);
+  line_seg = subseg_get (".debug_line", 0);
+
+  /* The DW_LNS_fixed_advance_pc opcode has a 2-byte operand so it can
+     advance the address by at most 64K.  Linker relaxation (without
+     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)
+    {
+      symbolS *to_sym;
+      expressionS expr;
+
+      assert (exp->X_op = O_subtract);
+      to_sym = exp->X_add_symbol;
+
+      *p++ = DW_LNS_extended_op;
+      p += output_leb128 (p, sizeof_address + 1, 0);
+      *p++ = DW_LNE_set_address;
+      expr.X_op = O_symbol;
       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;
+      subseg_change (line_seg, 0);
+      emit_expr_fix (&expr, sizeof_address, frag, p);
+      p += sizeof_address;
+    }
+  else
+    {
+      *p++ = DW_LNS_fixed_advance_pc;
+      subseg_change (line_seg, 0);
+      emit_expr_fix (exp, 2, frag, p);
+      p += 2;
     }
 
-  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);
+  if (line_delta == INT_MAX)
+    {
+      *p++ = DW_LNS_extended_op;
+      *p++ = 1;
+      *p++ = DW_LNE_end_sequence;
+    }
+  else
+    *p++ = DW_LNS_copy;
 
-  out_opcode (DW_LNS_copy);
+  assert (p == end);
 }
 
 /* Generate a variant frag that we can use to relax address/line
@@ -1058,7 +1112,11 @@ relax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
 
   /* The maximum size of the frag is the line delta with a maximum
      sized address delta.  */
-  max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH);
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    max_chars = size_fixed_inc_line_addr (line_delta,
+                                         -DWARF2_LINE_MIN_INSN_LENGTH);
+  else
+    max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH);
 
   frag_var (rs_dwarf2dbg, max_chars, max_chars, 1,
            make_expr_symbol (&expr), line_delta, NULL);
@@ -1075,7 +1133,10 @@ dwarf2dbg_estimate_size_before_relax (fragS *frag)
   int size;
 
   addr_delta = resolve_symbol_value (frag->fr_symbol);
-  size = size_inc_line_addr (frag->fr_offset, addr_delta);
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    size = size_fixed_inc_line_addr (frag->fr_offset, addr_delta);
+  else
+    size = size_inc_line_addr (frag->fr_offset, addr_delta);
 
   frag->fr_subtype = size;
 
@@ -1113,8 +1174,13 @@ dwarf2dbg_convert_frag (fragS *frag)
      course, have allocated enough memory earlier.  */
   assert (frag->fr_var >= (int) frag->fr_subtype);
 
-  emit_inc_line_addr (frag->fr_offset, addr_diff,
-                     frag->fr_literal + frag->fr_fix, frag->fr_subtype);
+  if (DWARF2_USE_FIXED_ADVANCE_PC)
+    emit_fixed_inc_line_addr (frag->fr_offset, addr_diff, frag,
+                             frag->fr_literal + frag->fr_fix,
+                             frag->fr_subtype);
+  else
+    emit_inc_line_addr (frag->fr_offset, addr_diff,
+                       frag->fr_literal + frag->fr_fix, frag->fr_subtype);
 
   frag->fr_fix += frag->fr_subtype;
   frag->fr_type = rs_fill;
@@ -1192,9 +1258,7 @@ 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)
+      else if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC)
        out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs);
       else
        relax_inc_line_addr (line_delta, lab, last_lab);
@@ -1213,12 +1277,7 @@ 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 (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)
+  if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC)
     out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
   else
     {
index 2f3b2383f22f983b1cc30deee2676b755b37acd5..5718bf44f9c2f486912cc3c2b295c7e901740523 100644 (file)
@@ -1,6 +1,6 @@
 /* read.c - read a source file -
    Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -4175,41 +4175,45 @@ emit_expr (expressionS *exp, unsigned int nbytes)
        }
     }
   else
-    {
-      memset (p, 0, nbytes);
+    emit_expr_fix (exp, nbytes, frag_now, p);
+}
+
+void
+emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
+{
+  memset (p, 0, nbytes);
 
-      /* Now we need to generate a fixS to record the symbol value.  */
+  /* Generate a fixS to record the symbol value.  */
 
 #ifdef TC_CONS_FIX_NEW
-      TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
+  TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp);
 #else
-      {
-       bfd_reloc_code_real_type r;
+  {
+    bfd_reloc_code_real_type r;
 
-       switch (nbytes)
-         {
-         case 1:
-           r = BFD_RELOC_8;
-           break;
-         case 2:
-           r = BFD_RELOC_16;
-           break;
-         case 4:
-           r = BFD_RELOC_32;
-           break;
-         case 8:
-           r = BFD_RELOC_64;
-           break;
-         default:
-           as_bad (_("unsupported BFD relocation size %u"), nbytes);
-           r = BFD_RELOC_32;
-           break;
-         }
-       fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp,
-                    0, r);
+    switch (nbytes)
+      {
+      case 1:
+       r = BFD_RELOC_8;
+       break;
+      case 2:
+       r = BFD_RELOC_16;
+       break;
+      case 4:
+       r = BFD_RELOC_32;
+       break;
+      case 8:
+       r = BFD_RELOC_64;
+       break;
+      default:
+       as_bad (_("unsupported BFD relocation size %u"), nbytes);
+       r = BFD_RELOC_32;
+       break;
       }
+    fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp,
+                0, r);
+  }
 #endif
-    }
 }
 \f
 #ifdef BITFIELD_CONS_EXPRESSIONS
index 88599946711671732cdd0810253fa0d87542c405..9974d741d2e3f6e12cc8d61f7e04e62b6681739f 100644 (file)
@@ -1,6 +1,6 @@
 /* read.h - of read.c
    Copyright 1986, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -111,6 +111,7 @@ extern void add_include_dir (char *path);
 extern void cons (int nbytes);
 extern void demand_empty_rest_of_line (void);
 extern void emit_expr (expressionS *exp, unsigned int nbytes);
+extern void emit_expr_fix (expressionS *, unsigned int, fragS *, char *);
 extern void equals (char *sym_name, int reassign);
 extern void float_cons (int float_type);
 extern void ignore_rest_of_line (void);
index cedaa25750cc8125202e6de4fc5c12030ee78bbc..fb0aa85364d37c5b80ccc12c31a790a86d0caf61 100644 (file)
@@ -1,3 +1,10 @@
+2008-01-09  Bob Wilson  <bob.wilson@acm.org>
+       
+       * gas/lns/lns.exp: Run new lns-big-delta test for targets that set
+       DWARF2_USE_FIXED_ADVANCE_PC.
+       * gas/lns/lns-big-delta.s: New.
+       * gas/lns/lns-big-delta.d: New.
+       
 2008-01-08  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        PR gas/5322
diff --git a/gas/testsuite/gas/lns/lns-big-delta.d b/gas/testsuite/gas/lns/lns-big-delta.d
new file mode 100644 (file)
index 0000000..6190138
--- /dev/null
@@ -0,0 +1,14 @@
+#source: lns-big-delta.s
+#readelf: -wl
+#name: lns-big-delta
+Dump of debug contents of section \.debug_line:
+#...
+ Line Number Statements:
+  Extended opcode 2: set Address to .*
+  Copy
+  Advance Line by 1 to 2
+  Extended opcode 2: set Address to .*
+  Copy
+  Advance PC by fixed size amount 0 to .*
+  Extended opcode 1: End of Sequence
+#pass
diff --git a/gas/testsuite/gas/lns/lns-big-delta.s b/gas/testsuite/gas/lns/lns-big-delta.s
new file mode 100644 (file)
index 0000000..a959748
--- /dev/null
@@ -0,0 +1,5 @@
+       .file 1 "foo.c"
+       .loc 1 1 0
+       .loc 1 2 0
+       .space  75000
+       .loc 1 3 0
index b292f2ec18198290ee9447a76880a20367002464..e3f176fe22a3512c3cdbff7a9b9c2927a3c1f163 100644 (file)
@@ -22,6 +22,7 @@ if {
     # Use alternate file for targets using DW_LNS_fixed_advance_pc opcodes.
     if { [istarget xtensa-*-*] } {
       run_dump_test "lns-common-1-alt"
+      run_dump_test "lns-big-delta"
     } elseif { [istarget ia64*-*-*] } {
       run_dump_test "lns-common-1" { { source "lns-common-1-ia64.s" } }
     } else {