* libtool.m4 (LD): Append -melf* option to LD on IRIX with GNU ld.
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index 0068f7a620b0333dfc32ae632385899fa0b98a4f..58ac0f5785204dfbcc35a2af3ee6a97cb91739d5 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf2dbg.c - DWARF2 debug support
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    This file is part of GAS, the GNU Assembler.
 #endif
 #endif
 
+#include "dwarf2dbg.h"
+#include <filenames.h>
+
+#ifndef DWARF2_FORMAT
+# define DWARF2_FORMAT() dwarf2_format_32bit
+#endif
+
+#ifndef DWARF2_ADDR_SIZE
+# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8);
+#endif
+
+
 #ifdef BFD_ASSEMBLER
 
-#include "dwarf2dbg.h"
 #include "subsegs.h"
 
 #include "elf/dwarf2.h"
@@ -122,7 +133,7 @@ struct line_seg {
 static struct line_seg *all_segs;
 
 struct file_entry {
-  char *filename;
+  const char *filename;
   unsigned int dir;
 };
 
@@ -131,14 +142,14 @@ static struct file_entry *files;
 static unsigned int files_in_use;
 static unsigned int files_allocated;
 
-/* Correlate file numbers as given by the user in .file/.loc directives
-   with the file numbers used in the output debug info.  */
-static unsigned int *user_filenum;
-static unsigned int user_filenum_allocated;
+/* Table of directories used by .debug_line.  */
+static char **dirs;
+static unsigned int dirs_in_use;
+static unsigned int dirs_allocated;
 
-/* True when we've seen a .loc directive recently.  Used to avoid
+/* TRUE when we've seen a .loc directive recently.  Used to avoid
    doing work when there's nothing to do.  */
-static boolean loc_directive_seen;
+static bfd_boolean loc_directive_seen;
 
 /* Current location as indicated by the most recent .loc directive.  */
 static struct dwarf2_line_info current;
@@ -150,7 +161,7 @@ static char const fake_label_name[] = ".L0\001";
 static unsigned int sizeof_address;
 \f
 static struct line_subseg *get_line_subseg PARAMS ((segT, subsegT));
-static unsigned int get_filenum PARAMS ((const char *));
+static unsigned int get_filenum PARAMS ((const char *, unsigned int));
 static struct frag *first_frag_for_seg PARAMS ((segT));
 static struct frag *last_frag_for_seg PARAMS ((segT));
 static void out_byte PARAMS ((int));
@@ -235,11 +246,24 @@ dwarf2_gen_line_info (ofs, loc)
 {
   struct line_subseg *ss;
   struct line_entry *e;
+  static unsigned int line = -1;
+  static unsigned int filenum = -1;
 
   /* Early out for as-yet incomplete location information.  */
   if (loc->filenum == 0 || loc->line == 0)
     return;
 
+  /* Don't emit sequences of line symbols for the same line when the
+     symbols apply to assembler code.  It is necessary to emit
+     duplicate line symbols when a compiler asks for them, because GDB
+     uses them to determine the end of the prologue.  */
+  if (debug_type == DEBUG_DWARF2
+      && line == loc->line && filenum == loc->filenum)
+    return;
+
+  line = loc->line;
+  filenum = loc->filenum;
+
   e = (struct line_entry *) xmalloc (sizeof (*e));
   e->next = NULL;
   e->frag = frag_now;
@@ -259,7 +283,7 @@ dwarf2_where (line)
     {
       char *filename;
       as_where (&filename, &line->line);
-      line->filenum = get_filenum (filename);
+      line->filenum = get_filenum (filename, 0);
       line->column = 0;
       line->flags = DWARF2_FLAG_BEGIN_STMT;
     }
@@ -278,54 +302,138 @@ dwarf2_emit_insn (size)
 {
   struct dwarf2_line_info loc;
 
-  if (debug_type != DEBUG_DWARF2 && ! loc_directive_seen)
+  if (loc_directive_seen)
+    {
+      /* Use the last location established by a .loc directive, not
+        the value returned by dwarf2_where().  That calls as_where()
+        which will return either the logical input file name (foo.c)
+       or the physical input file name (foo.s) and not the file name
+       specified in the most recent .loc directive (eg foo.h).  */
+      loc = current;
+
+      /* Unless we generate DWARF2 debugging information for each
+        assembler line, we only emit one line symbol for one LOC.  */
+      if (debug_type != DEBUG_DWARF2)
+       loc_directive_seen = FALSE;
+    }
+  else if (debug_type != DEBUG_DWARF2)
     return;
-  loc_directive_seen = false;
+  else
+    dwarf2_where (& loc);
 
-  dwarf2_where (&loc);
   dwarf2_gen_line_info (frag_now_fix () - size, &loc);
 }
 
-/* Get a .debug_line file number for FILENAME.  */
+/* Get a .debug_line file number for FILENAME.  If NUM is nonzero,
+   allocate it on that file table slot, otherwise return the first
+   empty one.  */
 
 static unsigned int
-get_filenum (filename)
+get_filenum (filename, num)
      const char *filename;
+     unsigned int num;
 {
-  static unsigned int last_used;
-  unsigned int i;
+  static unsigned int last_used, last_used_dir_len;
+  const char *file;
+  size_t dir_len;
+  unsigned int i, dir;
 
-  if (last_used)
-    if (strcmp (filename, files[last_used].filename) == 0)
-      return last_used;
+  if (num == 0 && last_used)
+    {
+      if (! files[last_used].dir
+         && strcmp (filename, files[last_used].filename) == 0)
+       return last_used;
+      if (files[last_used].dir
+         && strncmp (filename, dirs[files[last_used].dir],
+                     last_used_dir_len) == 0
+         && IS_DIR_SEPARATOR (filename [last_used_dir_len])
+         && strcmp (filename + last_used_dir_len + 1,
+                    files[last_used].filename) == 0)
+       return last_used;
+    }
 
-  for (i = 1; i < files_in_use; ++i)
-    if (strcmp (filename, files[i].filename) == 0)
-      return i;
+  file = lbasename (filename);
+  /* Don't make empty string from / or A: from A:/ .  */
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  if (file <= filename + 3)
+    file = filename;
+#else
+  if (file == filename + 1)
+    file = filename;
+#endif
+  dir_len = file - filename;
+
+  dir = 0;
+  if (dir_len)
+    {
+      --dir_len;
+      for (dir = 1; dir < dirs_in_use; ++dir)
+       if (memcmp (filename, dirs[dir], dir_len) == 0
+           && dirs[dir][dir_len] == '\0')
+         break;
+
+      if (dir >= dirs_in_use)
+       {
+         if (dir >= dirs_allocated)
+           {
+             dirs_allocated = dir + 32;
+             dirs = (char **)
+                    xrealloc (dirs, (dir + 32) * sizeof (const char *));
+           }
+
+         dirs[dir] = xmalloc (dir_len + 1);
+         memcpy (dirs[dir], filename, dir_len);
+         dirs[dir][dir_len] = '\0';
+         dirs_in_use = dir + 1;
+       }
+    }
+
+  if (num == 0)
+    {
+      for (i = 1; i < files_in_use; ++i)
+       if (files[i].dir == dir
+           && strcmp (file, files[i].filename) == 0)
+         {
+           last_used = i;
+           last_used_dir_len = dir_len;
+           return i;
+         }
+    }
+  else
+    i = num;
 
   if (i >= files_allocated)
     {
+      unsigned int old = files_allocated;
+
       files_allocated = i + 32;
       files = (struct file_entry *)
        xrealloc (files, (i + 32) * sizeof (struct file_entry));
+
+      memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry));
     }
 
-  files[i].filename = xstrdup (filename);
-  files[i].dir = 0;
+  files[i].filename = num ? file : xstrdup (file);
+  files[i].dir = dir;
   files_in_use = i + 1;
   last_used = i;
+  last_used_dir_len = dir_len;
 
   return i;
 }
 
