2002-09-27 David Carlton <carlton@math.stanford.edu>
[deliverable/binutils-gdb.git] / bfd / dwarf2.c
index 1c02912d214f390804b5bffdbfae2d7ccdb41754..7c000b9890e54562186aaa1f11fda3d42f2cf9c1 100644 (file)
@@ -1,5 +1,6 @@
 /* DWARF 2 support.
-   Copyright 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
    Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
    (gavin@cygnus.com).
    based on Fred Fish's (Cygnus Support) implementation of DWARF 1
    support in dwarfread.c
 
-This file is part of BFD.
+   This file is part of BFD.
 
-This program 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 of the License, or (at
-your option) any later version.
+   This program 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 of the License, or (at
+   your option) any later version.
 
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
@@ -36,36 +37,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "elf/dwarf2.h"
 
 /* The data in the .debug_line statement prologue looks like this.  */
+
 struct line_head
-  {
-    unsigned int total_length;
-    unsigned short version;
-    unsigned int prologue_length;
-    unsigned char minimum_instruction_length;
-    unsigned char default_is_stmt;
-    int line_base;
-    unsigned char line_range;
-    unsigned char opcode_base;
-    unsigned char *standard_opcode_lengths;
-  };
-
-/* Attributes have a name and a value */
+{
+  bfd_vma total_length;
+  unsigned short version;
+  bfd_vma prologue_length;
+  unsigned char minimum_instruction_length;
+  unsigned char default_is_stmt;
+  int line_base;
+  unsigned char line_range;
+  unsigned char opcode_base;
+  unsigned char *standard_opcode_lengths;
+};
+
+/* Attributes have a name and a value.  */
+
 struct attribute
+{
+  enum dwarf_attribute name;
+  enum dwarf_form form;
+  union
   {
-    enum dwarf_attribute name;
-    enum dwarf_form form;
-    union
-      {
-       char *str;
-       struct dwarf_block *blk;
-       unsigned int unsnd;
-       int snd;
-       bfd_vma addr;
-      }
-    u;
-  };
+    char *str;
+    struct dwarf_block *blk;
+    unsigned int unsnd;
+    int snd;
+    bfd_vma addr;
+  }
+  u;
+};
 
-/* Get at parts of an attribute structure */
+/* Get at parts of an attribute structure */
 
 #define DW_STRING(attr)    ((attr)->u.str)
 #define DW_UNSND(attr)     ((attr)->u.unsnd)
@@ -73,31 +76,38 @@ struct attribute
 #define DW_SND(attr)       ((attr)->u.snd)
 #define DW_ADDR(attr)     ((attr)->u.addr)
 
-/* Blocks are a bunch of untyped bytes. */
+/* Blocks are a bunch of untyped bytes.  */
 struct dwarf_block
