* config/tc-i370.c: Fix typo in last change.
[deliverable/binutils-gdb.git] / bfd / dwarf2.c
index f364719dee37e99a945332dcf4237a92a69f5e33..71263600069f3618373a0bd69fb5aa43ba9c02c2 100644 (file)
@@ -96,6 +96,14 @@ struct dwarf2_debug
   /* Pointer to the end of the .debug_info section memory buffer.  */
   char* info_ptr_end;
 
+  /* 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;
 
@@ -165,6 +173,72 @@ struct comp_unit
   unsigned char addr_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;
+};
+
+#ifndef ABBREV_HASH_SIZE
+#define ABBREV_HASH_SIZE 121
+#endif
+#ifndef ATTR_ALLOC_CHUNK
+#define ATTR_ALLOC_CHUNK 4
+#endif
+
+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 unsigned int 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 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 *, unsigned int, struct dwarf2_debug *));
+static char *read_attribute
+  PARAMS ((struct attribute *, struct attr_abbrev *,
+          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, const char **, unsigned int *));
+static boolean lookup_address_in_function_table
+  PARAMS ((struct funcinfo *, bfd_vma, 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.  */
@@ -349,30 +423,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 *
@@ -413,6 +463,7 @@ read_abbrevs (abfd, offset, stash)
   struct abbrev_info *cur_abbrev;
   unsigned int abbrev_number, bytes_read, abbrev_name;
   unsigned int abbrev_form, hash_number;
+  bfd_size_type amt;
 
   if (! stash->dwarf_abbrev_buffer)
     {
@@ -427,25 +478,25 @@ read_abbrevs (abfd, offset, stash)
        }
 
       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)."),
+      (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%u) greater than or equal to abbrev size (%u)."),
                             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);
@@ -454,7 +505,8 @@ read_abbrevs (abfd, offset, stash)
   /* 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.  */
       cur_abbrev->number = abbrev_number;
@@ -473,10 +525,10 @@ read_abbrevs (abfd, offset, stash)
        {
          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;
            }
@@ -524,6 +576,7 @@ read_attribute (attr, abbrev, unit, 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;
@@ -536,7 +589,8 @@ read_attribute (attr, abbrev, 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);
@@ -544,7 +598,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);
@@ -568,7 +623,8 @@ read_attribute (attr, abbrev, unit, info_ptr)
       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);
@@ -576,7 +632,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);
@@ -672,8 +729,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;
@@ -749,7 +806,7 @@ arange_add (unit, low_pc, high_pc)
     }
 
   /* Need to allocate a new arange and insert it into the arange list.  */
-  arange = bfd_zalloc (unit->abfd, sizeof (*arange));
+  arange = bfd_zalloc (unit->abfd, (bfd_size_type) sizeof (*arange));
   arange->low = low_pc;
   arange->high = high_pc;
 
@@ -772,6 +829,7 @@ decode_line_info (unit, stash)
   unsigned int i, bytes_read;
   char *cur_file, *cur_dir;
   unsigned char op_code, extended_op, adj_opcode;
+  bfd_size_type amt;
 
   if (! stash->dwarf_line_buffer)
     {
@@ -786,13 +844,12 @@ decode_line_info (unit, stash)
        }
 
       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
@@ -804,14 +861,14 @@ decode_line_info (unit, stash)
      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 (%u) greater than or equal to line size (%u)."),
                             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;
 
@@ -844,8 +901,8 @@ decode_line_info (unit, stash)
   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;
 
@@ -862,9 +919,9 @@ decode_line_info (unit, stash)
 
       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;
        }
@@ -881,10 +938,9 @@ decode_line_info (unit, stash)
 
       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;
        }
@@ -951,10 +1007,10 @@ decode_line_info (unit, stash)
                  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;
                    }
@@ -1158,7 +1214,8 @@ scan_unit_for_functions (unit)
 
       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;
        }
@@ -1219,6 +1276,60 @@ 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
@@ -1249,6 +1360,8 @@ parse_comp_unit (abfd, stash, unit_length, abbrev_length)
 
   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;
@@ -1259,6 +1372,12 @@ parse_comp_unit (abfd, stash, unit_length, abbrev_length)
     abbrev_offset = read_4_bytes (abfd, info_ptr);
   else if (abbrev_length == 8)
     abbrev_offset = read_8_bytes (abfd, info_ptr);
+  /* 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 += abbrev_length;
   addr_size = read_1_byte (abfd, info_ptr);
   info_ptr += 1;
@@ -1310,7 +1429,8 @@ parse_comp_unit (abfd, stash, unit_length, abbrev_length)
       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->abbrevs = abbrevs;
@@ -1498,7 +1618,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
                               addr_size, pinfo)
      bfd *abfd;
      asection *section;
-     asymbol **symbols ATTRIBUTE_UNUSED;
+     asymbol **symbols;
      bfd_vma offset;
      const char **filename_ptr;
      const char **functionname_ptr;
@@ -1534,11 +1654,11 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
   if (! stash)
     {
-      unsigned long total_size;
+      bfd_size_type total_size;
       asection *msec;
+      bfd_size_type amt = sizeof (struct dwarf2_debug);
 
-      stash =
-       (struct dwarf2_debug*) bfd_zalloc (abfd, sizeof (struct dwarf2_debug));
+      stash = (struct dwarf2_debug*) bfd_zalloc (abfd, amt);
       if (! stash)
        return false;
 
@@ -1569,8 +1689,8 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
           msec;
           msec = find_debug_info (abfd, msec))
        {
-         unsigned long size;
-         unsigned long start;
+         bfd_size_type size;
+         bfd_size_type start;
 
          size = msec->_raw_size;
          if (size == 0)
@@ -1578,13 +1698,18 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
 
          start = stash->info_ptr_end - stash->info_ptr;
 
-         if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start, 0, size))
+         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;
        }
 
-      BFD_ASSERT (stash->info_ptr_end = stash->info_ptr + total_size);
+      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;
     }
 
   /* FIXME: There is a problem with the contents of the
@@ -1617,7 +1742,6 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
   /* 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;
 
@@ -1632,6 +1756,13 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
          each = parse_comp_unit (abfd, stash, length, addr_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;
This page took 0.0291439999999999 seconds and 4 git commands to generate.