* bfd-in.h (STRING_AND_COMMA): New macro. Takes one constant string as its
[deliverable/binutils-gdb.git] / bfd / dwarf2.c
index 32f0b4443d0f55f899b899b407ab56ab3f10ec0c..b05711435908ce5d2f1b2a79dcb35773c1191c59 100644 (file)
@@ -1,6 +1,6 @@
 /* DWARF 2 support.
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005 Free Software Foundation, Inc.
+   2004, 2005, 2006 Free Software Foundation, Inc.
 
    Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
    (gavin@cygnus.com).
@@ -74,6 +74,12 @@ struct dwarf_block
   bfd_byte *data;
 };
 
+struct loadable_section
+{
+  asection *section;
+  bfd_vma adj_vma;
+};
+
 struct dwarf2_debug
 {
   /* A list of all previously read comp_units.  */
@@ -124,6 +130,12 @@ struct dwarf2_debug
      calling chain for subsequent calls to bfd_find_inliner_info to
      use. */
   struct funcinfo *inliner_chain;
+
+  /* Number of loadable sections.  */
+  unsigned int loadable_section_count;
+
+  /* Array of loadable sections.  */
+  struct loadable_section *loadable_sections;
 };
 
 struct arange
@@ -141,7 +153,7 @@ struct comp_unit
   /* Chain the previously read compilation units.  */
   struct comp_unit *next_unit;
 
-  /* Keep the bdf convenient (for memory allocation).  */
+  /* Keep the bfd convenient (for memory allocation).  */
   bfd *abfd;
 
   /* The lowest and highest addresses contained in this compilation
@@ -182,6 +194,9 @@ struct comp_unit
   /* A list of the functions found in this comp. unit.  */
   struct funcinfo *function_table;
 
+  /* A list of the variables found in this comp. unit.  */
+  struct varinfo *variable_table;
+
   /* Pointer to dwarf2_debug structure.  */
   struct dwarf2_debug *stash;
 
@@ -344,16 +359,35 @@ read_indirect_string (struct comp_unit* unit,
 static bfd_uint64_t
 read_address (struct comp_unit *unit, bfd_byte *buf)
 {
-  switch (unit->addr_size)
+  int signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma;
+
+  if (signed_vma)
     {
-    case 8:
-      return bfd_get_64 (unit->abfd, buf);
-    case 4:
-      return bfd_get_32 (unit->abfd, buf);
-    case 2:
-      return bfd_get_16 (unit->abfd, buf);
-    default:
-      abort ();
+      switch (unit->addr_size)
+       {
+       case 8:
+         return bfd_get_signed_64 (unit->abfd, buf);
+       case 4:
+         return bfd_get_signed_32 (unit->abfd, buf);
+       case 2:
+         return bfd_get_signed_16 (unit->abfd, buf);
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+      switch (unit->addr_size)
+       {
+       case 8:
+         return bfd_get_64 (unit->abfd, buf);
+       case 4:
+         return bfd_get_32 (unit->abfd, buf);
+       case 2:
+         return bfd_get_16 (unit->abfd, buf);
+       default:
+         abort ();
+       }
     }
 }
 
@@ -459,21 +493,21 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
              amt *= sizeof (struct attr_abbrev);
              tmp = bfd_realloc (cur_abbrev->attrs, amt);
              if (tmp == NULL)
-               {
-                 size_t i;
-
-                 for (i = 0; i < ABBREV_HASH_SIZE; i++)
-                   {
-                   struct abbrev_info *abbrev = abbrevs[i];
-
-                   while (abbrev)
-                     {
-                       free (abbrev->attrs);
-                       abbrev = abbrev->next;
-                     }
-                   }
-                 return NULL;
-               }
+               {
+                 size_t i;
+
+                 for (i = 0; i < ABBREV_HASH_SIZE; i++)
+                   {
+                     struct abbrev_info *abbrev = abbrevs[i];
+
+                     while (abbrev)
+                       {
+                         free (abbrev->attrs);
+                         abbrev = abbrev->next;
+                       }
+                   }
+                 return NULL;
+               }
              cur_abbrev->attrs = tmp;
            }
 
@@ -499,7 +533,7 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
         for the next compile unit) or if the end of the abbreviation
         table is reached.  */
       if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer)
-           >= stash->dwarf_abbrev_size)
+         >= stash->dwarf_abbrev_size)
        break;
       abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
       abbrev_ptr += bytes_read;
@@ -697,12 +731,42 @@ struct funcinfo
   struct funcinfo *caller_func;                /* Pointer to function one scope higher */
   char *caller_file;                   /* Source location file name where caller_func inlines this func */
   int caller_line;                     /* Source location line number where caller_func inlines this func */