-/* Handle the .file directive.  */
+/* Handle two forms of .file directive:
+   - Pass .file "source.c" to s_app_file
+   - Handle .file 1 "source.c" by adding an entry to the DWARF-2 file table
 
-void
+   If an entry is added to the file table, return a pointer to the filename. */
+
+char *
 dwarf2_directive_file (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   offsetT num;
-  const char *filename;
+  char *filename;
   int filename_len;
 
   /* Continue to accept a bare string and pass it off.  */
@@ -333,32 +441,28 @@ dwarf2_directive_file (dummy)
   if (*input_line_pointer == '"')
     {
       s_app_file (0);
-      return;
+      return NULL;
     }
 
   num = get_absolute_expression ();
   filename = demand_copy_C_string (&filename_len);
   demand_empty_rest_of_line ();
 
-  if (num < 0)
+  if (num < 1)
     {
-      as_bad (_("File number less than zero"));
-      return;
+      as_bad (_("file number less than one"));
+      return NULL;
     }
 
-  if (num >= (int) user_filenum_allocated)
+  if (num < (int) files_in_use && files[num].filename != 0)
     {
-      unsigned int old = user_filenum_allocated;
-
-      user_filenum_allocated = num + 16;
-      user_filenum = (unsigned int *)
-       xrealloc (user_filenum, (num + 16) * sizeof (unsigned int));
-
-      /* Zero the new memory.  */
-      memset (user_filenum + old, 0, (num + 16 - old) * sizeof (unsigned int));
+      as_bad (_("file number %ld already allocated"), (long) num);
+      return NULL;
     }
 
-  user_filenum[num] = get_filenum (filename);
+  get_filenum (filename, num);
+
+  return filename;
 }
 
 void
