+ /* 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;
+ last_vma += sz;
+ }
+
+ p->section = sect;
+ p->adj_vma = sect->vma;
+ p++;
+ }
+ if (abfd == stash->bfd_ptr)
+ break;
+ abfd = stash->bfd_ptr;
+ }
+ }
+
+ if (orig_bfd != stash->bfd_ptr)
+ set_debug_vma (orig_bfd, stash->bfd_ptr);
+
+ return TRUE;
+}
+
+/* Look up a funcinfo by name using the given info hash table. If found,
+ also update the locations pointed to by filename_ptr and linenumber_ptr.
+
+ This function returns TRUE if a funcinfo that matches the given symbol
+ and address is found with any error; otherwise it returns FALSE. */
+
+static bfd_boolean
+info_hash_lookup_funcinfo (struct info_hash_table *hash_table,
+ asymbol *sym,
+ bfd_vma addr,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr)
+{
+ struct funcinfo* each_func;
+ struct funcinfo* best_fit = NULL;
+ bfd_vma best_fit_len = 0;
+ struct info_list_node *node;
+ struct arange *arange;
+ const char *name = bfd_asymbol_name (sym);
+ asection *sec = bfd_get_section (sym);
+
+ for (node = lookup_info_hash_table (hash_table, name);
+ node;
+ node = node->next)
+ {
+ each_func = (struct funcinfo *) node->info;
+ for (arange = &each_func->arange;
+ arange;
+ arange = arange->next)
+ {
+ if ((!each_func->sec || each_func->sec == sec)
+ && addr >= arange->low
+ && addr < arange->high
+ && (!best_fit
+ || arange->high - arange->low < best_fit_len))
+ {
+ best_fit = each_func;
+ best_fit_len = arange->high - arange->low;
+ }
+ }
+ }
+
+ if (best_fit)
+ {
+ best_fit->sec = sec;
+ *filename_ptr = best_fit->file;
+ *linenumber_ptr = best_fit->line;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Look up a varinfo by name using the given info hash table. If found,
+ also update the locations pointed to by filename_ptr and linenumber_ptr.
+
+ This function returns TRUE if a varinfo that matches the given symbol
+ and address is found with any error; otherwise it returns FALSE. */
+
+static bfd_boolean
+info_hash_lookup_varinfo (struct info_hash_table *hash_table,
+ 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;
+ struct info_list_node *node;
+
+ for (node = lookup_info_hash_table (hash_table, name);
+ node;
+ node = node->next)
+ {
+ each = (struct varinfo *) node->info;
+ if (each->addr == addr
+ && (!each->sec || each->sec == sec))
+ {
+ each->sec = sec;
+ *filename_ptr = each->file;
+ *linenumber_ptr = each->line;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Update the funcinfo and varinfo info hash tables if they are
+ not up to date. Returns TRUE if there is no error; otherwise
+ returns FALSE and disable the info hash tables. */
+
+static bfd_boolean
+stash_maybe_update_info_hash_tables (struct dwarf2_debug *stash)
+{
+ struct comp_unit *each;
+
+ /* Exit if hash tables are up-to-date. */
+ if (stash->all_comp_units == stash->hash_units_head)
+ return TRUE;
+
+ if (stash->hash_units_head)
+ each = stash->hash_units_head->prev_unit;
+ else
+ each = stash->last_comp_unit;
+
+ while (each)
+ {
+ if (!comp_unit_hash_info (stash, each, stash->funcinfo_hash_table,
+ stash->varinfo_hash_table))
+ {
+ stash->info_hash_status = STASH_INFO_HASH_DISABLED;
+ return FALSE;
+ }
+ each = each->prev_unit;
+ }
+
+ stash->hash_units_head = stash->all_comp_units;
+ return TRUE;
+}
+
+/* Check consistency of info hash tables. This is for debugging only. */
+
+static void ATTRIBUTE_UNUSED
+stash_verify_info_hash_table (struct dwarf2_debug *stash)
+{
+ struct comp_unit *each_unit;
+ struct funcinfo *each_func;
+ struct varinfo *each_var;
+ struct info_list_node *node;
+ bfd_boolean found;
+
+ for (each_unit = stash->all_comp_units;
+ each_unit;
+ each_unit = each_unit->next_unit)
+ {
+ for (each_func = each_unit->function_table;
+ each_func;
+ each_func = each_func->prev_func)
+ {
+ if (!each_func->name)
+ continue;
+ node = lookup_info_hash_table (stash->funcinfo_hash_table,
+ each_func->name);
+ BFD_ASSERT (node);
+ found = FALSE;
+ while (node && !found)
+ {
+ found = node->info == each_func;
+ node = node->next;
+ }
+ BFD_ASSERT (found);
+ }
+
+ for (each_var = each_unit->variable_table;
+ each_var;
+ each_var = each_var->prev_var)
+ {
+ if (!each_var->name || !each_var->file || each_var->stack)
+ continue;
+ node = lookup_info_hash_table (stash->varinfo_hash_table,
+ each_var->name);
+ BFD_ASSERT (node);
+ found = FALSE;
+ while (node && !found)
+ {
+ found = node->info == each_var;
+ node = node->next;
+ }
+ BFD_ASSERT (found);
+ }
+ }
+}
+
+/* Check to see if we want to enable the info hash tables, which consume
+ quite a bit of memory. Currently we only check the number times
+ bfd_dwarf2_find_line is called. In the future, we may also want to
+ take the number of symbols into account. */
+
+static void
+stash_maybe_enable_info_hash_tables (bfd *abfd, struct dwarf2_debug *stash)
+{
+ BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_OFF);
+
+ if (stash->info_hash_count++ < STASH_INFO_HASH_TRIGGER)
+ return;
+
+ /* FIXME: Maybe we should check the reduce_memory_overheads
+ and optimize fields in the bfd_link_info structure ? */
+
+ /* Create hash tables. */
+ stash->funcinfo_hash_table = create_info_hash_table (abfd);
+ stash->varinfo_hash_table = create_info_hash_table (abfd);
+ if (!stash->funcinfo_hash_table || !stash->varinfo_hash_table)
+ {
+ /* Turn off info hashes if any allocation above fails. */
+ stash->info_hash_status = STASH_INFO_HASH_DISABLED;
+ return;
+ }
+ /* We need a forced update so that the info hash tables will
+ be created even though there is no compilation unit. That
+ happens if STASH_INFO_HASH_TRIGGER is 0. */
+ stash_maybe_update_info_hash_tables (stash);
+ stash->info_hash_status = STASH_INFO_HASH_ON;
+}
+
+/* Find the file and line associated with a symbol and address using the
+ info hash tables of a stash. If there is a match, the function returns
+ TRUE and update the locations pointed to by filename_ptr and linenumber_ptr;
+ otherwise it returns FALSE. */
+
+static bfd_boolean
+stash_find_line_fast (struct dwarf2_debug *stash,
+ asymbol *sym,
+ bfd_vma addr,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr)
+{
+ BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_ON);
+
+ if (sym->flags & BSF_FUNCTION)
+ return info_hash_lookup_funcinfo (stash->funcinfo_hash_table, sym, addr,
+ filename_ptr, linenumber_ptr);
+ return info_hash_lookup_varinfo (stash->varinfo_hash_table, sym, addr,
+ filename_ptr, linenumber_ptr);
+}
+
+/* Save current section VMAs. */
+
+static bfd_boolean
+save_section_vma (const bfd *abfd, struct dwarf2_debug *stash)
+{
+ asection *s;
+ unsigned int i;
+
+ if (abfd->section_count == 0)
+ return TRUE;
+ stash->sec_vma = bfd_malloc (sizeof (*stash->sec_vma) * abfd->section_count);
+ if (stash->sec_vma == NULL)
+ return FALSE;
+ for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next)
+ {
+ if (s->output_section != NULL)
+ stash->sec_vma[i] = s->output_section->vma + s->output_offset;
+ else
+ stash->sec_vma[i] = s->vma;
+ }
+ return TRUE;
+}
+
+/* Compare current section VMAs against those at the time the stash
+ was created. If find_nearest_line is used in linker warnings or
+ errors early in the link process, the debug info stash will be
+ invalid for later calls. This is because we relocate debug info
+ sections, so the stashed section contents depend on symbol values,
+ which in turn depend on section VMAs. */
+
+static bfd_boolean
+section_vma_same (const bfd *abfd, const struct dwarf2_debug *stash)
+{
+ asection *s;
+ unsigned int i;
+
+ for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next)
+ {
+ bfd_vma vma;
+
+ if (s->output_section != NULL)
+ vma = s->output_section->vma + s->output_offset;
+ else
+ vma = s->vma;
+ if (vma != stash->sec_vma[i])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified.
+ If DEBUG_BFD is not specified, we read debug information from ABFD
+ or its gnu_debuglink. The results will be stored in PINFO.
+ The function returns TRUE iff debug information is ready. */
+
+bfd_boolean
+_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
+ const struct dwarf_debug_section *debug_sections,
+ asymbol **symbols,
+ void **pinfo,
+ bfd_boolean do_place)
+{
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
+ bfd_size_type total_size;
+ asection *msec;
+ struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
+
+ if (stash != NULL)
+ {
+ if (section_vma_same (abfd, stash))
+ return TRUE;
+ _bfd_dwarf2_cleanup_debug_info (abfd, pinfo);
+ memset (stash, 0, amt);
+ }
+ else
+ {
+ stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+ }
+ stash->debug_sections = debug_sections;
+ stash->syms = symbols;
+ if (!save_section_vma (abfd, stash))
+ return FALSE;
+
+ *pinfo = stash;
+
+ if (debug_bfd == NULL)
+ debug_bfd = abfd;
+
+ msec = find_debug_info (debug_bfd, debug_sections, NULL);
+ if (msec == NULL && abfd == debug_bfd)
+ {
+ char * debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR);
+
+ if (debug_filename == NULL)
+ /* No dwarf2 info, and no gnu_debuglink to follow.
+ Note that at this point the stash has been allocated, but
+ contains zeros. This lets future calls to this function
+ fail more quickly. */
+ return FALSE;
+
+ /* Set BFD_DECOMPRESS to decompress debug sections. */
+ if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
+ || !(debug_bfd->flags |= BFD_DECOMPRESS,
+ bfd_check_format (debug_bfd, bfd_object))
+ || (msec = find_debug_info (debug_bfd,
+ debug_sections, NULL)) == NULL
+ || !bfd_generic_link_read_symbols (debug_bfd))
+ {
+ if (debug_bfd)
+ bfd_close (debug_bfd);
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ free (debug_filename);
+ return FALSE;
+ }
+
+ symbols = bfd_get_outsymbols (debug_bfd);
+ stash->syms = symbols;
+ stash->close_on_cleanup = TRUE;
+ }
+ stash->bfd_ptr = debug_bfd;
+
+ if (do_place
+ && !place_sections (abfd, stash))
+ return FALSE;
+
+ /* There can be more than one DWARF2 info section in a BFD these
+ days. First handle the easy case when there's only one. If
+ there's more than one, try case two: none of the sections is
+ compressed. In that case, 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, and 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.) If
+ some or all sections are compressed, then do things the slow
+ way, with a bunch of reallocs. */
+
+ if (! find_debug_info (debug_bfd, debug_sections, msec))
+ {
+ /* Case 1: only one info section. */
+ total_size = msec->size;
+ if (! read_section (debug_bfd, &stash->debug_sections[debug_info],
+ symbols, 0,
+ &stash->info_ptr_memory, &total_size))
+ return FALSE;
+ }
+ else
+ {
+ /* Case 2: multiple sections. */
+ for (total_size = 0;
+ msec;
+ msec = find_debug_info (debug_bfd, debug_sections, msec))
+ total_size += msec->size;
+
+ stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size);
+ if (stash->info_ptr_memory == NULL)
+ return FALSE;
+
+ total_size = 0;
+ for (msec = find_debug_info (debug_bfd, debug_sections, NULL);
+ msec;
+ msec = find_debug_info (debug_bfd, debug_sections, msec))
+ {
+ bfd_size_type size;
+
+ size = msec->size;
+ if (size == 0)
+ continue;
+
+ if (!(bfd_simple_get_relocated_section_contents
+ (debug_bfd, msec, stash->info_ptr_memory + total_size,
+ symbols)))
+ return FALSE;
+
+ total_size += size;
+ }
+ }
+
+ stash->info_ptr = stash->info_ptr_memory;
+ stash->info_ptr_end = stash->info_ptr + total_size;
+ stash->sec = find_debug_info (debug_bfd, debug_sections, NULL);
+ stash->sec_info_ptr = stash->info_ptr;
+ return TRUE;
+}
+
+/* Scan the debug information in PINFO looking for a DW_TAG_subprogram
+ abbrev with a DW_AT_low_pc attached to it. Then lookup that same
+ symbol in SYMBOLS and return the difference between the low_pc and
+ the symbol's address. Returns 0 if no suitable symbol could be found. */
+
+bfd_signed_vma
+_bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo)
+{
+ struct dwarf2_debug *stash;
+ struct comp_unit * unit;
+
+ stash = (struct dwarf2_debug *) *pinfo;
+
+ if (stash == NULL)
+ return 0;
+
+ for (unit = stash->all_comp_units; unit; unit = unit->next_unit)
+ {
+ struct funcinfo * func;
+
+ if (unit->function_table == NULL)
+ {
+ if (unit->line_table == NULL)
+ unit->line_table = decode_line_info (unit, stash);
+ if (unit->line_table != NULL)
+ scan_unit_for_symbols (unit);
+ }
+
+ for (func = unit->function_table; func != NULL; func = func->prev_func)
+ if (func->name && func->arange.low)
+ {
+ asymbol ** psym;
+
+ /* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */
+
+ for (psym = symbols; * psym != NULL; psym++)
+ {
+ asymbol * sym = * psym;
+
+ if (sym->flags & BSF_FUNCTION
+ && sym->section != NULL
+ && strcmp (sym->name, func->name) == 0)
+ return ((bfd_signed_vma) func->arange.low) -
+ ((bfd_signed_vma) (sym->value + sym->section->vma));
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Find the source code location of SYMBOL. If SYMBOL is NULL
+ then find the nearest source code location corresponding to
+ the address SECTION + OFFSET.
+ Returns TRUE if the line is found without error and fills in
+ FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was
+ NULL the FUNCTIONNAME_PTR is also filled in.
+ SYMBOLS contains the symbol table for ABFD.
+ DEBUG_SECTIONS contains the name of the dwarf debug sections.
+ ADDR_SIZE is the number of bytes in the initial .debug_info length
+ field and in the abbreviation offset, or zero to indicate that the
+ default value should be used. */
+
+bfd_boolean
+_bfd_dwarf2_find_nearest_line (bfd *abfd,
+ asymbol **symbols,
+ asymbol *symbol,
+ asection *section,
+ bfd_vma offset,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
+ const struct dwarf_debug_section *debug_sections,
+ 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;
+ struct funcinfo *function = NULL;
+ bfd_boolean found = FALSE;
+ bfd_boolean do_line;
+
+ *filename_ptr = NULL;
+ if (functionname_ptr != NULL)
+ *functionname_ptr = NULL;
+ *linenumber_ptr = 0;
+ if (discriminator_ptr)
+ *discriminator_ptr = 0;
+
+ if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, debug_sections,
+ symbols, pinfo,
+ (abfd->flags & (EXEC_P | DYNAMIC)) == 0))
+ return FALSE;
+
+ stash = (struct dwarf2_debug *) *pinfo;
+
+ do_line = symbol != NULL;
+ if (do_line)
+ {
+ BFD_ASSERT (section == NULL && offset == 0 && functionname_ptr == NULL);
+ section = bfd_get_section (symbol);
+ addr = symbol->value;
+ }
+ else
+ {
+ BFD_ASSERT (section != NULL && functionname_ptr != NULL);
+ addr = offset;
+ }
+
+ if (section->output_section)
+ addr += section->output_section->vma + section->output_offset;
+ else
+ addr += section->vma;
+
+ /* 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;
+
+ stash->inliner_chain = NULL;
+
+ /* Check the previously read comp. units first. */
+ if (do_line)
+ {
+ /* The info hash tables use quite a bit of memory. We may not want to
+ always use them. We use some heuristics to decide if and when to
+ turn it on. */
+ if (stash->info_hash_status == STASH_INFO_HASH_OFF)
+ stash_maybe_enable_info_hash_tables (abfd, stash);
+
+ /* Keep info hash table up to date if they are available. Note that we
+ may disable the hash tables if there is any error duing update. */
+ if (stash->info_hash_status == STASH_INFO_HASH_ON)
+ stash_maybe_update_info_hash_tables (stash);
+
+ if (stash->info_hash_status == STASH_INFO_HASH_ON)
+ {
+ found = stash_find_line_fast (stash, symbol, addr, filename_ptr,
+ linenumber_ptr);
+ if (found)
+ goto done;
+ }
+ else
+ {
+ /* Check the previously read comp. units first. */
+ for (each = stash->all_comp_units; each; each = each->next_unit)
+ if ((symbol->flags & BSF_FUNCTION) == 0
+ || each->arange.high == 0
+ || comp_unit_contains_address (each, addr))
+ {
+ found = comp_unit_find_line (each, symbol, addr, filename_ptr,
+ linenumber_ptr, stash);
+ if (found)
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ bfd_vma min_range = (bfd_vma) -1;
+ const char * local_filename = NULL;
+ struct funcinfo *local_function = NULL;
+ unsigned int local_linenumber = 0;
+ unsigned int local_discriminator = 0;
+
+ for (each = stash->all_comp_units; each; each = each->next_unit)
+ {
+ bfd_vma range = (bfd_vma) -1;
+
+ found = ((each->arange.high == 0
+ || comp_unit_contains_address (each, addr))
+ && (range = comp_unit_find_nearest_line (each, addr,
+ & local_filename,
+ & local_function,
+ & local_linenumber,
+ & local_discriminator,
+ stash)) != 0);
+ if (found)
+ {
+ /* PRs 15935 15994: Bogus debug information may have provided us
+ with an erroneous match. We attempt to counter this by
+ selecting the match that has the smallest address range
+ associated with it. (We are assuming that corrupt debug info
+ will tend to result in extra large address ranges rather than
+ extra small ranges).
+
+ This does mean that we scan through all of the CUs associated
+ with the bfd each time this function is called. But this does
+ have the benefit of producing consistent results every time the
+ function is called. */
+ if (range <= min_range)
+ {
+ if (filename_ptr && local_filename)
+ * filename_ptr = local_filename;
+ if (local_function)
+ function = local_function;
+ if (discriminator_ptr && local_discriminator)
+ * discriminator_ptr = local_discriminator;
+ if (local_linenumber)
+ * linenumber_ptr = local_linenumber;
+ min_range = range;