+/* Parse the next DWARF2 compilation unit at FILE->INFO_PTR. */
+
+static struct comp_unit *
+stash_comp_unit (struct dwarf2_debug *stash, struct dwarf2_debug_file *file)
+{
+ bfd_size_type length;
+ unsigned int offset_size;
+ bfd_byte *info_ptr_unit = file->info_ptr;
+ bfd_byte *info_ptr_end = file->dwarf_info_buffer + file->dwarf_info_size;
+
+ if (file->info_ptr >= info_ptr_end)
+ return NULL;
+
+ length = read_4_bytes (file->bfd_ptr, file->info_ptr, info_ptr_end);
+ /* 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 (file->bfd_ptr, file->info_ptr + 4,
+ info_ptr_end);
+ file->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 (file->bfd_ptr, file->info_ptr + 4,
+ info_ptr_end);
+ file->info_ptr += 8;
+ }
+ /* In the absence of the hints above, we assume 32-bit DWARF2
+ offsets even for targets with 64-bit addresses, because:
+ a) most of the time these targets will not have generated
+ more than 2Gb of debug info and so will not need 64-bit
+ offsets,
+ and
+ b) if they do use 64-bit offsets but they are not using
+ the size hints that are tested for above then they are
+ not conforming to the DWARF3 standard anyway. */
+ else
+ {
+ offset_size = 4;
+ file->info_ptr += 4;
+ }
+
+ if (length != 0
+ && file->info_ptr + length <= info_ptr_end
+ && file->info_ptr + length > file->info_ptr)
+ {
+ struct comp_unit *each = parse_comp_unit (stash, file,
+ file->info_ptr, length,
+ info_ptr_unit, offset_size);
+ if (each)
+ {
+ if (file->all_comp_units)
+ file->all_comp_units->prev_unit = each;
+ else
+ file->last_comp_unit = each;
+
+ each->next_unit = file->all_comp_units;
+ file->all_comp_units = each;
+
+ file->info_ptr += length;
+ return each;
+ }
+ }
+
+ /* Don't trust any of the DWARF info after a corrupted length or
+ parse error. */
+ file->info_ptr = info_ptr_end;
+ return NULL;
+}
+
+/* Hash function for an asymbol. */
+
+static hashval_t
+hash_asymbol (const void *sym)
+{
+ const asymbol *asym = sym;
+ return htab_hash_string (asym->name);
+}
+
+/* Equality function for asymbols. */
+
+static int
+eq_asymbol (const void *a, const void *b)
+{
+ const asymbol *sa = a;
+ const asymbol *sb = b;
+ return strcmp (sa->name, sb->name) == 0;
+}
+
+/* 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;
+ htab_t sym_hash;
+ bfd_signed_vma result = 0;
+ asymbol ** psym;
+
+ stash = (struct dwarf2_debug *) *pinfo;
+
+ if (stash == NULL || symbols == NULL)
+ return 0;
+
+ sym_hash = htab_create_alloc (10, hash_asymbol, eq_asymbol,
+ NULL, xcalloc, free);
+ for (psym = symbols; * psym != NULL; psym++)
+ {
+ asymbol * sym = * psym;
+
+ if (sym->flags & BSF_FUNCTION && sym->section != NULL)
+ {
+ void **slot = htab_find_slot (sym_hash, sym, INSERT);
+ *slot = sym;
+ }
+ }
+
+ for (unit = stash->f.all_comp_units; unit; unit = unit->next_unit)
+ {
+ struct funcinfo * func;
+
+ comp_unit_maybe_decode_line_info (unit);
+
+ for (func = unit->function_table; func != NULL; func = func->prev_func)
+ if (func->name && func->arange.low)
+ {
+ asymbol search, *sym;
+
+ /* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */
+
+ search.name = func->name;
+ sym = htab_find (sym_hash, &search);
+ if (sym != NULL)
+ {
+ result = ((bfd_signed_vma) func->arange.low) -
+ ((bfd_signed_vma) (sym->value + sym->section->vma));
+ goto done;
+ }
+ }
+ }
+
+ done:
+ htab_delete (sym_hash);
+ return result;
+}
+