-  {
-    unsigned int size;
-    char *data;
-  };
-
-
-struct dwarf2_debug {
+{
+  unsigned int size;
+  char *data;
+};
 
-  /* A list of all previously read comp_units. */
+struct dwarf2_debug
+{
+  /* A list of all previously read comp_units.  */
   struct comp_unit* all_comp_units;
 
   /* The next unread compilation unit within the .debug_info section.
      Zero indicates that the .debug_info section has not been loaded
-     into a buffer yet.*/
+     into a buffer yet.  */
   char* info_ptr;
 
-  /* Pointer to the end of the .debug_info section memory buffer. */
+  /* Pointer to the end of the .debug_info section memory buffer.  */
   char* info_ptr_end;
 
-  /* Pointer to the .debug_abbrev section loaded into memory. */
+  /* Pointer to the section and address of the beginning of the
+     section.  */
+  asection* sec;
+  char* sec_info_ptr;
+
+  /* Pointer to the symbol table.  */
+  asymbol** syms;
+
+  /* Pointer to the .debug_abbrev section loaded into memory.  */
   char* dwarf_abbrev_buffer;
 
-  /* Length of the loaded .debug_abbrev section. */
+  /* Length of the loaded .debug_abbrev section.  */
   unsigned long dwarf_abbrev_size;
 
   /* Buffer for decode_line_info.  */
@@ -105,71 +115,152 @@ struct dwarf2_debug {
 
   /* Length of the loaded .debug_line section.  */
   unsigned long dwarf_line_size;
+
+  /* Pointer to the .debug_str section loaded into memory.  */
+  char* dwarf_str_buffer;
+
+  /* Length of the loaded .debug_str section.  */
+  unsigned long dwarf_str_size;
 };
 
-struct arange {
+struct arange
+{
   struct arange *next;
   bfd_vma low;
   bfd_vma high;
 };
 
-
 /* A minimal decoding of DWARF2 compilation units.  We only decode
-   what's needed to get to the line number information. */
+   what's needed to get to the line number information.  */
 
-struct comp_unit {
-
-  /* Chain the previously read compilation units. */
+struct comp_unit
+{
+  /* Chain the previously read compilation units.  */
   struct comp_unit* next_unit;
 
-  /* Keep the bdf convenient (for memory allocation). */
+  /* Keep the bdf convenient (for memory allocation).  */
   bfd* abfd;
 
   /* The lowest and higest addresses contained in this compilation
-     unit as specified in the compilation unit header. */
+     unit as specified in the compilation unit header.  */
   struct arange arange;
 
-  /* The DW_AT_name attribute (for error messages). */
+  /* The DW_AT_name attribute (for error messages).  */
   char* name;
 
-  /* The abbrev hash table. */
+  /* The abbrev hash table.  */
   struct abbrev_info** abbrevs;
 
-  /* Note that an error was found by comp_unit_find_nearest_line. */
+  /* Note that an error was found by comp_unit_find_nearest_line.  */
   int error;
 
-  /* The DW_AT_comp_dir attribute */
+  /* The DW_AT_comp_dir attribute */
   char* comp_dir;
 
-  /* True if there is a line number table associated with this comp. unit. */
+  /* True if there is a line number table associated with this comp. unit.  */
   int stmtlist;
-  
-  /* The offset into .debug_line of the line number table. */
+
+  /* The offset into .debug_line of the line number table.  */
   unsigned long line_offset;
 
-  /* Pointer to the first child die for the comp unit. */
+  /* Pointer to the first child die for the comp unit.  */
   char *first_child_die_ptr;
 
-  /* The end of the comp unit. */
+  /* The end of the comp unit.  */
   char *end_ptr;
 
-  /* The decoded line number, NULL if not yet decoded. */
+  /* The decoded line number, NULL if not yet decoded.  */
   struct line_info_table* line_table;
 
-  /* A list of the functions found in this comp. unit. */
-  struct funcinfo* function_table; 
+  /* A list of the functions found in this comp. unit.  */
+  struct funcinfo* function_table;
+
+  /* Pointer to dwarf2_debug structure.  */
+  struct dwarf2_debug *stash;
 
-  /* Address size for this unit - from unit header */
+  /* Address size for this unit - from unit header */
   unsigned char addr_size;
+
+  /* Offset size for this unit - from unit header.  */
+  unsigned char offset_size;
 };
 
+/* This data structure holds the information of an abbrev.  */
+struct abbrev_info
+{
+  unsigned int number;         /* Number identifying abbrev.  */
+  enum dwarf_tag tag;          /* DWARF tag.  */
+  int has_children;            /* Boolean.  */
+  unsigned int num_attrs;      /* Number of attributes.  */
+  struct attr_abbrev *attrs;   /* An array of attribute descriptions.  */
+  struct abbrev_info *next;    /* Next in chain.  */
+};
 
+struct attr_abbrev
+{
+  enum dwarf_attribute name;
+  enum dwarf_form form;
+};
 
-/* VERBATIM 
-   The following function up to the END VERBATIM mark are 
-   copied directly from dwarf2read.c. */
+#ifndef ABBREV_HASH_SIZE
+#define ABBREV_HASH_SIZE 121
+#endif
+#ifndef ATTR_ALLOC_CHUNK
+#define ATTR_ALLOC_CHUNK 4
+#endif
 
-/* read dwarf information from a buffer */
+static unsigned int read_1_byte PARAMS ((bfd *, char *));
+static int read_1_signed_byte PARAMS ((bfd *, char *));
+static unsigned int read_2_bytes PARAMS ((bfd *, char *));
+static unsigned int read_4_bytes PARAMS ((bfd *, char *));
+static bfd_vma read_8_bytes PARAMS ((bfd *, char *));
+static char *read_n_bytes PARAMS ((bfd *, char *, unsigned int));
+static char *read_string PARAMS ((bfd *, char *, unsigned int *));
+static char *read_indirect_string PARAMS ((struct comp_unit *, char *, unsigned int *));
+static unsigned int read_unsigned_leb128
+  PARAMS ((bfd *, char *, unsigned int *));
+static int read_signed_leb128
+  PARAMS ((bfd *, char *, unsigned int *));
+static bfd_vma read_address PARAMS ((struct comp_unit *, char *));
+static struct abbrev_info *lookup_abbrev
+  PARAMS ((unsigned int, struct abbrev_info **));
+static struct abbrev_info **read_abbrevs
+  PARAMS ((bfd *, bfd_vma, struct dwarf2_debug *));
+static char *read_attribute
+  PARAMS ((struct attribute *, struct attr_abbrev *,
+          struct comp_unit *, char *));
+static char *read_attribute_value
+  PARAMS ((struct attribute *, unsigned,
+          struct comp_unit *, char *));
+static void add_line_info
+  PARAMS ((struct line_info_table *, bfd_vma, char *,
+          unsigned int, unsigned int, int));
+static char *concat_filename PARAMS ((struct line_info_table *, unsigned int));
+static void arange_add PARAMS ((struct comp_unit *, bfd_vma, bfd_vma));
+static struct line_info_table *decode_line_info
+  PARAMS ((struct comp_unit *, struct dwarf2_debug *));
+static boolean lookup_address_in_line_info_table
+  PARAMS ((struct line_info_table *, bfd_vma, struct funcinfo *,
+          const char **, unsigned int *));
+static boolean lookup_address_in_function_table
+  PARAMS ((struct funcinfo *, bfd_vma, struct funcinfo **, const char **));
+static boolean scan_unit_for_functions PARAMS ((struct comp_unit *));
+static bfd_vma find_rela_addend
+  PARAMS ((bfd *, asection *, bfd_size_type, asymbol**));
+static struct comp_unit *parse_comp_unit
+  PARAMS ((bfd *, struct dwarf2_debug *, bfd_vma, unsigned int));
+static boolean comp_unit_contains_address
+  PARAMS ((struct comp_unit *, bfd_vma));
+static boolean comp_unit_find_nearest_line
+  PARAMS ((struct comp_unit *, bfd_vma, const char **, const char **,
+          unsigned int *, struct dwarf2_debug *));
+static asection *find_debug_info PARAMS ((bfd *, asection *));
+
+/* VERBATIM
+   The following function up to the END VERBATIM mark are
+   copied directly from dwarf2read.c.  */
+
+/* Read dwarf information from a buffer.  */
 
 static unsigned int
 read_1_byte (abfd, buf)
@@ -195,9 +286,7 @@ read_2_bytes (abfd, buf)
   return bfd_get_16 (abfd, (bfd_byte *) buf);
 }
 
-#if 0
-
-/* This is not used.  */
+#if 0  /* This is not used.  */
 
 static int
 read_2_signed_bytes (abfd, buf)
@@ -217,9 +306,7 @@ read_4_bytes (abfd, buf)
   return bfd_get_32 (abfd, (bfd_byte *) buf);
 }
 
-#if 0
-
-/* This is not used.  */
+#if 0  /* This is not used.  */
 
 static int
 read_4_signed_bytes (abfd, buf)
@@ -231,7 +318,7 @@ read_4_signed_bytes (abfd, buf)
 
 #endif
 
-static unsigned int
+static bfd_vma
 read_8_bytes (abfd, buf)
      bfd *abfd;
      char *buf;
@@ -257,18 +344,70 @@ read_string (abfd, buf, bytes_read_ptr)
      char *buf;
      unsigned int *bytes_read_ptr;
 {
-  /* If the size of a host char is 8 bits, we can return a pointer
-     to the string, otherwise we have to copy the string to a buffer
-     allocated on the temporary obstack.  */
+  /* Return a pointer to the embedded string.  */
   if (*buf == '\0')
     {
       *bytes_read_ptr = 1;
       return NULL;
     }
+
   *bytes_read_ptr = strlen (buf) + 1;
   return buf;
 }
 
+static char *
+read_indirect_string (unit, buf, bytes_read_ptr)
+     struct comp_unit* unit;
+     char *buf;
+     unsigned int *bytes_read_ptr;
+{
+  bfd_vma offset;
+  struct dwarf2_debug *stash = unit->stash;
+
+  if (unit->offset_size == 4)
+    offset = read_4_bytes (unit->abfd, buf);
+  else
+    offset = read_8_bytes (unit->abfd, buf);
+  *bytes_read_ptr = unit->offset_size;
+
+  if (! stash->dwarf_str_buffer)
+    {
+      asection *msec;
+      bfd *abfd = unit->abfd;
+
+      msec = bfd_get_section_by_name (abfd, ".debug_str");
+      if (! msec)
+       {
+         (*_bfd_error_handler)
+           (_("Dwarf Error: Can't find .debug_str section."));
+         bfd_set_error (bfd_error_bad_value);
+         return NULL;
+       }
+
+      stash->dwarf_str_size = msec->_raw_size;
+      stash->dwarf_str_buffer = (char*) bfd_alloc (abfd, msec->_raw_size);
+      if (! stash->dwarf_abbrev_buffer)
+       return NULL;
+
+      if (! bfd_get_section_contents (abfd, msec, stash->dwarf_str_buffer,
+                                     (bfd_vma) 0, msec->_raw_size))
+       return NULL;
+    }
+
+  if (offset >= stash->dwarf_str_size)
+    {
+      (*_bfd_error_handler) (_("Dwarf Error: DW_FORM_strp offset (%lu) greater than or equal to .debug_str size (%lu)."),
+                            (unsigned long) offset, stash->dwarf_str_size);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+
+  buf = stash->dwarf_str_buffer + offset;  
+  if (*buf == '\0')
+    return NULL;
+  return buf;
+}
+
 static unsigned int
 read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
      bfd *abfd ATTRIBUTE_UNUSED;
@@ -283,7 +422,7 @@ read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
   result   = 0;
   shift    = 0;
   num_read = 0;
-  
+
   do
     {
       byte = bfd_get_8 (abfd, (bfd_byte *) buf);
@@ -293,9 +432,9 @@ read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
       shift += 7;
     }
   while (byte & 0x80);
-  
+
   * bytes_read_ptr = num_read;
-  
+
   return result;
 }
 
@@ -323,12 +462,12 @@ read_signed_leb128 (abfd, buf, bytes_read_ptr)
       shift += 7;
     }
   while (byte & 0x80);
-  
+
   if ((shift < 32) && (byte & 0x40))
     result |= -(1 << shift);
 
   * bytes_read_ptr = num_read;
-  
+
   return result;
 }
 
@@ -352,34 +491,6 @@ read_address (unit, buf)
     }
 }
 