+  char *file;                          /* Source location file name */
+  int line;                            /* Source location line number */
   int tag;
-  int nesting_level;
   char *name;
   struct arange arange;
+  asection *sec;                       /* Where the symbol is defined */
 };
 
+struct varinfo
+{
+  /* Pointer to previous variable in list of all variables */
+  struct varinfo *prev_var;
+  /* Source location file name */
+  char *file;
+  /* Source location line number */
+  int line;
+  int tag;
+  char *name;
+  bfd_vma addr;
+  /* Where the symbol is defined */
+  asection *sec;
+  /* Is this a stack variable? */
+  unsigned int stack: 1;
+};
+
+/* Return TRUE if NEW_LINE should sort after LINE.  */
+
+static inline bfd_boolean
+new_line_sorts_after (struct line_info *new_line, struct line_info *line)
+{
+  return (new_line->address > line->address
+         || (new_line->address == line->address
+             && new_line->end_sequence < line->end_sequence));
+}
+
+
 /* Adds a new entry to the line_info list in the line_info_table, ensuring
    that the list is sorted.  Note that the line_info list is sorted from
    highest to lowest VMA (with possible duplicates); that is,
@@ -719,6 +783,21 @@ add_line_info (struct line_info_table *table,
   bfd_size_type amt = sizeof (struct line_info);
   struct line_info* info = bfd_alloc (table->abfd, amt);
 
+  /* Set member data of 'info'.  */
+  info->address = address;
+  info->line = line;
+  info->column = column;
+  info->end_sequence = end_sequence;
+
+  if (filename && filename[0])
+    {
+      info->filename = bfd_alloc (table->abfd, strlen (filename) + 1);
+      if (info->filename)
+       strcpy (info->filename, filename);
+    }
+  else
+    info->filename = NULL;
+
   /* Find the correct location for 'info'.  Normally we will receive
      new line_info data 1) in order and 2) with increasing VMAs.
      However some compilers break the rules (cf. decode_line_info) and
@@ -734,70 +813,45 @@ add_line_info (struct line_info_table *table,
 
      Note: we may receive duplicate entries from 'decode_line_info'.  */
 
-  while (1)
-    if (!table->last_line
-       || address >= table->last_line->address)
-      {
-       /* Normal case: add 'info' to the beginning of the list */
-       info->prev_line = table->last_line;
-       table->last_line = info;
-
-       /* lcl_head: initialize to head a *possible* sequence at the end.  */
-       if (!table->lcl_head)
-         table->lcl_head = info;
-       break;
-      }
-    else if (!table->lcl_head->prev_line
-            && table->lcl_head->address > address)
-      {
-       /* Abnormal but easy: lcl_head is 1) at the *end* of the line
-          list and 2) the head of 'info'.  */
-       info->prev_line = NULL;
-       table->lcl_head->prev_line = info;
-       break;
-      }
-    else if (table->lcl_head->prev_line
-            && table->lcl_head->address > address
-            && address >= table->lcl_head->prev_line->address)
-      {
-       /* Abnormal but easy: lcl_head is 1) in the *middle* of the line
-          list and 2) the head of 'info'.  */
-       info->prev_line = table->lcl_head->prev_line;
-       table->lcl_head->prev_line = info;
-       break;
-      }
-    else
-      {
-       /* Abnormal and hard: Neither 'last_line' nor 'lcl_head' are valid
-          heads for 'info'.  Reset 'lcl_head' and repeat.  */
-       struct line_info* li2 = table->last_line; /* always non-NULL */
-       struct line_info* li1 = li2->prev_line;
-
-       while (li1)
-         {
-           if (li2->address > address && address >= li1->address)
-             break;
-
-           li2 = li1; /* always non-NULL */
-           li1 = li1->prev_line;
-         }
-       table->lcl_head = li2;
-      }
-
-  /* Set member data of 'info'.  */
-  info->address = address;
-  info->line = line;
-  info->column = column;
-  info->end_sequence = end_sequence;
+  if (!table->last_line
+      || new_line_sorts_after (info, table->last_line))
+    {
+      /* Normal case: add 'info' to the beginning of the list */
+      info->prev_line = table->last_line;
+      table->last_line = info;
 
-  if (filename && filename[0])
+      /* lcl_head: initialize to head a *possible* sequence at the end.  */
+      if (!table->lcl_head)
+       table->lcl_head = info;
+    }
+  else if (!new_line_sorts_after (info, table->lcl_head)
+          && (!table->lcl_head->prev_line
+              || new_line_sorts_after (info, table->lcl_head->prev_line)))
     {
-      info->filename = bfd_alloc (table->abfd, strlen (filename) + 1);
-      if (info->filename)
-       strcpy (info->filename, filename);
+      /* Abnormal but easy: lcl_head is the head of 'info'.  */
+      info->prev_line = table->lcl_head->prev_line;
+      table->lcl_head->prev_line = info;
     }
   else