@@ -374,28 +478,43 @@ dwarf2_directive_loc (dummy)
   column = get_absolute_expression ();
   demand_empty_rest_of_line ();
 
-  if (filenum < 0)
+  if (filenum < 1)
     {
-      as_bad (_("File number less than zero"));
+      as_bad (_("file number less than one"));
       return;
     }
-  if (filenum >= (int) user_filenum_allocated
-      || user_filenum[filenum] == 0)
+  if (filenum >= (int) files_in_use || files[filenum].filename == 0)
     {
-      as_bad (_("Unassigned file number %ld"), (long) filenum);
+      as_bad (_("unassigned file number %ld"), (long) filenum);
       return;
     }
 
-  current.filenum = user_filenum[filenum];
+  current.filenum = filenum;
   current.line = line;
   current.column = column;
   current.flags = DWARF2_FLAG_BEGIN_STMT;
 
-  loc_directive_seen = true;
+  loc_directive_seen = TRUE;
 
 #ifndef NO_LISTING
   if (listing)
-    listing_source_line (line);
+    {
+      if (files[filenum].dir)
+       {
+         size_t dir_len = strlen (dirs[files[filenum].dir]);
+         size_t file_len = strlen (files[filenum].filename);
+         char *cp = (char *) alloca (dir_len + 1 + file_len + 1);
+
+         memcpy (cp, dirs[files[filenum].dir], dir_len);
+         cp[dir_len] = '/';
+         memcpy (cp + dir_len + 1, files[filenum].filename, file_len);
+         cp[dir_len + file_len + 1] = '\0';
+         listing_source_file (cp);
+       }
+      else
+       listing_source_file (files[filenum].filename);
+      listing_source_line (line);
+    }
 #endif
 }
 \f
@@ -518,8 +637,9 @@ get_frag_fix (frag)
   for (fr = frchain_root; fr; fr = fr->frch_next)
     if (fr->frch_last == frag)
       {
-       return ((char *) obstack_next_free (&fr->frch_obstack)
-               - frag->fr_literal);
+       long align_mask = -1 << get_recorded_alignment (fr->frch_seg);
+       return (((char *) obstack_next_free (&fr->frch_obstack)
+                - frag->fr_literal) + ~align_mask) & align_mask;
       }
 
   abort ();
@@ -548,6 +668,26 @@ out_set_addr (seg, frag, ofs)
   emit_expr (&expr, sizeof_address);
 }
 
+#if DWARF2_LINE_MIN_INSN_LENGTH > 1
+static void scale_addr_delta PARAMS ((addressT *));
+
+static void
+scale_addr_delta (addr_delta)
+     addressT *addr_delta;
+{
+  static int printed_this = 0;
+  if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0)
+    {
+      if (!printed_this)
+       as_bad("unaligned opcodes detected in executable segment");
+      printed_this = 1;
+    }
+  *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.
 
@@ -564,10 +704,7 @@ size_inc_line_addr (line_delta, addr_delta)
   int len = 0;
 
   /* Scale the address delta by the minimum instruction length.  */
-#if DWARF2_LINE_MIN_INSN_LENGTH > 1
-  assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0);
-  addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
-#endif
+  scale_addr_delta (&addr_delta);
 
   /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.
      We cannot use special opcodes here, since we want the end_sequence
@@ -630,11 +767,9 @@ emit_inc_line_addr (line_delta, addr_delta, p, len)
   int need_copy = 0;
   char *end = p + len;
 
-#if DWARF2_LINE_MIN_INSN_LENGTH > 1
   /* Scale the address delta by the minimum instruction length.  */