-
-
-
-
-/* This data structure holds the information of an abbrev. */
-struct abbrev_info
-  {
-    unsigned int number;       /* number identifying abbrev */
-    enum dwarf_tag tag;                /* dwarf tag */
-    int has_children;          /* boolean */
-    unsigned int num_attrs;    /* number of attributes */
-    struct attr_abbrev *attrs; /* an array of attribute descriptions */
-    struct abbrev_info *next;  /* next in chain */
-  };
-
-struct attr_abbrev
-  {
-    enum dwarf_attribute name;
-    enum dwarf_form form;
-  };
-
-#ifndef ABBREV_HASH_SIZE
-#define ABBREV_HASH_SIZE 121
-#endif
-#ifndef ATTR_ALLOC_CHUNK
-#define ATTR_ALLOC_CHUNK 4
-#endif
-
 /* Lookup an abbrev_info structure in the abbrev hash table.  */
 
 static struct abbrev_info *
@@ -400,6 +511,7 @@ lookup_abbrev (number,abbrevs)
       else
        abbrev = abbrev->next;
     }
+
   return NULL;
 }
 
@@ -409,18 +521,17 @@ lookup_abbrev (number,abbrevs)
    in a hash table.  */
 
 static struct abbrev_info**
-read_abbrevs (abfd, offset)
+read_abbrevs (abfd, offset, stash)
      bfd * abfd;
-     unsigned int offset;
+     bfd_vma offset;
+     struct dwarf2_debug *stash;
 {
   struct abbrev_info **abbrevs;
   char *abbrev_ptr;
   struct abbrev_info *cur_abbrev;
   unsigned int abbrev_number, bytes_read, abbrev_name;
   unsigned int abbrev_form, hash_number;
-  struct dwarf2_debug *stash;
-
-  stash = elf_tdata(abfd)->dwarf2_find_line_info;
+  bfd_size_type amt;
 
   if (! stash->dwarf_abbrev_buffer)
     {
@@ -433,60 +544,63 @@ read_abbrevs (abfd, offset)
          bfd_set_error (bfd_error_bad_value);
          return 0;
        }
-      
+
       stash->dwarf_abbrev_size = msec->_raw_size;
-      stash->dwarf_abbrev_buffer = (char*) bfd_alloc (abfd, stash->dwarf_abbrev_size);
+      stash->dwarf_abbrev_buffer = (char*) bfd_alloc (abfd, msec->_raw_size);
       if (! stash->dwarf_abbrev_buffer)
          return 0;
-      
-      if (! bfd_get_section_contents (abfd, msec, 
-                                     stash->dwarf_abbrev_buffer, 0,
-                                     stash->dwarf_abbrev_size))
+
+      if (! bfd_get_section_contents (abfd, msec, stash->dwarf_abbrev_buffer,
+                                     (bfd_vma) 0, msec->_raw_size))
        return 0;
     }
 
-  if (offset > stash->dwarf_abbrev_size)
+  if (offset >= stash->dwarf_abbrev_size)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%u) bigger than abbrev size (%u)."), 
-                            offset, stash->dwarf_abbrev_size );
+      (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%lu) greater than or equal to .debug_abbrev size (%lu)."),
+                            (unsigned long) offset, stash->dwarf_abbrev_size);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
-  abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, sizeof(struct abbrev_info*) * ABBREV_HASH_SIZE);
+  amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
+  abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, amt);
 
   abbrev_ptr = stash->dwarf_abbrev_buffer + offset;
   abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
   abbrev_ptr += bytes_read;
 
-  /* loop until we reach an abbrev number of 0 */
+  /* Loop until we reach an abbrev number of 0.  */
   while (abbrev_number)
     {
-      cur_abbrev = (struct abbrev_info*)bfd_zalloc (abfd, sizeof (struct abbrev_info));
+      amt = sizeof (struct abbrev_info);
+      cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt);
 
-      /* read in abbrev header */
+      /* Read in abbrev header.  */
       cur_abbrev->number = abbrev_number;
       cur_abbrev->tag = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
       abbrev_ptr += bytes_read;
       cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
       abbrev_ptr += 1;
 
-      /* now read in declarations */
+      /* Now read in declarations.  */
       abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
       abbrev_ptr += bytes_read;
       abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
       abbrev_ptr += bytes_read;
+
       while (abbrev_name)
        {
          if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0)
            {
-             cur_abbrev->attrs = (struct attr_abbrev *)
-               bfd_realloc (cur_abbrev->attrs,
-                            (cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK)
-                            * sizeof (struct attr_abbrev));
+             amt = cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK;
+             amt *= sizeof (struct attr_abbrev);
+             cur_abbrev->attrs = ((struct attr_abbrev *)
+                                  bfd_realloc (cur_abbrev->attrs, amt));
              if (! cur_abbrev->attrs)
                return 0;
            }
+
          cur_abbrev->attrs[cur_abbrev->num_attrs].name = abbrev_name;
          cur_abbrev->attrs[cur_abbrev->num_attrs++].form = abbrev_form;
          abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
@@ -518,30 +632,33 @@ read_abbrevs (abfd, offset)
   return abbrevs;
 }
 
-/* Read an attribute described by an abbreviated attribute.  */
+/* Read an attribute value described by an attribute form.  */
 
 static char *
-read_attribute (attr, abbrev, unit, info_ptr)
+read_attribute_value (attr, form, unit, info_ptr)
      struct attribute   *attr;
-     struct attr_abbrev *abbrev;
+     unsigned form;
      struct comp_unit   *unit;
      char               *info_ptr;
 {
   bfd *abfd = unit->abfd;
   unsigned int bytes_read;
   struct dwarf_block *blk;
+  bfd_size_type amt;
 
-  attr->name = abbrev->name;
-  attr->form = abbrev->form;
-  switch (abbrev->form)
+  attr->form = form;
+
+  switch (form)
     {
     case DW_FORM_addr:
+      /* FIXME: DWARF3 draft sais DW_FORM_ref_addr is offset_size.  */
     case DW_FORM_ref_addr:
       DW_ADDR (attr) = read_address (unit, info_ptr);
       info_ptr += unit->addr_size;
       break;
     case DW_FORM_block2:
-      blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+      amt = sizeof (struct dwarf_block);
+      blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       blk->size = read_2_bytes (abfd, info_ptr);
       info_ptr += 2;
       blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -549,7 +666,8 @@ read_attribute (attr, abbrev, unit, info_ptr)
       DW_BLOCK (attr) = blk;
       break;
     case DW_FORM_block4:
-      blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+      amt = sizeof (struct dwarf_block);
+      blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       blk->size = read_4_bytes (abfd, info_ptr);
       info_ptr += 4;
       blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -572,8 +690,13 @@ read_attribute (attr, abbrev, unit, info_ptr)
       DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
+    case DW_FORM_strp:
+      DW_STRING (attr) = read_indirect_string (unit, info_ptr, &bytes_read);
+      info_ptr += bytes_read;
+      break;
     case DW_FORM_block:
-      blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+      amt = sizeof (struct dwarf_block);
+      blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -581,7 +704,8 @@ read_attribute (attr, abbrev, unit, info_ptr)
       DW_BLOCK (attr) = blk;
       break;
     case DW_FORM_block1:
-      blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+      amt = sizeof (struct dwarf_block);
+      blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       blk->size = read_1_byte (abfd, info_ptr);
       info_ptr += 1;
       blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -624,52 +748,76 @@ read_attribute (attr, abbrev, unit, info_ptr)
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
-    case DW_FORM_strp:
     case DW_FORM_indirect:
+      form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      info_ptr += bytes_read;
+      info_ptr = read_attribute_value (attr, form, unit, info_ptr);
+      break;
     default:
-      (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %d."),
-                            abbrev->form);
+      (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."),
+                            form);
       bfd_set_error (bfd_error_bad_value);
     }
   return info_ptr;
 }
 
+/* Read an attribute described by an abbreviated attribute.  */
 