-    info->filename = NULL;
+    {
+      /* Abnormal and hard: Neither 'last_line' nor 'lcl_head' are valid
+        heads for 'info'.  Reset 'lcl_head'.  */
+      struct line_info* li2 = table->last_line; /* always non-NULL */
+      struct line_info* li1 = li2->prev_line;
+
+      while (li1)
+       {
+         if (!new_line_sorts_after (info, li2)
+             && new_line_sorts_after (info, li1))
+           break;
+
+         li2 = li1; /* always non-NULL */
+         li1 = li1->prev_line;
+       }
+      table->lcl_head = li2;
+      info->prev_line = table->lcl_head->prev_line;
+      table->lcl_head->prev_line = info;
+    }
 }
 
 /* Extract a fully qualified filename from a line info table.
@@ -811,8 +865,10 @@ concat_filename (struct line_info_table *table, unsigned int file)
 
   if (file - 1 >= table->num_files)
     {
-      (*_bfd_error_handler)
-       (_("Dwarf Error: mangled line number section (bad file number)."));
+      /* FILE == 0 means unknown.  */
+      if (file)
+       (*_bfd_error_handler)
+         (_("Dwarf Error: mangled line number section (bad file number)."));
       return strdup ("<unknown>");
     }
 
@@ -1061,14 +1117,13 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
       unsigned int line = 1;
       unsigned int column = 0;
       int is_stmt = lh.default_is_stmt;
-      int basic_block = 0;
       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 low_pc  = (bfd_vma) -1;
       bfd_vma high_pc = 0;
 
       /* Decode the table.  */
@@ -1086,8 +1141,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
              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)
+             if (address < low_pc)
                low_pc = address;
              if (address > high_pc)
                high_pc = address;
@@ -1106,7 +1160,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
                  end_sequence = 1;
                  add_line_info (table, address, filename, line, column,
                                 end_sequence);
-                 if (low_pc == 0 || address < low_pc)
+                 if (address < low_pc)
                    low_pc = address;
                  if (address > high_pc)
                    high_pc = address;
@@ -1127,12 +1181,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
                      amt *= sizeof (struct fileinfo);
                      tmp = bfd_realloc (table->files, amt);
                      if (tmp == NULL)
-                       {
+                       {
                          free (table->files);
                          free (table->dirs);
                          free (filename);
                          return NULL;
-                       }
+                       }
                      table->files = tmp;
                    }
                  table->files[table->num_files].name = cur_file;
@@ -1158,8 +1212,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
              break;
            case DW_LNS_copy:
              add_line_info (table, address, filename, line, column, 0);
-             basic_block = 0;
-             if (low_pc == 0 || address < low_pc)
+             if (address < low_pc)
                low_pc = address;
              if (address > high_pc)
                high_pc = address;
@@ -1194,7 +1247,6 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
              is_stmt = (!is_stmt);
              break;
            case DW_LNS_set_basic_block:
-             basic_block = 1;
              break;
            case DW_LNS_const_add_pc:
              address += lh.minimum_instruction_length
@@ -1294,6 +1346,11 @@ lookup_address_in_line_info_table (struct line_info_table *table,
                  *linenumber_ptr = each_line->line;
                }
            }
+         else
+           {
+             *filename_ptr = each_line->filename;
+             *linenumber_ptr = each_line->line;
+           }
        }
 
       if (addr_match && !each_line->end_sequence)