-  assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0);
-  addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH;
-#endif
+  scale_addr_delta (&addr_delta);
+
   /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence.
      We cannot use special opcodes here, since we want the end_sequence
      to emit the matrix entry.  */
@@ -766,7 +901,7 @@ dwarf2dbg_estimate_size_before_relax (frag)
   offsetT addr_delta;
   int size;
 
-  addr_delta = resolve_symbol_value (frag->fr_symbol, 0);
+  addr_delta = resolve_symbol_value (frag->fr_symbol);
   size = size_inc_line_addr (frag->fr_offset, addr_delta);
 
   frag->fr_subtype = size;
@@ -800,7 +935,7 @@ dwarf2dbg_convert_frag (frag)
 {
   offsetT addr_diff;
 
-  addr_diff = resolve_symbol_value (frag->fr_symbol, 1);
+  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
@@ -867,7 +1002,11 @@ process_entries (seg, e)
          changed = 1;
        }
 
-      if (line != e->loc.line || changed)
+      /* Don't try to optimize away redundant entries; gdb wants two
+        entries for a function where the code starts on the same line as
+        the {, and there's no way to identify that case here.  Trust gcc
+        to optimize appropriately.  */
+      if (1 /* line != e->loc.line || changed */)
        {
          int line_delta = e->loc.line - line;
          if (frag == NULL)
@@ -916,11 +1055,24 @@ out_file_list ()
   char *cp;
   unsigned int i;
 
-  /* Terminate directory list.  */
+  /* Emit directory list.  */
+  for (i = 1; i < dirs_in_use; ++i)
+    {
+      size = strlen (dirs[i]) + 1;
+      cp = frag_more (size);
+      memcpy (cp, dirs[i], size);
+    }
+  /* Terminate it.  */
   out_byte ('\0');
 
   for (i = 1; i < files_in_use; ++i)
     {
+      if (files[i].filename == NULL)
+       {
+         as_bad (_("unassigned file number %ld"), (long) i);
+         continue;
+       }
+
       size = strlen (files[i].filename) + 1;
       cp = frag_more (size);
       memcpy (cp, files[i].filename, size);
@@ -945,6 +1097,8 @@ out_debug_line (line_seg)
   symbolS *prologue_end;
   symbolS *line_end;
   struct line_seg *s;
+  enum dwarf2_format d2f;
+  int sizeof_offset;
 
   subseg_set (line_seg, 0);
 
@@ -956,8 +1110,31 @@ out_debug_line (line_seg)
   expr.X_op = O_subtract;
   expr.X_add_symbol = line_end;
   expr.X_op_symbol = line_start;
-  expr.X_add_number = -4;
-  emit_expr (&expr, 4);
+
+  d2f = DWARF2_FORMAT ();
+  if (d2f == dwarf2_format_32bit)
+    {
+      expr.X_add_number = -4;
+      emit_expr (&expr, 4);
+      sizeof_offset = 4;
+    }
+  else if (d2f == dwarf2_format_64bit)
+    {
+      expr.X_add_number = -12;
+      out_four (-1);
+      emit_expr (&expr, 8);
+      sizeof_offset = 8;
+    }
+  else if (d2f == dwarf2_format_64bit_irix)
+    {
+      expr.X_add_number = -8;
+      emit_expr (&expr, 8);
+      sizeof_offset = 8;
+    }
+  else
+    {
+      as_fatal (_("internal error: unknown dwarf2 format"));
+    }
 
   /* Version.  */
   out_two (2);
@@ -967,7 +1144,7 @@ out_debug_line (line_seg)
   expr.X_add_symbol = prologue_end;
   expr.X_op_symbol = line_start;
   expr.X_add_number = - (4 + 2 + 4);
-  emit_expr (&expr, 4);
+  emit_expr (&expr, sizeof_offset);
 
   /* Parameters of the state machine.  */
   out_byte (DWARF2_LINE_MIN_INSN_LENGTH);
@@ -1095,6 +1272,7 @@ out_debug_abbrev (abbrev_seg)
       out_abbrev (DW_AT_low_pc, DW_FORM_addr);
       out_abbrev (DW_AT_high_pc, DW_FORM_addr);
     }
+  out_abbrev (DW_AT_name, DW_FORM_string);
   out_abbrev (DW_AT_comp_dir, DW_FORM_string);
   out_abbrev (DW_AT_producer, DW_FORM_string);
   out_abbrev (DW_AT_language, DW_FORM_data2);
@@ -1119,6 +1297,8 @@ out_debug_info (info_seg, abbrev_seg, line_seg)
   symbolS *info_end;
   char *p;
   int len;
+  enum dwarf2_format d2f;
+  int sizeof_offset;
 
   subseg_set (info_seg, 0);
 
@@ -1129,8 +1309,31 @@ out_debug_info (info_seg, abbrev_seg, line_seg)
   expr.X_op = O_subtract;
   expr.X_add_symbol = info_end;
   expr.X_op_symbol = info_start;
-  expr.X_add_number = -4;
-  emit_expr (&expr, 4);
+
+  d2f = DWARF2_FORMAT ();
+  if (d2f == dwarf2_format_32bit)
+    {
+      expr.X_add_number = -4;
+      emit_expr (&expr, 4);
+      sizeof_offset = 4;
+    }
+  else if (d2f == dwarf2_format_64bit)
+    {
+      expr.X_add_number = -12;
+      out_four (-1);
+      emit_expr (&expr, 8);
+      sizeof_offset = 8;
+    }
+  else if (d2f == dwarf2_format_64bit_irix)
+    {
+      expr.X_add_number = -8;
+      emit_expr (&expr, 8);
+      sizeof_offset = 8;
+    }
+  else
+    {
+      as_fatal (_("internal error: unknown dwarf2 format"));
+    }
 
   /* DWARF version.  */
   out_two (2);
@@ -1139,7 +1342,7 @@ out_debug_info (info_seg, abbrev_seg, line_seg)
   expr.X_op = O_symbol;
   expr.X_add_symbol = section_symbol (abbrev_seg);
   expr.X_add_number = 0;
-  emit_expr (&expr, 4);
+  emit_expr (&expr, sizeof_offset);
 
   /* Target address size.  */
   out_byte (sizeof_address);
@@ -1170,6 +1373,23 @@ out_debug_info (info_seg, abbrev_seg, line_seg)
       emit_expr (&expr, sizeof_address);
     }
 
