+ return FALSE;
+}
+
+/* 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;
+
+ section = bfd_get_section (symbol);
+
+ addr = symbol->value;
+ if (section->output_section)
+ addr += section->output_section->lma + section->output_offset;
+ else
+ addr += section->lma;
+
+ *filename_ptr = NULL;
+ stash = *pinfo;
+ *filename_ptr = NULL;
+ *linenumber_ptr = 0;
+
+ if (! stash)
+ {
+ bfd_size_type total_size;
+ asection *msec;
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+ stash = bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+
+ *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. */
+ 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->size;
+
+ stash->info_ptr = bfd_alloc (abfd, total_size);
+ if (stash->info_ptr == NULL)
+ return FALSE;
+
+ 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)
+ return FALSE;
+
+ stash->inliner_chain = NULL;
+
+ /* Check the previously read comp. units first. */
+ for (each = stash->all_comp_units; each; each = each->next_unit)
+ 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)
+ return found;
+ }
+
+ /* 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;
+ 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. */
+ 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)
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+bfd_boolean
+_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *linenumber_ptr,
+ void **pinfo)
+{
+ struct dwarf2_debug *stash;
+
+ stash = *pinfo;
+ if (stash)
+ {
+ struct funcinfo *func = stash->inliner_chain;
+ if (func && func->caller_func)
+ {
+ *filename_ptr = func->caller_file;
+ *functionname_ptr = func->caller_func->name;
+ *linenumber_ptr = func->caller_line;
+ stash->inliner_chain = func->caller_func;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+void
+_bfd_dwarf2_cleanup_debug_info (bfd *abfd)
+{
+ struct comp_unit *each;
+ struct dwarf2_debug *stash;
+
+ if (abfd == NULL || elf_tdata (abfd) == NULL)
+ return;
+
+ stash = elf_tdata (abfd)->dwarf2_find_line_info;
+
+ if (stash == NULL)
+ return;
+
+ for (each = stash->all_comp_units; each; each = each->next_unit)
+ {
+ struct abbrev_info **abbrevs = each->abbrevs;
+ 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;
+ }
+ }
+
+ if (each->line_table)
+ {
+ free (each->line_table->dirs);
+ free (each->line_table->files);
+ }
+ }
+
+ free (stash->dwarf_abbrev_buffer);
+ free (stash->dwarf_line_buffer);
+ free (stash->dwarf_ranges_buffer);