Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4461)

Unified Diff: bfd/dwarf2.c

Issue 124383005: GDB 7.6.50 (Closed) Base URL: http://git.chromium.org/native_client/nacl-gdb.git@upstream
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « bfd/doc/targets.texi ('k') | bfd/ecoff.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: bfd/dwarf2.c
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index d31b84939ad47b29643b3d39627bd8d2e28470d9..4a904eafbb32edf70002423940e15359d817fc44 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -1,6 +1,5 @@
/* 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).
@@ -108,6 +107,16 @@ struct dwarf2_debug
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
@@ -173,6 +182,9 @@ struct dwarf2_debug
#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
@@ -287,6 +299,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
{ ".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" },
@@ -297,6 +310,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
{ ".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" },
@@ -309,12 +323,15 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
{ 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,
@@ -325,6 +342,7 @@ enum dwarf_debug_section_enum
debug_static_func,
debug_static_vars,
debug_str,
+ debug_str_alt,
debug_types,
debug_sfnames,
debug_srcinfo,
@@ -481,8 +499,8 @@ read_section (bfd * abfd,
asection *msec;
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)
@@ -623,6 +641,104 @@ read_indirect_string (struct comp_unit * unit,
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)
{
@@ -826,6 +942,7 @@ read_attribute_value (struct attribute *attr,
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);
@@ -875,6 +992,10 @@ read_attribute_value (struct attribute *attr,
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);
@@ -947,7 +1068,7 @@ read_attribute_value (struct attribute *attr,
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;
@@ -980,6 +1101,7 @@ struct line_info
char *filename;
unsigned int line;
unsigned int column;
+ unsigned int discriminator;
unsigned char op_index;
unsigned char end_sequence; /* End of (sequential) code sequence. */
};
@@ -1080,6 +1202,7 @@ add_line_info (struct line_info_table *table,
char *filename,
unsigned int line,
unsigned int column,
+ unsigned int discriminator,
int end_sequence)
{
bfd_size_type amt = sizeof (struct line_info);
@@ -1095,6 +1218,7 @@ add_line_info (struct line_info_table *table,
info->op_index = op_index;
info->line = line;
info->column = column;
+ info->discriminator = discriminator;
info->end_sequence = end_sequence;
if (filename && filename[0])
@@ -1573,6 +1697,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
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
@@ -1607,8 +1732,9 @@ 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. */
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)
@@ -1626,9 +1752,10 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
{
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)
@@ -1668,7 +1795,8 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
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:
@@ -1686,8 +1814,9 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
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)
@@ -1780,15 +1909,18 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
return NULL;
}
-/* If ADDR is within TABLE set the output parameters and return TRUE,
- otherwise return FALSE. The output parameters, FILENAME_PTR and
- LINENUMBER_PTR, are pointers to the objects to be filled in. */
+/* If ADDR is within TABLE set the output parameters and return the
+ range of addresses covered by the entry used to fill them out.
+ Otherwise set * FILENAME_PTR to NULL and return 0.
+ The parameters FILENAME_PTR, LINENUMBER_PTR and DISCRIMINATOR_PTR
+ are pointers to the objects to be filled in. */
-static bfd_boolean
+static bfd_vma
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;
@@ -1823,12 +1955,14 @@ lookup_address_in_line_info_table (struct line_info_table *table,
{
*filename_ptr = each_line->filename;
*linenumber_ptr = each_line->line;
- return TRUE;
+ if (discriminator_ptr)
+ *discriminator_ptr = each_line->discriminator;
+ return seq->last_line->address - seq->low_pc;
}
}
*filename_ptr = NULL;
- return FALSE;
+ return 0;
}
/* Read in the .debug_ranges section for future reference. */
@@ -1844,10 +1978,10 @@ read_debug_ranges (struct comp_unit *unit)
/* Function table functions. */
-/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE.
- Note that we need to find the function that has the smallest
- range that contains ADDR, to handle inlined functions without
- depending upon them being ordered in TABLE by increasing range. */
+/* If ADDR is within UNIT's function tables, set FUNCTIONNAME_PTR, and return
+ TRUE. Note that we need to find the function that has the smallest range
+ that contains ADDR, to handle inlined functions without depending upon
+ them being ordered in TABLE by increasing range. */
static bfd_boolean
lookup_address_in_function_table (struct comp_unit *unit,
@@ -1982,7 +2116,7 @@ find_abstract_instance_name (struct comp_unit *unit,
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. */
@@ -1995,8 +2129,20 @@ find_abstract_instance_name (struct comp_unit *unit,
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;
@@ -2543,18 +2689,18 @@ comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr)
FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects
to be filled in.
- Return TRUE if UNIT contains ADDR, and no errors were encountered;
- FALSE otherwise. */
+ Returns the range of addresses covered by the entry that was used
+ to fill in *LINENUMBER_PTR or 0 if it was not filled in. */
-static bfd_boolean
+static bfd_vma
comp_unit_find_nearest_line (struct comp_unit *unit,
bfd_vma addr,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
struct dwarf2_debug *stash)
{
- bfd_boolean line_p;
bfd_boolean func_p;
struct funcinfo *function;
@@ -2590,10 +2736,11 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
&function, functionname_ptr);
if (func_p && (function->tag == DW_TAG_inlined_subroutine))
stash->inliner_chain = function;
- line_p = lookup_address_in_line_info_table (unit->line_table, addr,
- filename_ptr,
- linenumber_ptr);
- return line_p || func_p;
+
+ return lookup_address_in_line_info_table (unit->line_table, addr,
+ filename_ptr,
+ linenumber_ptr,
+ discriminator_ptr);
}
/* Check to see if line info is already decoded in a comp_unit.
@@ -3193,6 +3340,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
if (! stash)
return FALSE;
stash->debug_sections = debug_sections;
+ stash->syms = symbols;
*pinfo = stash;
@@ -3222,7 +3370,9 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
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
@@ -3280,9 +3430,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
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;
- stash->syms = symbols;
- stash->bfd_ptr = debug_bfd;
-
return TRUE;
}
@@ -3308,6 +3455,7 @@ find_line (bfd *abfd,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
unsigned int addr_size,
void **pinfo)
{
@@ -3323,13 +3471,15 @@ find_line (bfd *abfd,
/* What address are we looking for? */
bfd_vma addr;
struct comp_unit* each;
- bfd_vma found = FALSE;
+ 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))
@@ -3411,17 +3561,56 @@ find_line (bfd *abfd,
}
else
{
+ bfd_vma min_range = (bfd_vma) -1;
+ const char * local_filename = NULL;
+ const char * local_functionname = 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))
- && comp_unit_find_nearest_line (each, addr,
- filename_ptr,
- functionname_ptr,
- linenumber_ptr,
- stash));
+ && (range = comp_unit_find_nearest_line (each, addr,
+ & local_filename,
+ & local_functionname,
+ & local_linenumber,
+ & local_discriminator,
+ stash)) != 0);
if (found)
- goto done;
+ {
+ /* 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 (functionname_ptr && local_functionname)
+ * functionname_ptr = local_functionname;
+ if (discriminator_ptr && local_discriminator)
+ * discriminator_ptr = local_discriminator;
+ if (local_linenumber)
+ * linenumber_ptr = local_linenumber;
+ min_range = range;
+ }
+ }
+ }
+
+ if (* linenumber_ptr)
+ {
+ found = TRUE;
+ goto done;
}
}
@@ -3488,10 +3677,10 @@ find_line (bfd *abfd,
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
@@ -3512,7 +3701,8 @@ find_line (bfd *abfd,
filename_ptr,
functionname_ptr,
linenumber_ptr,
- stash));
+ discriminator_ptr,
+ stash)) > 0;
if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
== stash->sec->size)
@@ -3546,12 +3736,13 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
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, debug_sections, section, offset, NULL, symbols,
- filename_ptr, functionname_ptr, linenumber_ptr, addr_size,
- pinfo);
+ filename_ptr, functionname_ptr, linenumber_ptr,
+ discriminator_ptr, addr_size, pinfo);
}
/* The DWARF2 version of find_line.
@@ -3563,11 +3754,13 @@ _bfd_dwarf2_find_line (bfd *abfd,
asymbol *symbol,
const char **filename_ptr,
unsigned int *linenumber_ptr,
+ unsigned int *discriminator_ptr,
unsigned int addr_size,
void **pinfo)
{
return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols,
- filename_ptr, NULL, linenumber_ptr, addr_size, pinfo);
+ filename_ptr, NULL, linenumber_ptr, discriminator_ptr,
+ addr_size, pinfo);
}
bfd_boolean
@@ -3600,7 +3793,7 @@ _bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
void
_bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
{
- struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;;
+ struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
struct comp_unit *each;
if (abfd == NULL || stash == NULL)
@@ -3668,4 +3861,12 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
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);
}
« no previous file with comments | « bfd/doc/targets.texi ('k') | bfd/ecoff.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698