-/* Source line information table routines. */
+static char *
+read_attribute (attr, abbrev, unit, info_ptr)
+     struct attribute   *attr;
+     struct attr_abbrev *abbrev;
+     struct comp_unit   *unit;
+     char               *info_ptr;
+{
+  attr->name = abbrev->name;
+  info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr);
+  return info_ptr;
+}
+
+/* Source line information table routines.  */
 
 #define FILE_ALLOC_CHUNK 5
 #define DIR_ALLOC_CHUNK 5
 
-struct line_info {
+struct line_info
+{
   struct line_info* prev_line;
-
   bfd_vma address;
   char* filename;
   unsigned int line;
   unsigned int column;
-  int end_sequence;            /* end of (sequential) code sequence */
+  int end_sequence;            /* End of (sequential) code sequence.  */
 };
 
-struct fileinfo {
+struct fileinfo
+{
   char *name;
   unsigned int dir;
   unsigned int time;
   unsigned int size;
 };
 
-struct line_info_table {
+struct line_info_table
+{
   bfd* abfd;
-
   unsigned int num_files;
   unsigned int num_dirs;
-
   char* comp_dir;
   char** dirs;
   struct fileinfo* files;
   struct line_info* last_line;
 };
 
-static void 
+struct funcinfo
+{
+  struct funcinfo *prev_func;
+  char* name;
+  bfd_vma low;
+  bfd_vma high;
+};
+
+static void
 add_line_info (table, address, filename, line, column, end_sequence)
      struct line_info_table* table;
      bfd_vma address;
@@ -678,8 +826,8 @@ add_line_info (table, address, filename, line, column, end_sequence)
      unsigned int column;
      int end_sequence;
 {
-  struct line_info* info = (struct line_info*)
-    bfd_alloc (table->abfd, sizeof (struct line_info));
+  bfd_size_type amt = sizeof (struct line_info);
+  struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, amt);
 
   info->prev_line = table->last_line;
   table->last_line = info;
@@ -691,7 +839,7 @@ add_line_info (table, address, filename, line, column, end_sequence)
   info->end_sequence = end_sequence;
 }
 
-static char
+static char *
 concat_filename (table, file)
      struct line_info_table* table;
      unsigned int file;
@@ -706,15 +854,20 @@ concat_filename (table, file)
     }
 
   filename = table->files[file - 1].name;
-  if (*filename == '/')
+  if (IS_ABSOLUTE_PATH(filename))
     return filename;
-
   else
     {
       char* dirname = (table->files[file - 1].dir
                       ? table->dirs[table->files[file - 1].dir - 1]
                       : table->comp_dir);
-      return (char*) concat (dirname, "/", filename, NULL);
+
+      /* Not all tools set DW_AT_comp_dir, so dirname may be unknown.  The
+        best we can do is return the filename part.  */
+      if (dirname == NULL)
+       return filename;
+      else
+       return (char*) concat (dirname, "/", filename, NULL);
     }
 }
 
@@ -726,8 +879,9 @@ arange_add (unit, low_pc, high_pc)
 {
   struct arange *arange;
 
-  /* first see if we can cheaply extend an existing range: */
+  /* First see if we can cheaply extend an existing range.  */
   arange = &unit->arange;
+
   do
     {
       if (low_pc == arange->high)
@@ -746,15 +900,15 @@ arange_add (unit, low_pc, high_pc)
 
   if (unit->arange.high == 0)
     {
-      /* this is the first address range: store it in unit->arange: */
+      /* This is the first address range: store it in unit->arange.  */
       unit->arange.next = 0;
       unit->arange.low = low_pc;
       unit->arange.high = high_pc;
       return;
     }
 
-  /* need to allocate a new arange and insert it into the arange list: */
-  arange = bfd_zalloc (unit->abfd, sizeof (*arange));
+  /* Need to allocate a new arange and insert it into the arange list.  */
+  arange = bfd_zalloc (unit->abfd, (bfd_size_type) sizeof (*arange));
   arange->low = low_pc;
   arange->high = high_pc;
 
@@ -762,26 +916,22 @@ arange_add (unit, low_pc, high_pc)
   unit->arange.next = arange;
 }
 
-/* Decode the line number information for UNIT. */
+/* Decode the line number information for UNIT.  */
 
 static struct line_info_table*
-decode_line_info (unit)
+decode_line_info (unit, stash)
      struct comp_unit *unit;
+     struct dwarf2_debug *stash;
 {
   bfd *abfd = unit->abfd;
-
-  struct dwarf2_debug *stash;
-
   struct line_info_table* table;
-
   char *line_ptr;
   char *line_end;
   struct line_head lh;
-  unsigned int i, bytes_read;
+  unsigned int i, bytes_read, offset_size;
   char *cur_file, *cur_dir;
   unsigned char op_code, extended_op, adj_opcode;
-
-  stash = elf_tdata (abfd)->dwarf2_find_line_info;
+  bfd_size_type amt;
 
   if (! stash->dwarf_line_buffer)
     {
@@ -794,19 +944,18 @@ decode_line_info (unit)
          bfd_set_error (bfd_error_bad_value);
          return 0;
        }
-      
+
       stash->dwarf_line_size = msec->_raw_size;
-      stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, stash->dwarf_line_size);
+      stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, msec->_raw_size);
       if (! stash->dwarf_line_buffer)
        return 0;
 
-      if (! bfd_get_section_contents (abfd, msec, 
-                                     stash->dwarf_line_buffer, 0,
-                                     stash->dwarf_line_size))
+      if (! bfd_get_section_contents (abfd, msec, stash->dwarf_line_buffer,
+                                     (bfd_vma) 0, msec->_raw_size))
        return 0;
 
       /* FIXME: We ought to apply the relocs against this section before
-        we process it.... */
+        we process it...  */
     }
 
   /* Since we are using un-relocated data, it is possible to get a bad value
@@ -814,14 +963,14 @@ decode_line_info (unit)
      below.  */
   if (unit->line_offset >= stash->dwarf_line_size)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: Line offset (%u) bigger than line size (%u)."),
+      (*_bfd_error_handler) (_("Dwarf Error: Line offset (%lu) greater than or equal to .debug_line size (%lu)."),
                             unit->line_offset, stash->dwarf_line_size);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
-  table = (struct line_info_table*) bfd_alloc (abfd, 
-                                              sizeof (struct line_info_table));
+  amt = sizeof (struct line_info_table);
+  table = (struct line_info_table*) bfd_alloc (abfd, amt);
   table->abfd = abfd;
   table->comp_dir = unit->comp_dir;
 
@@ -836,14 +985,31 @@ decode_line_info (unit)
 
   line_ptr = stash->dwarf_line_buffer + unit->line_offset;
 
-  /* read in the prologue */
+  /* Read in the prologue.  */
   lh.total_length = read_4_bytes (abfd, line_ptr);
   line_ptr += 4;
+  offset_size = 4;
+  if (lh.total_length == 0xffffffff)
+    {
+      lh.total_length = read_8_bytes (abfd, line_ptr);
+      line_ptr += 8;
+      offset_size = 8;
+    }
+  else if (lh.total_length == 0 && unit->addr_size == 8)
+    {
+      /* Handle (non-standard) 64-bit DWARF2 formats.  */
+      lh.total_length = read_4_bytes (abfd, line_ptr);
+      line_ptr += 4;
+      offset_size = 8;
+    }
   line_end = line_ptr + lh.total_length;
   lh.version = read_2_bytes (abfd, line_ptr);
   line_ptr += 2;
-  lh.prologue_length = read_4_bytes (abfd, line_ptr);
-  line_ptr += 4;
+  if (offset_size == 4)
+    lh.prologue_length = read_4_bytes (abfd, line_ptr);
+  else
+    lh.prologue_length = read_8_bytes (abfd, line_ptr);
+  line_ptr += offset_size;
   lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
   line_ptr += 1;
   lh.default_is_stmt = read_1_byte (abfd, line_ptr);