@@ -1384,34 +1441,97 @@ lookup_address_in_function_table (struct comp_unit *unit,
 
   if (best_fit)
     {
-      struct funcinfo* curr_func = best_fit;
-
       *functionname_ptr = best_fit->name;
       *function_ptr = best_fit;
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
 
-      /* If we found a match and it is a function that was inlined,
-        traverse the function list looking for the function at the
-        next higher scope and save a pointer to it for future use.
-        Note that because of the way the DWARF info is generated, and
-        the way we build the function list, the first function at the
-        next higher level is the one we want. */
+/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR
+   and LINENUMBER_PTR, and return TRUE.  */
 
-      for (each_func = best_fit -> prev_func;
-          each_func && (curr_func->tag == DW_TAG_inlined_subroutine);
-          each_func = each_func->prev_func)
+static bfd_boolean
+lookup_symbol_in_function_table (struct comp_unit *unit,
+                                asymbol *sym,
+                                bfd_vma addr,
+                                const char **filename_ptr,
+                                unsigned int *linenumber_ptr)
+{
+  struct funcinfo* each_func;
+  struct funcinfo* best_fit = NULL;
+  struct arange *arange;
+  const char *name = bfd_asymbol_name (sym);
+  asection *sec = bfd_get_section (sym);
+
+  for (each_func = unit->function_table;
+       each_func;
+       each_func = each_func->prev_func)
+    {
+      for (arange = &each_func->arange;
+          arange;
+          arange = arange->next)
        {
-         if (each_func->nesting_level < curr_func->nesting_level)
-           {
-             curr_func->caller_func = each_func;
-             curr_func = each_func;
-           }
+         if ((!each_func->sec || each_func->sec == sec)
+             && addr >= arange->low
+             && addr < arange->high
+             && each_func->name
+             && strcmp (name, each_func->name) == 0
+             && (!best_fit
+                 || ((arange->high - arange->low)
+                     < (best_fit->arange.high - best_fit->arange.low))))
+           best_fit = each_func;
        }
+    }
+
+  if (best_fit)
+    {
+      best_fit->sec = sec;
+      *filename_ptr = best_fit->file;
+      *linenumber_ptr = best_fit->line;
       return TRUE;
     }
   else
+    return FALSE;
+}
+
+/* Variable table functions.  */
+
+/* If SYM is within variable table of UNIT, set FILENAME_PTR and
+   LINENUMBER_PTR, and return TRUE.  */
+
+static bfd_boolean
+lookup_symbol_in_variable_table (struct comp_unit *unit,
+                                asymbol *sym,
+                                bfd_vma addr,
+                                const char **filename_ptr,
+                                unsigned int *linenumber_ptr)
+{
+  const char *name = bfd_asymbol_name (sym);
+  asection *sec = bfd_get_section (sym);
+  struct varinfo* each;
+
+  for (each = unit->variable_table; each; each = each->prev_var)
+    if (each->stack == 0
+       && each->file != NULL
+       && each->name != NULL
+       && each->addr == addr
+       && (!each->sec || each->sec == sec)
+       && strcmp (name, each->name) == 0)
+      break;
+
+  if (each)
     {
-      return FALSE;
+      each->sec = sec;
+      *filename_ptr = each->file;
+      *linenumber_ptr = each->line;
+      return TRUE;
     }
+  else
+    return FALSE;
 }
 
 static char *
@@ -1439,17 +1559,22 @@ find_abstract_instance_name (struct comp_unit *unit, bfd_uint64_t die_ref)
        }
       else
        {
-         for (i = 0; i < abbrev->num_attrs && !name; ++i)
+         for (i = 0; i < abbrev->num_attrs; ++i)
            {
              info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
              switch (attr.name)
                {
                case DW_AT_name:
-                 name = attr.u.str;
+                 /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name.  */
+                 if (name == NULL)
+                   name = attr.u.str;
                  break;
                case DW_AT_specification:
                  name = find_abstract_instance_name (unit, attr.u.val);
                  break;
+               case DW_AT_MIPS_linkage_name:
+                 name = attr.u.str;
+                 break;
                default:
                  break;
                }
@@ -1471,13 +1596,13 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offs
        return;
     }
   ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
-    
+
   for (;;)
     {
       bfd_vma low_pc;
       bfd_vma high_pc;
 
-      if (unit->offset_size == 4)
+      if (unit->addr_size == 4)
        {
          low_pc = read_4_bytes (unit->abfd, ranges_ptr);
          ranges_ptr += 4;
@@ -1496,21 +1621,31 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offs
       if (low_pc == -1UL && high_pc != -1UL)
        base_address = high_pc;
       else
-         arange_add (unit->abfd, arange, base_address + low_pc, base_address + high_pc);
+       arange_add (unit->abfd, arange, base_address + low_pc, base_address + high_pc);
     }
 }
 
 /* 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 and variables to the variable table.  */
 
 static bfd_boolean
-scan_unit_for_functions (struct comp_unit *unit)
+scan_unit_for_symbols (struct comp_unit *unit)
 {
   bfd *abfd = unit->abfd;
   bfd_byte *info_ptr = unit->first_child_die_ptr;
   int nesting_level = 1;
+  struct funcinfo **nested_funcs;
+  int nested_funcs_size;
+
+  /* Maintain a stack of in-scope functions and inlined functions, which we
+     can use to set the caller_func field.  */
+  nested_funcs_size = 32;
+  nested_funcs = bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
+  if (nested_funcs == NULL)
+    return FALSE;
+  nested_funcs[nesting_level] = 0;
 
   while (nesting_level)
     {
@@ -1518,6 +1653,7 @@ scan_unit_for_functions (struct comp_unit *unit)
       struct abbrev_info *abbrev;
       struct attribute attr;
       struct funcinfo *func;
+      struct varinfo *var;
       bfd_vma low_pc = 0;
       bfd_vma high_pc = 0;
 
@@ -1536,21 +1672,46 @@ scan_unit_for_functions (struct comp_unit *unit)
          (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
                             abbrev_number);
          bfd_set_error (bfd_error_bad_value);
+         free (nested_funcs);
          return FALSE;
        }
 
+      var = NULL;
       if (abbrev->tag == DW_TAG_subprogram
+         || abbrev->tag == DW_TAG_entry_point
          || abbrev->tag == DW_TAG_inlined_subroutine)
        {
          bfd_size_type amt = sizeof (struct funcinfo);
          func = bfd_zalloc (abfd, amt);
          func->tag = abbrev->tag;
-         func->nesting_level = nesting_level;
          func->prev_func = unit->function_table;
          unit->function_table = func;
+
+         if (func->tag == DW_TAG_inlined_subroutine)
+           for (i = nesting_level - 1; i >= 1; i--)
+             if (nested_funcs[i])
+               {
+                 func->caller_func = nested_funcs[i];
+                 break;
+               }
+         nested_funcs[nesting_level] = func;
        }
       else
-       func = NULL;
+       {
+         func = NULL;
+         if (abbrev->tag == DW_TAG_variable)
+           {
+             bfd_size_type amt = sizeof (struct varinfo);
+             var = bfd_zalloc (abfd, amt);
+             var->tag = abbrev->tag;
+             var->stack = 1;
+             var->prev_var = unit->variable_table;
+             unit->variable_table = var;
+           }
+
+         /* No inline function in scope at this nesting level.  */
+         nested_funcs[nesting_level] = 0;
+       }
 
       for (i = 0; i < abbrev->num_attrs; ++i)
        {
@@ -1594,6 +1755,70 @@ scan_unit_for_functions (struct comp_unit *unit)
                  read_rangelist (unit, &func->arange, attr.u.val);
                  break;
 
+               case DW_AT_decl_file:
+                 func->file = concat_filename (unit->line_table,
+                                               attr.u.val);
+                 break;
+
+               case DW_AT_decl_line:
+                 func->line = attr.u.val;
+                 break;
+
+               default:
+                 break;
+               }
+           }
+         else if (var)
+           {
+             switch (attr.name)
+               {
+               case DW_AT_name:
+                 var->name = attr.u.str;
+                 break;
+
+               case DW_AT_decl_file:
+                 var->file = concat_filename (unit->line_table,
+                                              attr.u.val);
+                 break;
+
+               case DW_AT_decl_line:
+                 var->line = attr.u.val;
+                 break;
+
+               case DW_AT_external:
+                 if (attr.u.val != 0)
+                   var->stack = 0;
+                 break;
+
+               case DW_AT_location:
+                 switch (attr.form)
+                   {
+                   case DW_FORM_block:
+                   case DW_FORM_block1:
+                   case DW_FORM_block2:
+                   case DW_FORM_block4:
+                     if (*attr.u.blk->data == DW_OP_addr)
+                       {
+                         var->stack = 0;
+
+                         /* Verify that DW_OP_addr is the only opcode in the
+                            location, in which case the block size will be 1
+                            plus the address size.  */
+                         /* ??? For TLS variables, gcc can emit
+                            DW_OP_addr <addr> DW_OP_GNU_push_tls_address
+                            which we don't handle here yet.  */
+                         if (attr.u.blk->size == unit->addr_size + 1U)
+                           var->addr = bfd_get (unit->addr_size * 8,
+                                                unit->abfd,
+                                                attr.u.blk->data + 1);
+                       }
+                     break;
+
+                   default:
+                     break;
+                   }
+                 break;
+
                default:
                  break;
                }
@@ -1606,9 +1831,29 @@ scan_unit_for_functions (struct comp_unit *unit)
        }
 
       if (abbrev->has_children)
-       nesting_level++;
+       {
+         nesting_level++;
+
+         if (nesting_level >= nested_funcs_size)
+           {
+             struct funcinfo **tmp;
+
+             nested_funcs_size *= 2;
+             tmp = bfd_realloc (nested_funcs,
+                                (nested_funcs_size
+                                 * sizeof (struct funcinfo *)));
+             if (tmp == NULL)
+               {
+                 free (nested_funcs);
+                 return FALSE;
+               }
+             nested_funcs = tmp;
+           }
+         nested_funcs[nesting_level] = 0;
+       }
     }
 
+  free (nested_funcs);
   return TRUE;
 }
 
