/* DWARF 2 support.
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright 1994-2013 Free Software Foundation, Inc.
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
(gavin@cygnus.com).
/* Last comp unit in list above. */
struct comp_unit *last_comp_unit;
+ /* Names of the debug sections. */
+ const struct dwarf_debug_section *debug_sections;
+
/* The next unread compilation unit within the .debug_info section.
Zero indicates that the .debug_info section has not been loaded
into a buffer yet. */
asection *sec;
bfd_byte *sec_info_ptr;
+ /* Support for alternate debug info sections created by the DWZ utility:
+ This includes a pointer to an alternate bfd which contains *extra*,
+ possibly duplicate debug sections, and pointers to the loaded
+ .debug_str and .debug_info sections from this bfd. */
+ bfd * alt_bfd_ptr;
+ bfd_byte * alt_dwarf_str_buffer;
+ bfd_size_type alt_dwarf_str_size;
+ bfd_byte * alt_dwarf_info_buffer;
+ bfd_size_type alt_dwarf_info_size;
+
/* A pointer to the memory block allocated for info_ptr. Neither
info_ptr nor sec_info_ptr are guaranteed to stay pointing to the
beginning of the malloc block. This is used only to free the
#define STASH_INFO_HASH_OFF 0
#define STASH_INFO_HASH_ON 1
#define STASH_INFO_HASH_DISABLED 2
+
+ /* True if we opened bfd_ptr. */
+ bfd_boolean close_on_cleanup;
};
struct arange
{ ".debug_aranges", ".zdebug_aranges" },
{ ".debug_frame", ".zdebug_frame" },
{ ".debug_info", ".zdebug_info" },
+ { ".debug_info", ".zdebug_info" },
{ ".debug_line", ".zdebug_line" },
{ ".debug_loc", ".zdebug_loc" },
{ ".debug_macinfo", ".zdebug_macinfo" },
+ { ".debug_macro", ".zdebug_macro" },
{ ".debug_pubnames", ".zdebug_pubnames" },
{ ".debug_pubtypes", ".zdebug_pubtypes" },
{ ".debug_ranges", ".zdebug_ranges" },
{ ".debug_static_func", ".zdebug_static_func" },
{ ".debug_static_vars", ".zdebug_static_vars" },
{ ".debug_str", ".zdebug_str", },
+ { ".debug_str", ".zdebug_str", },
{ ".debug_types", ".zdebug_types" },
/* GNU DWARF 1 extensions */
{ ".debug_sfnames", ".zdebug_sfnames" },
{ NULL, NULL },
};
+/* NB/ Numbers in this enum must match up with indicies
+ into the dwarf_debug_sections[] array above. */
enum dwarf_debug_section_enum
{
debug_abbrev = 0,
debug_aranges,
debug_frame,
debug_info,
+ debug_info_alt,
debug_line,
debug_loc,
debug_macinfo,
+ debug_macro,
debug_pubnames,
debug_pubtypes,
debug_ranges,
debug_static_func,
debug_static_vars,
debug_str,
+ debug_str_alt,
debug_types,
debug_sfnames,
debug_srcinfo,
{
struct info_hash_table *hash_table;
- hash_table = (struct info_hash_table *)
- bfd_alloc (abfd, sizeof (struct info_hash_table));
+ hash_table = ((struct info_hash_table *)
+ bfd_alloc (abfd, sizeof (struct info_hash_table)));
if (!hash_table)
return hash_table;
static bfd_boolean
read_section (bfd * abfd,
- enum dwarf_debug_section_enum sec,
+ const struct dwarf_debug_section *sec,
asymbol ** syms,
bfd_uint64_t offset,
bfd_byte ** section_buffer,
bfd_size_type * section_size)
{
asection *msec;
- const char *section_name = dwarf_debug_sections[sec].uncompressed_name;
+ const char *section_name = sec->uncompressed_name;
- /* read_section is a noop if the section has already been read. */
- if (!*section_buffer)
+ /* The section may have already been read. */
+ if (*section_buffer == NULL)
{
msec = bfd_get_section_by_name (abfd, section_name);
if (! msec)
{
- section_name = dwarf_debug_sections[sec].compressed_name;
- msec = bfd_get_section_by_name (abfd, section_name);
+ section_name = sec->compressed_name;
+ if (section_name != NULL)
+ msec = bfd_get_section_by_name (abfd, section_name);
}
if (! msec)
{
- (*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."), section_name);
+ (*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."),
+ sec->uncompressed_name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (syms)
{
*section_buffer
- = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+ = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
if (! *section_buffer)
return FALSE;
}
that the client wants. Validate it here to avoid trouble later. */
if (offset != 0 && offset >= *section_size)
{
- (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu) greater than or equal to %s size (%lu)."),
+ (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu)"
+ " greater than or equal to %s size (%lu)."),
(long) offset, section_name, *section_size);
bfd_set_error (bfd_error_bad_value);
return FALSE;
*bytes_read_ptr = unit->offset_size;
- if (! read_section (unit->abfd, debug_str, stash->syms, offset,
+ if (! read_section (unit->abfd, &stash->debug_sections[debug_str],
+ stash->syms, offset,
&stash->dwarf_str_buffer, &stash->dwarf_str_size))
return NULL;
return str;
}
+/* Like read_indirect_string but uses a .debug_str located in
+ an alternate filepointed to by the .gnu_debuglink section.
+ Used to impement DW_FORM_GNU_strp_alt. */
+
+static char *
+read_alt_indirect_string (struct comp_unit * unit,
+ bfd_byte * buf,
+ unsigned int * bytes_read_ptr)
+{
+ bfd_uint64_t offset;
+ struct dwarf2_debug *stash = unit->stash;
+ char *str;
+
+ if (unit->offset_size == 4)
+ offset = read_4_bytes (unit->abfd, buf);
+ else
+ offset = read_8_bytes (unit->abfd, buf);
+
+ *bytes_read_ptr = unit->offset_size;
+
+ if (stash->alt_bfd_ptr == NULL)
+ {
+ bfd * debug_bfd;
+ char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
+
+ if (debug_filename == NULL)
+ return NULL;
+
+ if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
+ || ! bfd_check_format (debug_bfd, bfd_object))
+ {
+ if (debug_bfd)
+ bfd_close (debug_bfd);
+
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ free (debug_filename);
+ return NULL;
+ }
+ stash->alt_bfd_ptr = debug_bfd;
+ }
+
+ if (! read_section (unit->stash->alt_bfd_ptr,
+ stash->debug_sections + debug_str_alt,
+ NULL, /* FIXME: Do we need to load alternate symbols ? */
+ offset,
+ &stash->alt_dwarf_str_buffer,
+ &stash->alt_dwarf_str_size))
+ return NULL;
+
+ str = (char *) stash->alt_dwarf_str_buffer + offset;
+ if (*str == '\0')
+ return NULL;
+
+ return str;
+}
+
+/* Resolve an alternate reference from UNIT at OFFSET.
+ Returns a pointer into the loaded alternate CU upon success
+ or NULL upon failure. */
+
+static bfd_byte *
+read_alt_indirect_ref (struct comp_unit * unit,
+ bfd_uint64_t offset)
+{
+ struct dwarf2_debug *stash = unit->stash;
+
+ if (stash->alt_bfd_ptr == NULL)
+ {
+ bfd * debug_bfd;
+ char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
+
+ if (debug_filename == NULL)
+ return FALSE;
+
+ if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
+ || ! bfd_check_format (debug_bfd, bfd_object))
+ {
+ if (debug_bfd)
+ bfd_close (debug_bfd);
+
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ free (debug_filename);
+ return NULL;
+ }
+ stash->alt_bfd_ptr = debug_bfd;
+ }
+
+ if (! read_section (unit->stash->alt_bfd_ptr,
+ stash->debug_sections + debug_info_alt,
+ NULL, /* FIXME: Do we need to load alternate symbols ? */
+ offset,
+ &stash->alt_dwarf_info_buffer,
+ &stash->alt_dwarf_info_size))
+ return NULL;
+
+ return stash->alt_dwarf_info_buffer + offset;
+}
+
static bfd_uint64_t
read_address (struct comp_unit *unit, bfd_byte *buf)
{
unsigned int abbrev_form, hash_number;
bfd_size_type amt;
- if (! read_section (abfd, debug_abbrev, stash->syms, offset,
+ if (! read_section (abfd, &stash->debug_sections[debug_abbrev],
+ stash->syms, offset,
&stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
return NULL;
attr->u.val = read_address (unit, info_ptr);
info_ptr += unit->addr_size;
break;
+ case DW_FORM_GNU_ref_alt:
case DW_FORM_sec_offset:
if (unit->offset_size == 4)
attr->u.val = read_4_bytes (unit->abfd, info_ptr);
attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_GNU_strp_alt:
+ attr->u.str = read_alt_indirect_string (unit, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
case DW_FORM_exprloc:
case DW_FORM_block:
amt = sizeof (struct dwarf_block);
info_ptr = read_attribute_value (attr, form, unit, info_ptr);
break;
default:
- (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."),
+ (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."),
form);
bfd_set_error (bfd_error_bad_value);
return NULL;
char *filename;
unsigned int line;
unsigned int column;
+ unsigned int discriminator;
unsigned char op_index;
unsigned char end_sequence; /* End of (sequential) code sequence. */
};
/* Remember some information about each function. If the function is
inlined (DW_TAG_inlined_subroutine) it may have two additional
attributes, DW_AT_call_file and DW_AT_call_line, which specify the
- source code location where this function was inlined. */
+ source code location where this function was inlined. */
struct funcinfo
{
- struct funcinfo *prev_func; /* Pointer to previous function in list of all functions */
- 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 */
+ /* Pointer to previous function in list of all functions. */
+ struct funcinfo *prev_func;
+ /* Pointer to function one scope higher. */
+ struct funcinfo *caller_func;
+ /* Source location file name where caller_func inlines this func. */
+ char *caller_file;
+ /* Source location line number where caller_func inlines this func. */
+ int caller_line;
+ /* Source location file name. */
+ char *file;
+ /* Source location line number. */
+ int line;
int tag;
char *name;
struct arange arange;
- asection *sec; /* Where the symbol is defined */
+ /* Where the symbol is defined. */
+ asection *sec;
};
struct varinfo
char *filename,
unsigned int line,
unsigned int column,
+ unsigned int discriminator,
int end_sequence)
{
bfd_size_type amt = sizeof (struct line_info);
info->op_index = op_index;
info->line = line;
info->column = column;
+ info->discriminator = discriminator;
info->end_sequence = end_sequence;
if (filename && filename[0])
}
static bfd_boolean
-arange_add (bfd *abfd, struct arange *first_arange,
+arange_add (const struct comp_unit *unit, struct arange *first_arange,
bfd_vma low_pc, bfd_vma high_pc)
{
struct arange *arange;
- /* If the first arange is empty, use it. */
+ /* Ignore empty ranges. */
+ if (low_pc == high_pc)
+ return TRUE;
+
+ /* If the first arange is empty, use it. */
if (first_arange->high == 0)
{
first_arange->low = low_pc;
/* Need to allocate a new arange and insert it into the arange list.
Order isn't significant, so just insert after the first arange. */
- arange = (struct arange *) bfd_zalloc (abfd, sizeof (*arange));
+ arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange));
if (arange == NULL)
return FALSE;
arange->low = low_pc;
unsigned int i, bytes_read, offset_size;
char *cur_file, *cur_dir;
unsigned char op_code, extended_op, adj_opcode;
+ unsigned int exop_len;
bfd_size_type amt;
- if (! read_section (abfd, debug_line, stash->syms, unit->line_offset,
+ if (! read_section (abfd, &stash->debug_sections[debug_line],
+ stash->syms, unit->line_offset,
&stash->dwarf_line_buffer, &stash->dwarf_line_size))
return NULL;
char * filename = table->num_files ? concat_filename (table, 1) : NULL;
unsigned int line = 1;
unsigned int column = 0;
+ unsigned int discriminator = 0;
int is_stmt = lh.default_is_stmt;
int end_sequence = 0;
/* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some
/* Special operand. */
adj_opcode = op_code - lh.opcode_base;
if (lh.maximum_ops_per_insn == 1)
- address += (adj_opcode / lh.line_range)
- * lh.minimum_instruction_length;
+ address += (adj_opcode / lh.line_range
+ * lh.minimum_instruction_length);
else
{
- address += ((op_index + (adj_opcode / lh.line_range))
- / lh.maximum_ops_per_insn)
- * lh.minimum_instruction_length;
- op_index = (op_index + (adj_opcode / lh.line_range))
- % lh.maximum_ops_per_insn;
+ address += ((op_index + adj_opcode / lh.line_range)
+ / lh.maximum_ops_per_insn
+ * lh.minimum_instruction_length);
+ op_index = ((op_index + adj_opcode / lh.line_range)
+ % lh.maximum_ops_per_insn);
}
line += lh.line_base + (adj_opcode % lh.line_range);
/* Append row to matrix using current values. */
if (!add_line_info (table, address, op_index, filename,
- line, column, 0))
+ line, column, discriminator, 0))
goto line_fail;
+ discriminator = 0;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
else switch (op_code)
{
case DW_LNS_extended_op:
- /* Ignore length. */
- line_ptr += 1;
+ exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
extended_op = read_1_byte (abfd, line_ptr);
line_ptr += 1;
{
case DW_LNE_end_sequence:
end_sequence = 1;
- if (!add_line_info (table, address, op_index, filename,
- line, column, end_sequence))
+ if (!add_line_info (table, address, op_index, filename, line,
+ column, discriminator, end_sequence))
goto line_fail;
+ discriminator = 0;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
high_pc = address;
- if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+ if (!arange_add (unit, &unit->arange, low_pc, high_pc))
goto line_fail;
break;
case DW_LNE_set_address:
table->num_files++;
break;
case DW_LNE_set_discriminator:
- (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ discriminator =
+ read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
+ case DW_LNE_HP_source_file_correlation:
+ line_ptr += exop_len - 1;
+ break;
default:
- (*_bfd_error_handler) (_("Dwarf Error: mangled line number section."));
+ (*_bfd_error_handler)
+ (_("Dwarf Error: mangled line number section."));
bfd_set_error (bfd_error_bad_value);
line_fail:
if (filename != NULL)
break;
case DW_LNS_copy:
if (!add_line_info (table, address, op_index,
- filename, line, column, 0))
+ filename, line, column, discriminator, 0))
goto line_fail;
+ discriminator = 0;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
break;
case DW_LNS_advance_pc:
if (lh.maximum_ops_per_insn == 1)
- address += lh.minimum_instruction_length
- * read_unsigned_leb128 (abfd, line_ptr,
- &bytes_read);
+ address += (lh.minimum_instruction_length
+ * read_unsigned_leb128 (abfd, line_ptr,
+ &bytes_read));
else
{
bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr,
&bytes_read);
- address = ((op_index + adjust) / lh.maximum_ops_per_insn)
- * lh.minimum_instruction_length;
+ address = ((op_index + adjust) / lh.maximum_ops_per_insn
+ * lh.minimum_instruction_length);
op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
}
line_ptr += bytes_read;
break;
case DW_LNS_const_add_pc:
if (lh.maximum_ops_per_insn == 1)
- address += lh.minimum_instruction_length
- * ((255 - lh.opcode_base) / lh.line_range);
+ address += (lh.minimum_instruction_length
+ * ((255 - lh.opcode_base) / lh.line_range));
else
{
bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range);
- address += lh.minimum_instruction_length
- * ((op_index + adjust) / lh.maximum_ops_per_insn);
+ address += (lh.minimum_instruction_length
+ * ((op_index + adjust)
+ / lh.maximum_ops_per_insn));
op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
}
break;
lookup_address_in_line_info_table (struct line_info_table *table,
bfd_vma addr,
const char **filename_ptr,
- unsigned int *linenumber_ptr)
+ unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr)
{
struct line_sequence *seq = NULL;
struct line_info *each_line;
{
*filename_ptr = each_line->filename;
*linenumber_ptr = each_line->line;
+ if (discriminator_ptr)
+ *discriminator_ptr = each_line->discriminator;
return TRUE;
}
}
read_debug_ranges (struct comp_unit *unit)
{
struct dwarf2_debug *stash = unit->stash;
- return read_section (unit->abfd, debug_ranges, stash->syms, 0,
+ return read_section (unit->abfd, &stash->debug_sections[debug_ranges],
+ stash->syms, 0,
&stash->dwarf_ranges_buffer, &stash->dwarf_ranges_size);
}
{
if (addr >= arange->low && addr < arange->high)
{
- if (!best_fit ||
- ((arange->high - arange->low) < (best_fit->arange.high - best_fit->arange.low)))
+ if (!best_fit
+ || (arange->high - arange->low
+ < best_fit->arange.high - best_fit->arange.low))
best_fit = each_func;
}
}
&& each_func->name
&& strcmp (name, each_func->name) == 0
&& (!best_fit
- || ((arange->high - arange->low)
- < (best_fit->arange.high - best_fit->arange.low))))
+ || (arange->high - arange->low
+ < best_fit->arange.high - best_fit->arange.low)))
best_fit = each_func;
}
}
struct abbrev_info *abbrev;
bfd_uint64_t die_ref = attr_ptr->u.val;
struct attribute attr;
- char *name = 0;
+ char *name = NULL;
/* DW_FORM_ref_addr can reference an entry in a different CU. It
is an offset from the .debug_info section, not the current CU. */
info_ptr = unit->sec_info_ptr + die_ref;
}
- else
+ else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
+ {
+ info_ptr = read_alt_indirect_ref (unit, die_ref);
+ if (info_ptr == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Unable to read alt ref %u."), die_ref);
+ bfd_set_error (bfd_error_bad_value);
+ return name;
+ }
+ }
+ else
info_ptr = unit->info_ptr_unit + die_ref;
+
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
abbrev = lookup_abbrev (abbrev_number, unit->abbrevs);
if (! abbrev)
{
- (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
- abbrev_number);
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number);
bfd_set_error (bfd_error_bad_value);
}
else
base_address = high_pc;
else
{
- if (!arange_add (unit->abfd, arange,
+ if (!arange_add (unit, arange,
base_address + low_pc, base_address + high_pc))
return FALSE;
}
can use to set the caller_func field. */
nested_funcs_size = 32;
nested_funcs = (struct funcinfo **)
- bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
+ bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
if (nested_funcs == NULL)
return FALSE;
nested_funcs[nesting_level] = 0;
struct varinfo *var;
bfd_vma low_pc = 0;
bfd_vma high_pc = 0;
+ bfd_boolean high_pc_relative = FALSE;
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
case DW_AT_high_pc:
high_pc = attr.u.val;
+ high_pc_relative = attr.form != DW_FORM_addr;
break;
case DW_AT_ranges:
}
}
+ if (high_pc_relative)
+ high_pc += low_pc;
+
if (func && high_pc != 0)
{
- if (!arange_add (unit->abfd, &func->arange, low_pc, high_pc))
+ if (!arange_add (unit, &func->arange, low_pc, high_pc))
goto fail;
}
nested_funcs_size *= 2;
tmp = (struct funcinfo **)
- bfd_realloc (nested_funcs,
- (nested_funcs_size * sizeof (struct funcinfo *)));
+ bfd_realloc (nested_funcs,
+ nested_funcs_size * sizeof (struct funcinfo *));
if (tmp == NULL)
goto fail;
nested_funcs = tmp;
bfd_vma low_pc = 0;
bfd_vma high_pc = 0;
bfd *abfd = stash->bfd_ptr;
+ bfd_boolean high_pc_relative = FALSE;
version = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
if (version != 2 && version != 3 && version != 4)
{
- (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2, 3 and 4 information."), version);
+ (*_bfd_error_handler)
+ (_("Dwarf Error: found dwarf version '%u', this reader"
+ " only handles version 2, 3 and 4 information."), version);
bfd_set_error (bfd_error_bad_value);
return 0;
}
if (addr_size > sizeof (bfd_vma))
{
- (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."),
- addr_size,
- (unsigned int) sizeof (bfd_vma));
+ (*_bfd_error_handler)
+ (_("Dwarf Error: found address size '%u', this reader"
+ " can not handle sizes greater than '%u'."),
+ addr_size,
+ (unsigned int) sizeof (bfd_vma));
bfd_set_error (bfd_error_bad_value);
return 0;
}
if (addr_size != 2 && addr_size != 4 && addr_size != 8)
{
- (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size);
+ (*_bfd_error_handler)
+ ("Dwarf Error: found address size '%u', this reader"
+ " can only handle address sizes '2', '4' and '8'.", addr_size);
bfd_set_error (bfd_error_bad_value);
return 0;
}
/* Read the abbrevs for this compilation unit into a table. */
abbrevs = read_abbrevs (abfd, abbrev_offset, stash);
if (! abbrevs)
- return 0;
+ return 0;
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
if (! abbrev_number)
{
(*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."),
- abbrev_number);
+ abbrev_number);
bfd_set_error (bfd_error_bad_value);
return 0;
}
if (! abbrev)
{
(*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
- abbrev_number);
+ abbrev_number);
bfd_set_error (bfd_error_bad_value);
return 0;
}
/* If the compilation unit DIE has a DW_AT_low_pc attribute,
this is the base address to use when reading location
lists or range lists. */
- unit->base_address = low_pc;
+ if (abbrev->tag == DW_TAG_compile_unit)
+ unit->base_address = low_pc;
break;
case DW_AT_high_pc:
high_pc = attr.u.val;
+ high_pc_relative = attr.form != DW_FORM_addr;
break;
case DW_AT_ranges:
break;
}
}
+ if (high_pc_relative)
+ high_pc += low_pc;
if (high_pc != 0)
{
- if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+ if (!arange_add (unit, &unit->arange, low_pc, high_pc))
return NULL;
}
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
struct dwarf2_debug *stash)
{
bfd_boolean line_p;
stash->inliner_chain = function;
line_p = lookup_address_in_line_info_table (unit->line_table, addr,
filename_ptr,
- linenumber_ptr);
+ linenumber_ptr,
+ discriminator_ptr);
return line_p || func_p;
}
/* 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
- sections. There are two permissiable names. The first is .debug_info.
- This is the standard DWARF2 name. The second is a prefix .gnu.linkonce.wi.
+ sections. There are three permissiable names. The first two are given
+ by DEBUG_SECTIONS[debug_info] (whose standard DWARF2 names are .debug_info
+ and .zdebug_info). The third is a prefix .gnu.linkonce.wi.
This is a variation on the .debug_info section which has a checksum
describing the contents appended onto the name. This allows the linker to
identify and discard duplicate debugging sections for different
compilation units. */
-#define DWARF2_DEBUG_INFO ".debug_info"
-#define DWARF2_COMPRESSED_DEBUG_INFO ".zdebug_info"
#define GNU_LINKONCE_INFO ".gnu.linkonce.wi."
static asection *
-find_debug_info (bfd *abfd, asection *after_sec)
+find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
+ asection *after_sec)
{
- asection * msec;
+ asection *msec;
+ const char *look;
- msec = after_sec != NULL ? after_sec->next : abfd->sections;
+ if (after_sec == NULL)
+ {
+ look = debug_sections[debug_info].uncompressed_name;
+ msec = bfd_get_section_by_name (abfd, look);
+ if (msec != NULL)
+ return msec;
+
+ look = debug_sections[debug_info].compressed_name;
+ if (look != NULL)
+ {
+ msec = bfd_get_section_by_name (abfd, look);
+ if (msec != NULL)
+ return msec;
+ }
- while (msec)
+ for (msec = abfd->sections; msec != NULL; msec = msec->next)
+ if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
+ return msec;
+
+ return NULL;
+ }
+
+ for (msec = after_sec->next; msec != NULL; msec = msec->next)
{
- if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0)
+ look = debug_sections[debug_info].uncompressed_name;
+ if (strcmp (msec->name, look) == 0)
return msec;
- if (strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0)
+ look = debug_sections[debug_info].compressed_name;
+ if (look != NULL && strcmp (msec->name, look) == 0)
return msec;
if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
return msec;
-
- msec = msec->next;
}
return NULL;
asection *sect;
bfd_vma last_vma = 0, last_dwarf = 0;
bfd_size_type amt;
+ const char *debug_info_name;
+ debug_info_name = stash->debug_sections[debug_info].uncompressed_name;
i = 0;
for (sect = abfd->sections; sect != NULL; sect = sect->next)
{
/* We need to adjust the VMAs of any .debug_info sections.
Skip compressed ones, since no relocations could target
them - they should not appear in object files anyway. */
- if (strcmp (sect->name, DWARF2_DEBUG_INFO) == 0)
+ if (strcmp (sect->name, debug_info_name) == 0)
is_debug_info = 1;
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO))
is_debug_info = 1;
}
amt = i * sizeof (struct adjusted_section);
- p = (struct adjusted_section *) bfd_zalloc (abfd, amt);
+ p = (struct adjusted_section *) bfd_alloc (abfd, amt);
if (! p)
return FALSE;
/* We need to adjust the VMAs of any .debug_info sections.
Skip compressed ones, since no relocations could target
them - they should not appear in object files anyway. */
- if (strcmp (sect->name, DWARF2_DEBUG_INFO) == 0)
+ if (strcmp (sect->name, debug_info_name) == 0)
is_debug_info = 1;
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO))
is_debug_info = 1;
&& addr >= arange->low
&& addr < arange->high
&& (!best_fit
- || ((arange->high - arange->low)
- < (best_fit->arange.high - best_fit->arange.low))))
+ || (arange->high - arange->low
+ < best_fit->arange.high - best_fit->arange.low)))
best_fit = each_func;
}
}
filename_ptr, linenumber_ptr);
}
+/* 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_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)
+ return TRUE;
+
+ stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+ stash->debug_sections = debug_sections;
+ stash->syms = symbols;
+
+ *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;
+
+ if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
+ || ! bfd_check_format (debug_bfd, bfd_object)
+ || (msec = find_debug_info (debug_bfd,
+ debug_sections, NULL)) == NULL)
+ {
+ if (debug_bfd)
+ bfd_close (debug_bfd);
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ free (debug_filename);
+ return FALSE;
+ }
+ stash->close_on_cleanup = TRUE;
+ }
+ stash->bfd_ptr = debug_bfd;
+
+ /* 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;
+}
+
/* Find the source code location of SYMBOL. If SYMBOL is NULL
then find the nearest source code location corresponding to
the address SECTION + OFFSET.
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. */
static bfd_boolean
find_line (bfd *abfd,
+ const struct dwarf_debug_section *debug_sections,
asection *section,
bfd_vma offset,
asymbol *symbol,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
unsigned int addr_size,
void **pinfo)
{
bfd_vma found = FALSE;
bfd_boolean do_line;
- stash = (struct dwarf2_debug *) *pinfo;
+ *filename_ptr = NULL;
+ if (functionname_ptr != NULL)
+ *functionname_ptr = NULL;
+ *linenumber_ptr = 0;
+ if (discriminator_ptr)
+ *discriminator_ptr = 0;
- if (! stash)
- {
- bfd_size_type amt = sizeof (struct dwarf2_debug);
+ if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL,
+ debug_sections, symbols, pinfo))
+ return FALSE;
- stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
- if (! stash)
- return FALSE;
- }
+ stash = (struct dwarf2_debug *) *pinfo;
/* In a relocatable file, 2 functions may have the same address.
We change the section vma so that they won't overlap. */
addr += section->output_section->vma + section->output_offset;
else
addr += section->vma;
- *filename_ptr = NULL;
- if (! do_line)
- *functionname_ptr = NULL;
- *linenumber_ptr = 0;
-
- if (! *pinfo)
- {
- bfd *debug_bfd;
- bfd_size_type total_size;
- asection *msec;
-
- *pinfo = stash;
-
- msec = find_debug_info (abfd, NULL);
- if (msec == NULL)
- {
- 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. */
- goto done;
-
- if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
- || ! bfd_check_format (debug_bfd, bfd_object)
- || (msec = find_debug_info (debug_bfd, NULL)) == NULL)
- {
- if (debug_bfd)
- bfd_close (debug_bfd);
- /* FIXME: Should we report our failure to follow the debuglink ? */
- free (debug_filename);
- goto done;
- }
- }
- else
- debug_bfd = abfd;
-
- /* 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, msec))
- {
- /* Case 1: only one info section. */
- total_size = msec->size;
- if (! read_section (debug_bfd, debug_info, symbols, 0,
- &stash->info_ptr_memory, &total_size))
- goto done;
- }
- else
- {
- /* Case 2: multiple sections. */
- for (total_size = 0; msec; msec = find_debug_info (debug_bfd, msec))
- total_size += msec->size;
-
- stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size);
- if (stash->info_ptr_memory == NULL)
- goto done;
-
- total_size = 0;
- for (msec = find_debug_info (debug_bfd, NULL);
- msec;
- msec = find_debug_info (debug_bfd, 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)))
- goto done;
-
- 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, NULL);
- stash->sec_info_ptr = stash->info_ptr;
- stash->syms = symbols;
- stash->bfd_ptr = debug_bfd;
- }
/* 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;
+ 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
+ || each->arange.high == 0
|| comp_unit_contains_address (each, addr))
{
found = comp_unit_find_line (each, symbol, addr, filename_ptr,
{
for (each = stash->all_comp_units; each; each = each->next_unit)
{
- found = (comp_unit_contains_address (each, addr)
+ found = ((each->arange.high == 0
+ || comp_unit_contains_address (each, addr))
&& comp_unit_find_nearest_line (each, addr,
filename_ptr,
functionname_ptr,
linenumber_ptr,
+ discriminator_ptr,
stash));
if (found)
goto done;
stash->all_comp_units->prev_unit = each;
else
stash->last_comp_unit = 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
filename_ptr,
functionname_ptr,
linenumber_ptr,
+ discriminator_ptr,
stash));
if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
== stash->sec->size)
{
- stash->sec = find_debug_info (stash->bfd_ptr, stash->sec);
+ stash->sec = find_debug_info (stash->bfd_ptr, debug_sections,
+ stash->sec);
stash->sec_info_ptr = stash->info_ptr;
}
}
}
-done:
+ done:
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
unset_sections (stash);
bfd_boolean
_bfd_dwarf2_find_nearest_line (bfd *abfd,
+ const struct dwarf_debug_section *debug_sections,
asection *section,
asymbol **symbols,
bfd_vma offset,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
unsigned int addr_size,
void **pinfo)
{
- return find_line (abfd, section, offset, NULL, symbols, filename_ptr,
- functionname_ptr, linenumber_ptr, addr_size,
- pinfo);
+ return find_line (abfd, debug_sections, section, offset, NULL, symbols,
+ filename_ptr, functionname_ptr, linenumber_ptr,
+ discriminator_ptr, addr_size, pinfo);
}
/* The DWARF2 version of find_line.
asymbol *symbol,
const char **filename_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
unsigned int addr_size,
void **pinfo)
{
- return find_line (abfd, NULL, 0, symbol, symbols, filename_ptr,
- NULL, linenumber_ptr, addr_size,
- pinfo);
+ return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols,
+ filename_ptr, NULL, linenumber_ptr, discriminator_ptr,
+ addr_size, pinfo);
}
bfd_boolean
}
void
-_bfd_dwarf2_cleanup_debug_info (bfd *abfd)
+_bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
{
+ struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
struct comp_unit *each;
- struct dwarf2_debug *stash;
-
- if (abfd == NULL || elf_tdata (abfd) == NULL)
- return;
-
- stash = (struct dwarf2_debug *) elf_tdata (abfd)->dwarf2_find_line_info;
- if (stash == NULL)
+ if (abfd == NULL || stash == NULL)
return;
for (each = stash->all_comp_units; each; each = each->next_unit)
free (stash->dwarf_ranges_buffer);
if (stash->info_ptr_memory)
free (stash->info_ptr_memory);
+ if (stash->close_on_cleanup)
+ bfd_close (stash->bfd_ptr);
+ if (stash->alt_dwarf_str_buffer)
+ free (stash->alt_dwarf_str_buffer);
+ if (stash->alt_dwarf_info_buffer)
+ free (stash->alt_dwarf_info_buffer);
+ if (stash->alt_bfd_ptr)
+ bfd_close (stash->alt_bfd_ptr);
}