@@ -854,45 +1020,50 @@ decode_line_info (unit)
   line_ptr += 1;
   lh.opcode_base = read_1_byte (abfd, line_ptr);
   line_ptr += 1;
-  lh.standard_opcode_lengths = (unsigned char *)
-    bfd_alloc (abfd, lh.opcode_base * sizeof (unsigned char));
+  amt = lh.opcode_base * sizeof (unsigned char);
+  lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt);
 
   lh.standard_opcode_lengths[0] = 1;
+
   for (i = 1; i < lh.opcode_base; ++i)
     {
       lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
       line_ptr += 1;
     }
 
-  /* Read directory table  */
+  /* Read directory table.  */
   while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
     {
       line_ptr += bytes_read;
+
       if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0)
        {
-         table->dirs = (char **)
-           bfd_realloc (table->dirs,
-                        (table->num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
+         amt = table->num_dirs + DIR_ALLOC_CHUNK;
+         amt *= sizeof (char *);
+         table->dirs = (char **) bfd_realloc (table->dirs, amt);
          if (! table->dirs)
            return 0;
        }
+
       table->dirs[table->num_dirs++] = cur_dir;
     }
+
   line_ptr += bytes_read;
 
-  /* Read file name table */
+  /* Read file name table */
   while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
     {
       line_ptr += bytes_read;
+
       if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
        {
-         table->files = (struct fileinfo *)
-           bfd_realloc (table->files,
-                        (table->num_files + FILE_ALLOC_CHUNK)
-                        * sizeof (struct fileinfo));
+         amt = table->num_files + FILE_ALLOC_CHUNK;
+         amt *= sizeof (struct fileinfo);
+         table->files = (struct fileinfo *) bfd_realloc (table->files, amt);
          if (! table->files)
            return 0;
        }
+
       table->files[table->num_files].name = cur_file;
       table->files[table->num_files].dir =
        read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
@@ -905,44 +1076,68 @@ decode_line_info (unit)
       line_ptr += bytes_read;
       table->num_files++;
     }
+
   line_ptr += bytes_read;
 
   /* Read the statement sequences until there's nothing left.  */
   while (line_ptr < line_end)
     {
-      /* state machine registers  */
+      /* State machine registers.  */
       bfd_vma address = 0;
-      char* filename = concat_filename (table, 1);
+      char * filename = concat_filename (table, 1);
       unsigned int line = 1;
       unsigned int column = 0;
       int is_stmt = lh.default_is_stmt;
       int basic_block = 0;
-      int end_sequence = 0, need_low_pc = 1;
-      bfd_vma low_pc = 0;
-
-      /* Decode the table. */
+      int end_sequence = 0;
+      /* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some
+         compilers generate address sequences that are wildly out of
+         order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler
+         for ia64-Linux).  Thus, to determine the low and high
+         address, we must compare on every DW_LNS_copy, etc.  */
+      bfd_vma low_pc  = 0;
+      bfd_vma high_pc = 0;
+
+      /* Decode the table.  */
       while (! end_sequence)
        {
          op_code = read_1_byte (abfd, line_ptr);
          line_ptr += 1;
-         switch (op_code)
+
+         if (op_code >= lh.opcode_base)
+           {
+             /* Special operand.  */
+             adj_opcode = op_code - lh.opcode_base;
+             address += (adj_opcode / lh.line_range)
+               * lh.minimum_instruction_length;
+             line += lh.line_base + (adj_opcode % lh.line_range);
+             /* Append row to matrix using current values.  */
+             add_line_info (table, address, filename, line, column, 0);
+             basic_block = 1;
+             if (low_pc == 0 || address < low_pc)
+               low_pc = address;
+             if (address > high_pc)
+               high_pc = address;
+           }
+         else switch (op_code)
            {
            case DW_LNS_extended_op:
-             line_ptr += 1;    /* ignore length */
+             /* Ignore length.  */
+             line_ptr += 1;
              extended_op = read_1_byte (abfd, line_ptr);
              line_ptr += 1;
+
              switch (extended_op)
                {
                case DW_LNE_end_sequence:
                  end_sequence = 1;
                  add_line_info (table, address, filename, line, column,
                                 end_sequence);
-                 if (need_low_pc)
-                   {
-                     need_low_pc = 0;
-                     low_pc = address;
-                   }
-                 arange_add (unit, low_pc, address);
+                 if (low_pc == 0 || address < low_pc)
+                   low_pc = address;
+                 if (address > high_pc)
+                   high_pc = address;
+                 arange_add (unit, low_pc, high_pc);
                  break;
                case DW_LNE_set_address:
                  address = read_address (unit, line_ptr);
@@ -953,10 +1148,10 @@ decode_line_info (unit)
                  line_ptr += bytes_read;
                  if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
                    {
-                     table->files = (struct fileinfo *)
-                       bfd_realloc (table->files,
-                                    (table->num_files + FILE_ALLOC_CHUNK)
-                                    * sizeof (struct fileinfo));
+                     amt = table->num_files + FILE_ALLOC_CHUNK;
+                     amt *= sizeof (struct fileinfo);
+                     table->files =
+                       (struct fileinfo *) bfd_realloc (table->files, amt);
                      if (! table->files)
                        return 0;
                    }
@@ -981,11 +1176,10 @@ decode_line_info (unit)
            case DW_LNS_copy:
              add_line_info (table, address, filename, line, column, 0);
              basic_block = 0;
-             if (need_low_pc)
-               {
-                 need_low_pc = 0;
-                 low_pc = address;
-               }
+             if (low_pc == 0 || address < low_pc)
+               low_pc = address;
+             if (address > high_pc)
+               high_pc = address;
              break;
            case DW_LNS_advance_pc:
              address += lh.minimum_instruction_length
@@ -1000,8 +1194,8 @@ decode_line_info (unit)
              {
                unsigned int file;
 
-               /* The file and directory tables are 0 based, the references
-                  are 1 based.  */
+               /* The file and directory tables are 0
+                  based, the references are 1 based.  */
                file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
                line_ptr += bytes_read;
                filename = concat_filename (table, file);
@@ -1025,19 +1219,16 @@ decode_line_info (unit)
              address += read_2_bytes (abfd, line_ptr);
              line_ptr += 2;
              break;
-           default:            /* special operand */
-             adj_opcode = op_code - lh.opcode_base;
-             address += (adj_opcode / lh.line_range)
-               * lh.minimum_instruction_length;
-             line += lh.line_base + (adj_opcode % lh.line_range);
-             /* append row to matrix using current values */
-             add_line_info (table, address, filename, line, column, 0);
-             basic_block = 1;
-             if (need_low_pc)
-               {
-                 need_low_pc = 0;
-                 low_pc = address;
-               }
+           default:
+             {
+               int i;
+               /* Unknown standard opcode, ignore it.  */
+               for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
+                 {
+                   (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+                   line_ptr += bytes_read;
+                 }
+             }
            }
        }
     }
@@ -1045,24 +1236,22 @@ decode_line_info (unit)
   return table;
 }
 
-
 /* If ADDR is within TABLE set the output parameters and return true,
    otherwise return false.  The output parameters, FILENAME_PTR and
-   LINENUMBER_PTR, are pointers to the objects to be filled in. */
+   LINENUMBER_PTR, are pointers to the objects to be filled in.  */
 
 static boolean
-lookup_address_in_line_info_table (table, 
-                                  addr,
-                                  filename_ptr, 
+lookup_address_in_line_info_table (table, addr, function, filename_ptr,
                                   linenumber_ptr)
      struct line_info_table* table;
      bfd_vma addr;
+     struct funcinfo *function;
      const char **filename_ptr;
      unsigned int *linenumber_ptr;
 {
   struct line_info* next_line = table->last_line;
   struct line_info* each_line;
-  
+
   if (!next_line)
     return false;
 
@@ -1073,39 +1262,51 @@ lookup_address_in_line_info_table (table,
       if (!each_line->end_sequence
          && addr >= each_line->address && addr < next_line->address)
        {
-         *filename_ptr = each_line->filename;
-         *linenumber_ptr = each_line->line;
+         /* If this line appears to span functions, and addr is in the
+            later function, return the first line of that function instead
+            of the last line of the earlier one.  This check is for GCC
+            2.95, which emits the first line number for a function late.  */
+         if (function != NULL
+             && each_line->address < function->low
+             && next_line->address > function->low)
+           {
+             *filename_ptr = next_line->filename;
+             *linenumber_ptr = next_line->line;
+           }
+         else
+           {
+             *filename_ptr = each_line->filename;
+             *linenumber_ptr = each_line->line;
+           }
          return true;
        }
       next_line = each_line;
       each_line = each_line->prev_line;
     }
-  
-  return false;
-}
-  
-
 
+  /* At this point each_line is NULL but next_line is not.  If we found the
+     containing function in this compilation unit, return the first line we
+     have a number for.  This is also for compatibility with GCC 2.95.  */
+  if (function != NULL)
+    {
+      *filename_ptr = next_line->filename;
+      *linenumber_ptr = next_line->line;
+      return true;
+    }
 
-/* Function table functions. */
-
-struct funcinfo {
-  struct funcinfo *prev_func;
-
-  char* name;
-  bfd_vma low;
-  bfd_vma high;
-};
+  return false;
+}
 
+/* Function table functions.  */
 
-/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true. */
+/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true.  */
 
 static boolean
-lookup_address_in_function_table (table, 
-                                 addr,
+lookup_address_in_function_table (table, addr, function_ptr,
                                  functionname_ptr)
      struct funcinfo* table;
      bfd_vma addr;
+     struct funcinfo** function_ptr;
      const char **functionname_ptr;
 {
   struct funcinfo* each_func;
@@ -1117,21 +1318,18 @@ lookup_address_in_function_table (table,
       if (addr >= each_func->low && addr < each_func->high)
        {
          *functionname_ptr = each_func->name;
+         *function_ptr = each_func;
          return true;
        }
     }
-  
+
   return false;
 }
 
-
-
-
-/* DWARF2 Compilation unit functions. */
-
+/* DWARF2 Compilation unit functions.  */
 
 /* Scan over each die in a comp. unit looking for functions to add
-   to the function table. */
+   to the function table.  */
 
 static boolean
 scan_unit_for_functions (unit)
@@ -1157,42 +1355,43 @@ scan_unit_for_functions (unit)
          nesting_level--;
          continue;
        }
-      
+
       abbrev = lookup_abbrev (abbrev_number,unit->abbrevs);
       if (! abbrev)
        {
-         (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."), 
+         (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
                             abbrev_number);
          bfd_set_error (bfd_error_bad_value);
          return false;
        }
-      
+
       if (abbrev->tag == DW_TAG_subprogram)
        {
-         func = (struct funcinfo*) bfd_zalloc (abfd, sizeof (struct funcinfo));
+         bfd_size_type amt = sizeof (struct funcinfo);
+         func = (struct funcinfo *) bfd_zalloc (abfd, amt);
          func->prev_func = unit->function_table;
          unit->function_table = func;
        }
       else
        func = NULL;
-  
+
       for (i = 0; i < abbrev->num_attrs; ++i)
        {
          info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
-         
+
          if (func)
            {
              switch (attr.name)
                {
                case DW_AT_name:
-                 
+
                  name = DW_STRING (&attr);
 
                  /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name.  */
                  if (func->name == NULL)
                    func->name = DW_STRING (&attr);
                  break;
-                 
+
                case DW_AT_MIPS_linkage_name:
                  func->name = DW_STRING (&attr);
                  break;
@@ -1216,7 +1415,7 @@ scan_unit_for_functions (unit)
                case DW_AT_name:
                  name = DW_STRING (&attr);
                  break;
-                 
+
                default:
                  break;
                }
@@ -1230,55 +1429,109 @@ scan_unit_for_functions (unit)
   return true;
 }
 
+/* Look for a RELA relocation to be applied on OFFSET of section SEC,
+   and return the addend if such a relocation is found.  Since this is
+   only used to find relocations referring to the .debug_abbrev
+   section, we make sure the relocation refers to this section, but
+   this is not strictly necessary, and it can probably be safely
+   removed if needed.  However, it is important to note that this
+   function only returns the addend, it doesn't serve the purpose of
+   applying a generic relocation.
 
+   If no suitable relocation is found, or if it is not a real RELA
+   relocation, this function returns 0.  */
 
+static bfd_vma
+find_rela_addend (abfd, sec, offset, syms)
+     bfd* abfd;
+     asection* sec;
+     bfd_size_type offset;
+     asymbol** syms;
+{
+  long reloc_size = bfd_get_reloc_upper_bound (abfd, sec);
+  arelent **relocs = NULL;
+  long reloc_count, relc;
+
+  if (reloc_size <= 0)
+    return 0;
 
+  relocs = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
+  if (relocs == NULL)
+    return 0;
+
+  reloc_count = bfd_canonicalize_reloc (abfd, sec, relocs, syms);
 
+  if (reloc_count <= 0)
+    {
+      free (relocs);
+      return 0;
+    }
+
+  for (relc = 0; relc < reloc_count; relc++)
+    if (relocs[relc]->address == offset
+       && (*relocs[relc]->sym_ptr_ptr)->flags & BSF_SECTION_SYM
+       && strcmp ((*relocs[relc]->sym_ptr_ptr)->name,
+                  ".debug_abbrev") == 0)
+      {
+       bfd_vma addend = (relocs[relc]->howto->partial_inplace
+                         ? 0 : relocs[relc]->addend);
+       free (relocs);
+       return addend;
+      }
+
+  free (relocs);
+  return 0;
+}
 
 /* Parse a DWARF2 compilation unit starting at INFO_PTR.  This
    includes the compilation unit header that proceeds the DIE's, but
    does not include the length field that preceeds each compilation
    unit header.  END_PTR points one past the end of this comp unit.
-   If ABBREV_LENGTH is 0, then the length of the abbreviation offset
-   is assumed to be four bytes.  Otherwise, it it is the size given.
+   OFFSET_SIZE is the size of DWARF2 offsets (either 4 or 8 bytes).
 
    This routine does not read the whole compilation unit; only enough
    to get to the line number information for the compilation unit.  */
 
 static struct comp_unit *
-parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length)
+parse_comp_unit (abfd, stash, unit_length, offset_size)
      bfd* abfd;
-     char* info_ptr;
-     char* end_ptr;
-     unsigned int abbrev_length;
+     struct dwarf2_debug *stash;
+     bfd_vma unit_length;
+     unsigned int offset_size;
 {
   struct comp_unit* unit;
-
-  unsigned short version;
-  unsigned int abbrev_offset = 0;
-  unsigned char addr_size;
+  unsigned int version;
+  bfd_vma abbrev_offset = 0;
+  unsigned int addr_size;
   struct abbrev_info** abbrevs;
-
   unsigned int abbrev_number, bytes_read, i;
   struct abbrev_info *abbrev;
   struct attribute attr;
+  char *info_ptr = stash->info_ptr;
+  char *end_ptr = info_ptr + unit_length;
+  bfd_size_type amt;
+  bfd_size_type off;
 
   version = read_2_bytes (abfd, info_ptr);
   info_ptr += 2;
-  BFD_ASSERT (abbrev_length == 0
-             || abbrev_length == 4
-             || abbrev_length == 8);
-  if (abbrev_length == 0 || abbrev_length == 4)
+  BFD_ASSERT (offset_size == 4 || offset_size == 8);
+  if (offset_size == 4)
     abbrev_offset = read_4_bytes (abfd, info_ptr);
-  else if (abbrev_length == 8)
+  else
     abbrev_offset = read_8_bytes (abfd, info_ptr);
-  info_ptr += abbrev_length;
+  /* The abbrev offset is generally a relocation pointing to
+     .debug_abbrev+offset.  On RELA targets, we have to find the
+     relocation and extract the addend to obtain the actual
+     abbrev_offset, so do it here.  */
+  off = info_ptr - stash->sec_info_ptr;
+  abbrev_offset += find_rela_addend (abfd, stash->sec, off, stash->syms);
+  info_ptr += offset_size;
   addr_size = read_1_byte (abfd, info_ptr);
   info_ptr += 1;
 
   if (version != 2)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%hu', this reader only handles version 2 information."), version );
+      (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2 information."), version);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
@@ -1287,20 +1540,20 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length)
     {
       (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."),
                         addr_size,
-                        sizeof (bfd_vma));
+                        (unsigned int) sizeof (bfd_vma));
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
   if (addr_size != 2 && addr_size != 4 && addr_size != 8)
     {
-      (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size );
+      (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
-  /* Read the abbrevs for this compilation unit into a table */
-  abbrevs = read_abbrevs (abfd, abbrev_offset);
+  /* Read the abbrevs for this compilation unit into a table */
+  abbrevs = read_abbrevs (abfd, abbrev_offset, stash);
   if (! abbrevs)
       return 0;
 
@@ -1308,7 +1561,7 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length)
   info_ptr += bytes_read;
   if (! abbrev_number)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %d."),
+      (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."),
                         abbrev_number);
       bfd_set_error (bfd_error_bad_value);
       return 0;
@@ -1317,17 +1570,20 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length)
   abbrev = lookup_abbrev (abbrev_number, abbrevs);
   if (! abbrev)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."),
+      (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
                         abbrev_number);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
-  
-  unit = (struct comp_unit*) bfd_zalloc (abfd, sizeof (struct comp_unit));
+
+  amt = sizeof (struct comp_unit);
+  unit = (struct comp_unit*) bfd_zalloc (abfd, amt);
   unit->abfd = abfd;
-  unit->addr_size = addr_size; 
+  unit->addr_size = addr_size;
+  unit->offset_size = offset_size;
   unit->abbrevs = abbrevs;
   unit->end_ptr = end_ptr;
+  unit->stash = stash;
 
   for (i = 0; i < abbrev->num_attrs; ++i)
     {
@@ -1379,11 +1635,7 @@ parse_comp_unit (abfd, info_ptr, end_ptr, abbrev_length)
   return unit;
 }
 
-
-
-
-
-/* Return true if UNIT contains the address given by ADDR. */
+/* Return true if UNIT contains the address given by ADDR.  */
 
 static boolean
 comp_unit_contains_address (unit, addr)
@@ -1403,30 +1655,32 @@ comp_unit_contains_address (unit, addr)
       arange = arange->next;
     }
   while (arange);
+
   return 0;
 }
 
-
 /* If UNIT contains ADDR, set the output parameters to the values for
    the line containing ADDR.  The output parameters, FILENAME_PTR,
    FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects
-   to be filled in.  
+   to be filled in.
 
    Return true of UNIT contains ADDR, and no errors were encountered;
    false otherwise.  */
 
 static boolean
-comp_unit_find_nearest_line (unit, addr,
-                            filename_ptr, functionname_ptr, linenumber_ptr)
+comp_unit_find_nearest_line (unit, addr, filename_ptr, functionname_ptr,
+                            linenumber_ptr, stash)
      struct comp_unit* unit;
      bfd_vma addr;
      const char **filename_ptr;
      const char **functionname_ptr;
      unsigned int *linenumber_ptr;
+     struct dwarf2_debug *stash;
 {
   boolean line_p;
   boolean func_p;
-  
+  struct funcinfo *function;
+
   if (unit->error)
     return false;
 
@@ -1437,32 +1691,70 @@ comp_unit_find_nearest_line (unit, addr,
          unit->error = 1;
          return false;
        }
-  
-      unit->line_table = decode_line_info (unit);
+
+      unit->line_table = decode_line_info (unit, stash);
 
       if (! unit->line_table)
        {
          unit->error = 1;
          return false;
        }
-      
-      if (! scan_unit_for_functions (unit))
+
+      if (unit->first_child_die_ptr < unit->end_ptr
+          && ! scan_unit_for_functions (unit))
        {
          unit->error = 1;
          return false;
        }
     }
 
-  line_p = lookup_address_in_line_info_table (unit->line_table,
-                                             addr,
-                                             filename_ptr, 
+  function = NULL;
+  func_p = lookup_address_in_function_table (unit->function_table, addr,
+                                            &function, functionname_ptr);
+  line_p = lookup_address_in_line_info_table (unit->line_table, addr,
+                                             function, filename_ptr,
                                              linenumber_ptr);
-  func_p = lookup_address_in_function_table (unit->function_table, 
-                                            addr,
-                                            functionname_ptr);
   return line_p || func_p;
 }
 
+/* Locate a section in a BFD containing debugging info.  The search starts
+   from the section after AFTER_SEC, or from the first section in the BFD if
+   AFTER_SEC is NULL.  The search works by examining the names of the
+   sections.  There are two permissiable names.  The first is .debug_info.
+   This is the standard DWARF2 name.  The second is a prefix .gnu.linkonce.wi.
+   This is a variation on the .debug_info section which has a checksum
+   describing the contents appended onto the name.  This allows the linker to
+   identify and discard duplicate debugging sections for different
+   compilation units.  */
+#define DWARF2_DEBUG_INFO ".debug_info"
+#define GNU_LINKONCE_INFO ".gnu.linkonce.wi."
+
+static asection *
+find_debug_info (abfd, after_sec)
+     bfd * abfd;
+     asection * after_sec;
+{
+  asection * msec;
+
+  if (after_sec)
+    msec = after_sec->next;
+  else
+    msec = abfd->sections;
+
+  while (msec)
+    {
+      if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0)
+       return msec;
+
+      if (strncmp (msec->name, GNU_LINKONCE_INFO, strlen (GNU_LINKONCE_INFO)) == 0)
+       return msec;
+
+      msec = msec->next;
+    }
+
+  return NULL;
+}
+
 /* The DWARF2 version of find_nearest line.  Return true if the line
    is found without error.  ADDR_SIZE is the number of bytes in the
    initial .debug_info length field and in the abbreviation offset.
@@ -1472,34 +1764,32 @@ comp_unit_find_nearest_line (unit, addr,
 boolean
 _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
                               filename_ptr, functionname_ptr,
-                              linenumber_ptr,
-                              addr_size)
+                              linenumber_ptr, addr_size, pinfo)
      bfd *abfd;
      asection *section;
-     asymbol **symbols ATTRIBUTE_UNUSED;
+     asymbol **symbols;
      bfd_vma offset;
      const char **filename_ptr;
      const char **functionname_ptr;
      unsigned int *linenumber_ptr;
      unsigned int addr_size;
+     PTR *pinfo;
 {
   /* Read each compilation unit from the section .debug_info, and check
      to see if it contains the address we are searching for.  If yes,
      lookup the address, and return the line number info.  If no, go
-     on to the next compilation unit.  
+     on to the next compilation unit.
 
      We keep a list of all the previously read compilation units, and
-     a pointer to the next un-read compilation unit.  Check the 
-     previously read units before reading more.
-     */
-
-  struct dwarf2_debug *stash = elf_tdata (abfd)->dwarf2_find_line_info;
+     a pointer to the next un-read compilation unit.  Check the
+     previously read units before reading more.  */
+  struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
 
-  /* What address are we looking for? */
+  /* What address are we looking for?  */
   bfd_vma addr = offset + section->vma;
 
   struct comp_unit* each;
-  
+
   *filename_ptr = NULL;
   *functionname_ptr = NULL;
   *linenumber_ptr = 0;
@@ -1510,93 +1800,134 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
   if (addr_size == 0)
     addr_size = 4;
   BFD_ASSERT (addr_size == 4 || addr_size == 8);
-    
+
   if (! stash)
     {
+      bfd_size_type total_size;
       asection *msec;
-      unsigned long size;
-      
-      stash = elf_tdata (abfd)->dwarf2_find_line_info =
-       (struct dwarf2_debug*) bfd_zalloc (abfd, sizeof (struct dwarf2_debug));
-      
+      bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+      stash = (struct dwarf2_debug*) bfd_zalloc (abfd, amt);
       if (! stash)
        return false;
-      
-      msec = bfd_get_section_by_name (abfd, ".debug_info");
-      if (! msec)
-       {
-         /* No dwarf2 info.  Note that at this point the stash
-            has been allocated, but contains zeros, this lets
-            future calls to this function fail quicker. */
-         return false;
-       }
 
-      size = msec->_raw_size;
-      if (size == 0)
-       return false;
-      
-      stash->info_ptr = (char *) bfd_alloc (abfd, size);
-      
-      if (! stash->info_ptr)
+      *pinfo = (PTR) stash;
+
+      msec = find_debug_info (abfd, NULL);
+      if (! msec)
+       /* No dwarf2 info.  Note that at this point the stash
+          has been allocated, but contains zeros, this lets
+          future calls to this function fail quicker.  */
+        return false;
+
+      /* There can be more than one DWARF2 info section in a BFD these days.
+         Read them all in and produce one large stash.  We do this in two
+        passes - in the first pass we just accumulate the section sizes.
+        In the second pass we read in the section's contents.  The allows
+        us to avoid reallocing the data as we add sections to the stash.  */
+      for (total_size = 0; msec; msec = find_debug_info (abfd, msec))
+       total_size += msec->_raw_size;
+
+      stash->info_ptr = (char *) bfd_alloc (abfd, total_size);
+      if (stash->info_ptr == NULL)
        return false;
 
-      if (! bfd_get_section_contents (abfd, msec, stash->info_ptr, 0, size))
+      stash->info_ptr_end = stash->info_ptr;
+
+      for (msec = find_debug_info (abfd, NULL);
+          msec;
+          msec = find_debug_info (abfd, msec))
        {
-         stash->info_ptr = 0;
-         return false;
+         bfd_size_type size;
+         bfd_size_type start;
+
+         size = msec->_raw_size;
+         if (size == 0)
+           continue;
+
+         start = stash->info_ptr_end - stash->info_ptr;
+
+         if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start,
+                                         (bfd_vma) 0, size))
+           continue;
+
+         stash->info_ptr_end = stash->info_ptr + start + size;
        }
 
-      stash->info_ptr_end = stash->info_ptr + size;
-
-      /* FIXME: There is a problem with the contents of the
-        .debug_info section.  The 'low' and 'high' addresses of the
-        comp_units are computed by relocs against symbols in the
-        .text segment.  We need these addresses in order to determine
-        the nearest line number, and so we have to resolve the
-        relocs.  There is a similar problem when the .debug_line
-        section is processed as well (e.g., there may be relocs
-        against the operand of the DW_LNE_set_address operator).
-        
-        Unfortunately getting hold of the reloc information is hard...
-
-        For now, this means that disassembling object files (as
-        opposed to fully executables) does not always work as well as
-        we would like.  */
+      BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size);
+
+      stash->sec = find_debug_info (abfd, NULL);
+      stash->sec_info_ptr = stash->info_ptr;
+      stash->syms = symbols;
     }