@@ -1772,7 +2017,11 @@ parse_comp_unit (bfd *abfd,
   return unit;
 }
 
-/* Return TRUE if UNIT contains the address given by ADDR.  */
+/* Return TRUE if UNIT may contain the address given by ADDR.  When
+   there are functions written entirely with inline asm statements, the
+   range info in the compilation unit header may not be correct.  We
+   need to consult the line info table to see if a compilation unit
+   really contains the given address.  */
 
 static bfd_boolean
 comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr)
@@ -1834,7 +2083,7 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
        }
 
       if (unit->first_child_die_ptr < unit->end_ptr
-         && ! scan_unit_for_functions (unit))
+         && ! scan_unit_for_symbols (unit))
        {
          unit->error = 1;
          return FALSE;
@@ -1852,6 +2101,59 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
   return line_p || func_p;
 }
 
+/* If UNIT contains SYM at ADDR, set the output parameters to the
+   values for the line containing SYM.  The output parameters,
+   FILENAME_PTR, and LINENUMBER_PTR, are pointers to the objects to be
+   filled in.
+
+   Return TRUE if UNIT contains SYM, and no errors were encountered;
+   FALSE otherwise.  */
+
+static bfd_boolean
+comp_unit_find_line (struct comp_unit *unit,
+                    asymbol *sym,
+                    bfd_vma addr,
+                    const char **filename_ptr,
+                    unsigned int *linenumber_ptr,
+                    struct dwarf2_debug *stash)
+{
+  if (unit->error)
+    return FALSE;
+
+  if (! unit->line_table)
+    {
+      if (! unit->stmtlist)
+       {
+         unit->error = 1;
+         return FALSE;
+       }
+
+      unit->line_table = decode_line_info (unit, stash);
+
+      if (! unit->line_table)
+       {
+         unit->error = 1;
+         return FALSE;
+       }
+
+      if (unit->first_child_die_ptr < unit->end_ptr
+         && ! scan_unit_for_symbols (unit))
+       {
+         unit->error = 1;
+         return FALSE;
+       }
+    }
+
+  if (sym->flags & BSF_FUNCTION)
+    return lookup_symbol_in_function_table (unit, sym, addr,
+                                           filename_ptr,
+                                           linenumber_ptr);
+  else
+    return lookup_symbol_in_variable_table (unit, sym, addr,
+                                           filename_ptr,
+                                           linenumber_ptr);
+}
+
 /* 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
@@ -1879,7 +2181,7 @@ find_debug_info (bfd *abfd, asection *after_sec)
       if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0)
        return msec;
 
-      if (strncmp (msec->name, GNU_LINKONCE_INFO, strlen (GNU_LINKONCE_INFO)) == 0)
+      if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
        return msec;
 
       msec = msec->next;
@@ -1888,6 +2190,97 @@ find_debug_info (bfd *abfd, asection *after_sec)
   return NULL;
 }
 
+/* Unset vmas for loadable sections in STASH.  */
+
+static void
+unset_sections (struct dwarf2_debug *stash)
+{
+  unsigned int i;
+  struct loadable_section *p;
+
+  i = stash->loadable_section_count;
+  p = stash->loadable_sections;
+  for (; i > 0; i--, p++)
+    p->section->vma = 0;
+}
+
+/* Set unique vmas for loadable sections in ABFD and save vmas in
+   STASH for unset_sections.  */
+
+static bfd_boolean
+place_sections (bfd *abfd, struct dwarf2_debug *stash)
+{
+  struct loadable_section *p;
+  unsigned int i;
+
+  if (stash->loadable_section_count != 0)
+    {
+      i = stash->loadable_section_count;
+      p = stash->loadable_sections;
+      for (; i > 0; i--, p++)
+       p->section->vma = p->adj_vma;
+    }
+  else
+    {
+      asection *sect;
+      bfd_vma last_vma = 0;
+      bfd_size_type amt;
+      struct loadable_section *p;
+
+      i = 0;
+      for (sect = abfd->sections; sect != NULL; sect = sect->next)
+       {
+         bfd_size_type sz;
+
+         if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0)
+           continue;
+
+         sz = sect->rawsize ? sect->rawsize : sect->size;
+         if (sz == 0)
+           continue;
+
+         i++;
+       }
+
+      amt = i * sizeof (struct loadable_section);
+      p = (struct loadable_section *) bfd_zalloc (abfd, amt);
+      if (! p)
+       return FALSE;
+
+      stash->loadable_sections = p;
+      stash->loadable_section_count = i;
+
+      for (sect = abfd->sections; sect != NULL; sect = sect->next)
+       {
+         bfd_size_type sz;
+
+         if (sect->vma != 0 || (sect->flags & SEC_LOAD) == 0)
+           continue;
+
+         sz = sect->rawsize ? sect->rawsize : sect->size;
+         if (sz == 0)
+           continue;
+
+         p->section = sect;
+         if (last_vma != 0)
+           {
+             /* Align the new address to the current section
+                alignment.  */
+             last_vma = ((last_vma
+                          + ~((bfd_vma) -1 << sect->alignment_power))
+                         & ((bfd_vma) -1 << sect->alignment_power));
+             sect->vma = last_vma;
+           }
+         p->adj_vma = sect->vma;
+         last_vma += sect->vma + sz;
+
+         p++;
+       }
+    }
+
+  return TRUE;
+}
+
 /* 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.
@@ -1920,7 +2313,27 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
 
   struct comp_unit* each;
 
+  bfd_vma found = FALSE;
+
   stash = *pinfo;
+
+  if (! stash)
+    {
+      bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+      stash = bfd_zalloc (abfd, amt);
+      if (! stash)
+       return FALSE;
+    }
+
+  /* In a relocatable file, 2 functions may have the same address.
+     We change the section vma so that they won't overlap.  */
+  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+    {
+      if (! place_sections (abfd, stash))
+       return FALSE;
+    }
+
   addr = offset;
   if (section->output_section)
     addr += section->output_section->vma + section->output_offset;