+  /* DW_AT_name.  We don't have the actual file name that was present
+     on the command line, so assume files[1] is the main input file.
+     We're not supposed to get called unless at least one line number
+     entry was emitted, so this should always be defined.  */
+  if (!files || files_in_use < 1)
+    abort ();
+  if (files[1].dir)
+    {
+      len = strlen (dirs[files[1].dir]);
+      p = frag_more (len + 1);
+      memcpy (p, dirs[files[1].dir], len);
+      p[len] = '/';
+    }
+  len = strlen (files[1].filename) + 1;
+  p = frag_more (len);
+  memcpy (p, files[1].filename, len);
+
   /* DW_AT_comp_dir */
   comp_dir = getpwd ();
   len = strlen (comp_dir) + 1;
@@ -1195,12 +1415,19 @@ dwarf2_finish ()
   segT line_seg;
   struct line_seg *s;
 
-  /* If no debug information was recorded, nothing to do.  */
-  if (all_segs == NULL)
+  /* We don't need to do anything unless:
+     - Some debug information was recorded via .file/.loc
+     - or, we are generating DWARF2 information ourself (--gdwarf2)
+     - or, there is a user-provided .debug_info section which could
+       reference the file table in the .debug_line section we generate
+       below.  */
+  if (all_segs == NULL
+      && debug_type != DEBUG_DWARF2
+      && bfd_get_section_by_name (stdoutput, ".debug_info") == NULL)
     return;
 
   /* Calculate the size of an address for the target machine.  */
-  sizeof_address = bfd_arch_bits_per_address (stdoutput) / 8;
+  sizeof_address = DWARF2_ADDR_SIZE (stdoutput);
 
   /* Create and switch to the line number section.  */
   line_seg = subseg_new (".debug_line", 0);
@@ -1223,7 +1450,7 @@ dwarf2_finish ()
 
   /* If this is assembler generated line info, we need .debug_info
      and .debug_abbrev sections as well.  */
-  if (debug_type == DEBUG_DWARF2)
+  if (all_segs != NULL && debug_type == DEBUG_DWARF2)
     {
       segT abbrev_seg;
       segT info_seg;
@@ -1280,11 +1507,12 @@ dwarf2_emit_insn (size)
 {
 }
 
-void
+char *
 dwarf2_directive_file (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  as_fatal (_("dwarf2 is not supported for this object file format"));
+  s_app_file (0);
+  return NULL;
 }
 
 void
This page took 0.030955 seconds and 4 git commands to generate.