-  
-  /* A null info_ptr indicates that there is no dwarf2 info 
-     (or that an error occured while setting up the stash). */
 
+  /* FIXME: There is a problem with the contents of the
+     .debug_info section.  The 'low' and 'high' addresses of the
+     comp_units are computed by relocs against symbols in the
+     .text segment.  We need these addresses in order to determine
+     the nearest line number, and so we have to resolve the
+     relocs.  There is a similar problem when the .debug_line
+     section is processed as well (e.g., there may be relocs
+     against the operand of the DW_LNE_set_address operator).
+
+     Unfortunately getting hold of the reloc information is hard...
+
+     For now, this means that disassembling object files (as
+     opposed to fully executables) does not always work as well as
+     we would like.  */
+
+  /* A null info_ptr indicates that there is no dwarf2 info
+     (or that an error occured while setting up the stash).  */
   if (! stash->info_ptr)
     return false;
 
-  /* Check the previously read comp. units first. */
-
+  /* Check the previously read comp. units first.  */
   for (each = stash->all_comp_units; each; each = each->next_unit)
     if (comp_unit_contains_address (each, addr))
-      return comp_unit_find_nearest_line (each, addr, filename_ptr, 
-                                         functionname_ptr, linenumber_ptr);
+      return comp_unit_find_nearest_line (each, addr, filename_ptr,
+                                         functionname_ptr, linenumber_ptr,
+                                         stash);
 