@@ -1937,15 +2350,226 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
     addr_size = 4;
   BFD_ASSERT (addr_size == 4 || addr_size == 8);
 
-  if (! stash)
+  if (! *pinfo)
     {
       bfd_size_type total_size;
       asection *msec;
+
+      *pinfo = 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.  */
+       goto done;
+
+      /* 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->size;
+
+      stash->info_ptr = bfd_alloc (abfd, total_size);
+      if (stash->info_ptr == NULL)
+       goto done;
+
+      stash->info_ptr_end = stash->info_ptr;
+
+      for (msec = find_debug_info (abfd, NULL);
+          msec;
+          msec = find_debug_info (abfd, msec))
+       {
+         bfd_size_type size;
+         bfd_size_type start;
+
+         size = msec->size;
+         if (size == 0)
+           continue;
+
+         start = stash->info_ptr_end - stash->info_ptr;
+
+         if ((bfd_simple_get_relocated_section_contents
+              (abfd, msec, stash->info_ptr + start, symbols)) == NULL)
+           continue;
+
+         stash->info_ptr_end = stash->info_ptr + start + 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;
+    }
+
+  /* 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)
+    goto done;
+
+  stash->inliner_chain = NULL;
+
+  /* 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)
+       && comp_unit_find_nearest_line (each, addr, filename_ptr,
+                                       functionname_ptr,
+                                       linenumber_ptr, stash))
+      {
+       found = TRUE;
+       goto done;
+      }
+
+  /* Read each remaining comp. units checking each as they are read.  */
+  while (stash->info_ptr < stash->info_ptr_end)
+    {
+      bfd_vma length;
+      unsigned int offset_size = addr_size;
+      bfd_byte *info_ptr_unit = stash->info_ptr;
+
+      length = read_4_bytes (abfd, stash->info_ptr);
+      /* A 0xffffff length is the DWARF3 way of indicating we use
+        64-bit offsets, instead of 32-bit offsets.  */
+      if (length == 0xffffffff)
+       {
+         offset_size = 8;
+         length = read_8_bytes (abfd, stash->info_ptr + 4);
+         stash->info_ptr += 12;
+       }
+      /* A zero length is the IRIX way of indicating 64-bit offsets,
+        mostly because the 64-bit length will generally fit in 32
+        bits, and the endianness helps.  */
+      else if (length == 0)
+       {
+         offset_size = 8;
+         length = read_4_bytes (abfd, stash->info_ptr + 4);
+         stash->info_ptr += 8;
+       }
+      /* In the absence of the hints above, we assume addr_size-sized
+        offsets, for backward-compatibility with pre-DWARF3 64-bit
+        platforms.  */
+      else if (addr_size == 8)
+       {
+         length = read_8_bytes (abfd, stash->info_ptr);
+         stash->info_ptr += 8;
+       }
+      else
+       stash->info_ptr += 4;
+
+      if (length > 0)
+       {
+         each = parse_comp_unit (abfd, stash, length, info_ptr_unit,
+                                 offset_size);
+         stash->info_ptr += length;
+
+         if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
+             == stash->sec->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;
+             stash->all_comp_units = each;
+
+             /* DW_AT_low_pc and DW_AT_high_pc are optional for
+                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.  */
+             if ((each->arange.high == 0
+                  || comp_unit_contains_address (each, addr))
+                 && comp_unit_find_nearest_line (each, addr,
+                                                 filename_ptr,
+                                                 functionname_ptr,
+                                                 linenumber_ptr,
+                                                 stash))
+               {
+                 found = TRUE;
+                 goto done;
+               }
+           }
+       }
+    }
+
+done:
+  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+    unset_sections (stash);
+
+  return found;
+}
+
+/* The DWARF2 version of find_line.  Return TRUE if the line is found
+   without error.  */
+
+bfd_boolean
+_bfd_dwarf2_find_line (bfd *abfd,
+                      asymbol **symbols,
+                      asymbol *symbol,
+                      const char **filename_ptr,
+                      unsigned int *linenumber_ptr,
+                      unsigned int addr_size,
+                      void **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.
+
+     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;
+
+  /* What address are we looking for?  */
+  bfd_vma addr;
+
+  struct comp_unit* each;
+
+  asection *section;
+
+  bfd_boolean found = FALSE;
+
+  section = bfd_get_section (symbol);
+
+  stash = *pinfo;
+
+  if (! stash)
+    {
       bfd_size_type amt = sizeof (struct dwarf2_debug);
 
       stash = bfd_zalloc (abfd, amt);
       if (! stash)
        return FALSE;
+    }
+
+  /* In a relocatable file, 2 functions may have the same address.
+     We change the section vma so that they won't overlap.  */
+  if (!stash && (abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+    {
+      if (! place_sections (abfd, stash))
+       return FALSE;
+    }
+
+  addr = symbol->value;
+  if (section->output_section)
+    addr += section->output_section->vma + section->output_offset;
+  else
+    addr += section->vma;
+
+  *filename_ptr = NULL;
+  *filename_ptr = NULL;
+  *linenumber_ptr = 0;
+
+  if (! *pinfo)
+    {
+      bfd_size_type total_size;
+      asection *msec;
 
       *pinfo = stash;
 
@@ -1954,7 +2578,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
        /* 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;
+       goto done;
 
       /* 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
@@ -1966,7 +2590,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
 
       stash->info_ptr = bfd_alloc (abfd, total_size);
       if (stash->info_ptr == NULL)
-       return FALSE;
+       goto done;
 
       stash->info_ptr_end = stash->info_ptr;
 
@@ -2000,22 +2624,32 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
   /* 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;
+    goto done;
 
   stash->inliner_chain = NULL;
 
   /* 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,
-                                         stash);
+    if ((symbol->flags & BSF_FUNCTION) == 0
+       || comp_unit_contains_address (each, addr))
+      {
+       found = comp_unit_find_line (each, symbol, addr, filename_ptr,
+                                    linenumber_ptr, stash);
+       if (found)
+         goto done;
+      }
+
+  /* The DWARF2 spec says that the initial length field, and the
+     offset of the abbreviation table, should both be 4-byte values.
+     However, some compilers do things differently.  */
+  if (addr_size == 0)
+    addr_size = 4;
+  BFD_ASSERT (addr_size == 4 || addr_size == 8);
 
   /* Read each remaining comp. units checking each as they are read.  */
   while (stash->info_ptr < stash->info_ptr_end)
     {
       bfd_vma length;
-      bfd_boolean found;
       unsigned int offset_size = addr_size;
       bfd_byte *info_ptr_unit = stash->info_ptr;
 
@@ -2071,30 +2705,24 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
                 unit->high == 0), we need to consult the line info
                 table to see if a compilation unit contains the given
                 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,
-                                                       stash);
-               }
-             else
-               {
-                 found = comp_unit_find_nearest_line (each, addr,
-                                                      filename_ptr,
-                                                      functionname_ptr,
-                                                      linenumber_ptr,
-                                                      stash);
-                 if (found)
-                   return TRUE;
-               }
+             found = (((symbol->flags & BSF_FUNCTION) == 0
+                       || each->arange.high <= 0
+                       || comp_unit_contains_address (each, addr))
+                      && comp_unit_find_line (each, symbol, addr,
+                                              filename_ptr,
+                                              linenumber_ptr,
+                                              stash));
+             if (found)
+               goto done;
            }
        }
     }
 
-  return FALSE;
+done:
+  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+    unset_sections (stash);
+
+  return found;
 }
 
 bfd_boolean
@@ -2143,21 +2771,21 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd)
       size_t i;
 
       for (i = 0; i < ABBREV_HASH_SIZE; i++)
-        {
-          struct abbrev_info *abbrev = abbrevs[i];
+       {
+         struct abbrev_info *abbrev = abbrevs[i];
 
-          while (abbrev)
-            {
-              free (abbrev->attrs);
-              abbrev = abbrev->next;
-            }
-        }
+         while (abbrev)
+           {
+             free (abbrev->attrs);
+             abbrev = abbrev->next;
+           }
+       }
 
       if (each->line_table)
-        {
-          free (each->line_table->dirs);
-          free (each->line_table->files);
-        }
+       {
+         free (each->line_table->dirs);
+         free (each->line_table->files);
+       }
     }
 
   free (stash->dwarf_abbrev_buffer);
This page took 0.059609 seconds and 4 git commands to generate.