-  /* Read each remaining comp. units checking each as they are read. */
+  /* Read each remaining comp. units checking each as they are read.  */
   while (stash->info_ptr < stash->info_ptr_end)
     {
-      struct comp_unit* each;
       bfd_vma length;
       boolean found;
+      unsigned int offset_size = addr_size;
 
       if (addr_size == 4)
-       length = read_4_bytes (abfd, stash->info_ptr);
+       {
+         length = read_4_bytes (abfd, stash->info_ptr);
+         if (length == 0xffffffff)
+           {
+             offset_size = 8;
+             length = read_8_bytes (abfd, stash->info_ptr + 4);
+             stash->info_ptr += 8;
+           }
+         else if (length == 0)
+           {
+             /* Handle (non-standard) 64-bit DWARF2 formats.  */
+             offset_size = 8;
+             length = read_4_bytes (abfd, stash->info_ptr + 4);
+             stash->info_ptr += 4;
+           }
+       }
       else
        length = read_8_bytes (abfd, stash->info_ptr);
       stash->info_ptr += addr_size;
 
       if (length > 0)
         {
-         each = parse_comp_unit (abfd, stash->info_ptr, 
-                                 stash->info_ptr + length,
-                                 addr_size);
+         each = parse_comp_unit (abfd, stash, length, offset_size);
          stash->info_ptr += length;
 
+         if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
+             == stash->sec->_raw_size)
+           {
+             stash->sec = find_debug_info (abfd, stash->sec);
+             stash->sec_info_ptr = stash->info_ptr;
+           }
+
          if (each)
            {
              each->next_unit = stash->all_comp_units;
@@ -1606,21 +1937,23 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
                 compilation units.  If we don't have them (i.e.,
                 unit->high == 0), we need to consult the line info
                 table to see if a compilation unit contains the given
-                address. */
+                address.  */
              if (each->arange.high > 0)
                {
                  if (comp_unit_contains_address (each, addr))
                    return comp_unit_find_nearest_line (each, addr,
                                                       filename_ptr,
                                                       functionname_ptr,
-                                                      linenumber_ptr);
+                                                      linenumber_ptr,
+                                                      stash);
                }
              else
                {
                  found = comp_unit_find_nearest_line (each, addr,
                                                       filename_ptr,
                                                       functionname_ptr,
-                                                      linenumber_ptr);
+                                                      linenumber_ptr,
+                                                      stash);
                  if (found)
                    return true;
                }
@@ -1630,5 +1963,3 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
   return false;
 }
-
-/* end of file */
This page took 0.047503 seconds and 4 git commands to generate.