/* 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
- memory later. */
+ beginning of the malloc block. */
bfd_byte *info_ptr_memory;
/* Pointer to the symbol table. */
/* Length of the loaded .debug_str section. */
bfd_size_type dwarf_str_size;
+ /* Pointer to the .debug_line_str section loaded into memory. */
+ bfd_byte *dwarf_line_str_buffer;
+
+ /* Length of the loaded .debug_line_str section. */
+ bfd_size_type dwarf_line_str_size;
+
/* Pointer to the .debug_ranges section loaded into memory. */
bfd_byte *dwarf_ranges_buffer;
by its reference. */
bfd_byte *info_ptr_unit;
- /* Pointer to the start of the debug section, for DW_FORM_ref_addr. */
- bfd_byte *sec_info_ptr;
-
/* The offset into .debug_line of the line number table. */
unsigned long line_offset;
{
enum dwarf_attribute name;
enum dwarf_form form;
+ bfd_vma implicit_const;
};
/* Map of uncompressed DWARF debug section name to compressed one. It
{ ".debug_static_vars", ".zdebug_static_vars" },
{ ".debug_str", ".zdebug_str", },
{ ".debug_str", ".zdebug_str", },
+ { ".debug_line_str", ".zdebug_line_str", },
{ ".debug_types", ".zdebug_types" },
/* GNU DWARF 1 extensions */
{ ".debug_sfnames", ".zdebug_sfnames" },
debug_static_vars,
debug_str,
debug_str_alt,
+ debug_line_str,
debug_types,
debug_sfnames,
debug_srcinfo,
debug_funcnames,
debug_typenames,
debug_varnames,
- debug_weaknames
+ debug_weaknames,
+ debug_max
};
+/* A static assertion. */
+extern int dwarf_debug_section_assert[ARRAY_SIZE (dwarf_debug_sections)
+ == debug_max + 1 ? 1 : -1];
+
#ifndef ABBREV_HASH_SIZE
#define ABBREV_HASH_SIZE 121
#endif
0, *section_size))
return FALSE;
}
+
+ /* Paranoia - if we are reading in a string section, make sure that it
+ is NUL terminated. This is to prevent string functions from running
+ off the end of the buffer. Note - knowing the size of the buffer is
+ not enough as some functions, eg strchr, do not have a range limited
+ equivalent.
+
+ FIXME: We ought to use a flag in the dwarf_debug_sections[] table to
+ determine the nature of a debug section, rather than checking the
+ section name as we do here. */
+ if (*section_size > 0
+ && (*section_buffer)[*section_size - 1] != 0
+ && (strstr (section_name, "_str") || strstr (section_name, "names")))
+ {
+ bfd_byte * new_buffer = malloc (*section_size + 1);
+
+ _bfd_error_handler (_("warning: dwarf string section '%s' is not NUL terminated"),
+ section_name);
+ memcpy (new_buffer, *section_buffer, *section_size);
+ new_buffer[*section_size] = 0;
+ free (*section_buffer);
+ *section_buffer = new_buffer;
+ }
}
/* It is possible to get a bad value for the offset into the section
if (offset != 0 && offset >= *section_size)
{
/* xgettext: c-format */
- _bfd_error_handler (_("Dwarf Error: Offset (%lu)"
- " greater than or equal to %s size (%lu)."),
- (long) offset, section_name, *section_size);
+ _bfd_error_handler (_("Dwarf Error: Offset (%llu)"
+ " greater than or equal to %s size (%Lu)."),
+ (long long) offset, section_name, *section_size);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
return str;
}
+/* Like read_indirect_string but from .debug_line_str section. */
+
+static char *
+read_indirect_line_string (struct comp_unit * unit,
+ bfd_byte * buf,
+ bfd_byte * buf_end,
+ unsigned int * bytes_read_ptr)
+{
+ bfd_uint64_t offset;
+ struct dwarf2_debug *stash = unit->stash;
+ char *str;
+
+ if (buf + unit->offset_size > buf_end)
+ {
+ * bytes_read_ptr = 0;
+ return NULL;
+ }
+
+ if (unit->offset_size == 4)
+ offset = read_4_bytes (unit->abfd, buf, buf_end);
+ else
+ offset = read_8_bytes (unit->abfd, buf, buf_end);
+
+ *bytes_read_ptr = unit->offset_size;
+
+ if (! read_section (unit->abfd, &stash->debug_sections[debug_line_str],
+ stash->syms, offset,
+ &stash->dwarf_line_str_buffer,
+ &stash->dwarf_line_str_size))
+ return NULL;
+
+ if (offset >= stash->dwarf_line_str_size)
+ return NULL;
+ str = (char *) stash->dwarf_line_str_buffer + offset;
+ if (*str == '\0')
+ return NULL;
+ return str;
+}
+
/* Like read_indirect_string but uses a .debug_str located in
an alternate file pointed to by the .gnu_debugaltlink section.
Used to impement DW_FORM_GNU_strp_alt. */
abbrev_ptr += 1;
/* Now read in declarations. */
- abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
- abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
-
- while (abbrev_name)
+ for (;;)
{
+ /* Initialize it just to avoid a GCC false warning. */
+ bfd_vma implicit_const = -1;
+
+ abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
+ FALSE, abbrev_end);
+ abbrev_ptr += bytes_read;
+ abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
+ FALSE, abbrev_end);
+ abbrev_ptr += bytes_read;
+ if (abbrev_form == DW_FORM_implicit_const)
+ {
+ implicit_const = _bfd_safe_read_leb128 (abfd, abbrev_ptr,
+ &bytes_read, TRUE,
+ abbrev_end);
+ abbrev_ptr += bytes_read;
+ }
+
+ if (abbrev_name == 0)
+ break;
+
if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0)
{
struct attr_abbrev *tmp;
cur_abbrev->attrs[cur_abbrev->num_attrs].name
= (enum dwarf_attribute) abbrev_name;
- cur_abbrev->attrs[cur_abbrev->num_attrs++].form
+ cur_abbrev->attrs[cur_abbrev->num_attrs].form
= (enum dwarf_form) abbrev_form;
- abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
- abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
+ cur_abbrev->attrs[cur_abbrev->num_attrs].implicit_const
+ = implicit_const;
+ ++cur_abbrev->num_attrs;
}
hash_number = abbrev_number % ABBREV_HASH_SIZE;
static inline bfd_boolean
is_str_attr (enum dwarf_form form)
{
- return form == DW_FORM_string || form == DW_FORM_strp || form == DW_FORM_GNU_strp_alt;
+ return (form == DW_FORM_string || form == DW_FORM_strp
+ || form == DW_FORM_line_strp || form == DW_FORM_GNU_strp_alt);
}
/* Read and fill in the value of attribute ATTR as described by FORM.
static bfd_byte *
read_attribute_value (struct attribute * attr,
unsigned form,
+ bfd_vma implicit_const,
struct comp_unit * unit,
bfd_byte * info_ptr,
bfd_byte * info_ptr_end)
attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_line_strp:
+ attr->u.str = read_indirect_line_string (unit, info_ptr, info_ptr_end, &bytes_read);
+ info_ptr += bytes_read;
+ break;
case DW_FORM_GNU_strp_alt:
attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
info_ptr += bytes_read;
form = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
FALSE, info_ptr_end);
info_ptr += bytes_read;
- info_ptr = read_attribute_value (attr, form, unit, info_ptr, info_ptr_end);
+ if (form == DW_FORM_implicit_const)
+ {
+ implicit_const = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
+ TRUE, info_ptr_end);
+ info_ptr += bytes_read;
+ }
+ info_ptr = read_attribute_value (attr, form, implicit_const, unit,
+ info_ptr, info_ptr_end);
+ break;
+ case DW_FORM_implicit_const:
+ attr->form = DW_FORM_sdata;
+ attr->u.sval = implicit_const;
break;
default:
_bfd_error_handler (_("Dwarf Error: Invalid or unhandled FORM value: %#x."),
bfd_byte * info_ptr_end)
{
attr->name = abbrev->name;
- info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, info_ptr_end);
+ info_ptr = read_attribute_value (attr, abbrev->form, abbrev->implicit_const,
+ unit, info_ptr, info_ptr_end);
return info_ptr;
}
}
filename = table->files[file - 1].name;
+ if (filename == NULL)
+ return strdup ("<unknown>");
if (!IS_ABSOLUTE_PATH (filename))
{
return TRUE;
}
+/* Add directory to TABLE. CUR_DIR memory ownership is taken by TABLE. */
+
+static bfd_boolean
+line_info_add_include_dir (struct line_info_table *table, char *cur_dir)
+{
+ if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0)
+ {
+ char **tmp;
+ bfd_size_type amt;
+
+ amt = table->num_dirs + DIR_ALLOC_CHUNK;
+ amt *= sizeof (char *);
+
+ tmp = (char **) bfd_realloc (table->dirs, amt);
+ if (tmp == NULL)
+ return FALSE;
+ table->dirs = tmp;
+ }
+
+ table->dirs[table->num_dirs++] = cur_dir;
+ return TRUE;
+}
+
+static bfd_boolean
+line_info_add_include_dir_stub (struct line_info_table *table, char *cur_dir,
+ unsigned int dir ATTRIBUTE_UNUSED,
+ unsigned int xtime ATTRIBUTE_UNUSED,
+ unsigned int size ATTRIBUTE_UNUSED)
+{
+ return line_info_add_include_dir (table, cur_dir);
+}
+
+/* Add file to TABLE. CUR_FILE memory ownership is taken by TABLE. */
+
+static bfd_boolean
+line_info_add_file_name (struct line_info_table *table, char *cur_file,
+ unsigned int dir, unsigned int xtime,
+ unsigned int size)
+{
+ if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
+ {
+ struct fileinfo *tmp;
+ bfd_size_type amt;
+
+ amt = table->num_files + FILE_ALLOC_CHUNK;
+ amt *= sizeof (struct fileinfo);
+
+ tmp = (struct fileinfo *) bfd_realloc (table->files, amt);
+ if (tmp == NULL)
+ return FALSE;
+ table->files = tmp;
+ }
+
+ table->files[table->num_files].name = cur_file;
+ table->files[table->num_files].dir = dir;
+ table->files[table->num_files].time = xtime;
+ table->files[table->num_files].size = size;
+ table->num_files++;
+ return TRUE;
+}
+
+/* Read directory or file name entry format, starting with byte of
+ format count entries, ULEB128 pairs of entry formats, ULEB128 of
+ entries count and the entries themselves in the described entry
+ format. */
+
+static bfd_boolean
+read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp,
+ bfd_byte *buf_end, struct line_info_table *table,
+ bfd_boolean (*callback) (struct line_info_table *table,
+ char *cur_file,
+ unsigned int dir,
+ unsigned int time,
+ unsigned int size))
+{
+ bfd *abfd = unit->abfd;
+ bfd_byte format_count, formati;
+ bfd_vma data_count, datai;
+ bfd_byte *buf = *bufp;
+ bfd_byte *format_header_data;
+ unsigned int bytes_read;
+
+ format_count = read_1_byte (abfd, buf, buf_end);
+ buf += 1;
+ format_header_data = buf;
+ for (formati = 0; formati < format_count; formati++)
+ {
+ _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end);
+ buf += bytes_read;
+ _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end);
+ buf += bytes_read;
+ }
+
+ data_count = _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end);
+ buf += bytes_read;
+ if (format_count == 0 && data_count != 0)
+ {
+ _bfd_error_handler (_("Dwarf Error: Zero format count."));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* PR 22210. Paranoia check. Don't bother running the loop
+ if we know that we are going to run out of buffer. */
+ if (data_count > (bfd_vma) (buf_end - buf))
+ {
+ _bfd_error_handler (_("Dwarf Error: data count (%Lx) larger than buffer size."),
+ data_count);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ for (datai = 0; datai < data_count; datai++)
+ {
+ bfd_byte *format = format_header_data;
+ struct fileinfo fe;
+
+ memset (&fe, 0, sizeof fe);
+ for (formati = 0; formati < format_count; formati++)
+ {
+ bfd_vma content_type, form;
+ char *string_trash;
+ char **stringp = &string_trash;
+ unsigned int uint_trash, *uintp = &uint_trash;
+ struct attribute attr;
+
+ content_type = _bfd_safe_read_leb128 (abfd, format, &bytes_read,
+ FALSE, buf_end);
+ format += bytes_read;
+ switch (content_type)
+ {
+ case DW_LNCT_path:
+ stringp = &fe.name;
+ break;
+ case DW_LNCT_directory_index:
+ uintp = &fe.dir;
+ break;
+ case DW_LNCT_timestamp:
+ uintp = &fe.time;
+ break;
+ case DW_LNCT_size:
+ uintp = &fe.size;
+ break;
+ case DW_LNCT_MD5:
+ break;
+ default:
+ _bfd_error_handler
+ (_("Dwarf Error: Unknown format content type %Lu."),
+ content_type);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ form = _bfd_safe_read_leb128 (abfd, format, &bytes_read, FALSE,
+ buf_end);
+ format += bytes_read;
+
+ buf = read_attribute_value (&attr, form, 0, unit, buf, buf_end);
+ if (buf == NULL)
+ return FALSE;
+ switch (form)
+ {
+ case DW_FORM_string:
+ case DW_FORM_line_strp:
+ *stringp = attr.u.str;
+ break;
+
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ *uintp = attr.u.val;
+ break;
+ }
+ }
+
+ if (!callback (table, fe.name, fe.dir, fe.time, fe.size))
+ return FALSE;
+ }
+
+ *bufp = buf;
+ return TRUE;
+}
+
/* Decode the line number information for UNIT. */
static struct line_info_table*
if (stash->dwarf_line_size < 16)
{
_bfd_error_handler
- (_("Dwarf Error: Line info section is too small (%ld)"),
- (long) stash->dwarf_line_size);
+ (_("Dwarf Error: Line info section is too small (%Ld)"),
+ stash->dwarf_line_size);
bfd_set_error (bfd_error_bad_value);
return NULL;
}
offset_size = 8;
}
- if (lh.total_length > stash->dwarf_line_size)
+ if (lh.total_length > (size_t) (line_end - line_ptr))
{
_bfd_error_handler
/* xgettext: c-format */
- (_("Dwarf Error: Line info data is bigger (0x%lx) than the section (0x%lx)"),
- (long) lh.total_length, (long) stash->dwarf_line_size);
+ (_("Dwarf Error: Line info data is bigger (%#Lx)"
+ " than the space remaining in the section (%#lx)"),
+ lh.total_length, (unsigned long) (line_end - line_ptr));
bfd_set_error (bfd_error_bad_value);
return NULL;
}
line_end = line_ptr + lh.total_length;
lh.version = read_2_bytes (abfd, line_ptr, line_end);
- if (lh.version < 2 || lh.version > 4)
+ if (lh.version < 2 || lh.version > 5)
{
_bfd_error_handler
(_("Dwarf Error: Unhandled .debug_line version %d."), lh.version);
}
line_ptr += 2;
- if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end)
+ if (line_ptr + offset_size + (lh.version >= 5 ? 8 : (lh.version >= 4 ? 6 : 5))
+ >= line_end)
{
_bfd_error_handler
(_("Dwarf Error: Ran out of room reading prologue"));
return NULL;
}
+ if (lh.version >= 5)
+ {
+ unsigned int segment_selector_size;
+
+ /* Skip address size. */
+ read_1_byte (abfd, line_ptr, line_end);
+ line_ptr += 1;
+
+ segment_selector_size = read_1_byte (abfd, line_ptr, line_end);
+ line_ptr += 1;
+ if (segment_selector_size != 0)
+ {
+ _bfd_error_handler
+ (_("Dwarf Error: Line info unsupported segment selector size %u."),
+ segment_selector_size);
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+ }
+
if (offset_size == 4)
lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end);
else
line_ptr += 1;
}
- /* Read directory table. */
- while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
+ if (lh.version >= 5)
{
- line_ptr += bytes_read;
+ /* Read directory table. */
+ if (!read_formatted_entries (unit, &line_ptr, line_end, table,
+ line_info_add_include_dir_stub))
+ goto fail;
- if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0)
+ /* Read file name table. */
+ if (!read_formatted_entries (unit, &line_ptr, line_end, table,
+ line_info_add_file_name))
+ goto fail;
+ }
+ else
+ {
+ /* Read directory table. */
+ while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
{
- char **tmp;
+ line_ptr += bytes_read;
- amt = table->num_dirs + DIR_ALLOC_CHUNK;
- amt *= sizeof (char *);
-
- tmp = (char **) bfd_realloc (table->dirs, amt);
- if (tmp == NULL)
+ if (!line_info_add_include_dir (table, cur_dir))
goto fail;
- table->dirs = tmp;
}
- table->dirs[table->num_dirs++] = cur_dir;
- }
-
- line_ptr += bytes_read;
-
- /* Read file name table. */
- while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
- {
line_ptr += bytes_read;
- if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
+ /* Read file name table. */
+ while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
{
- struct fileinfo *tmp;
+ unsigned int dir, xtime, size;
+
+ line_ptr += bytes_read;
- amt = table->num_files + FILE_ALLOC_CHUNK;
- amt *= sizeof (struct fileinfo);
+ dir = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
+ line_ptr += bytes_read;
+ xtime = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
+ line_ptr += bytes_read;
+ size = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
+ line_ptr += bytes_read;
- tmp = (struct fileinfo *) bfd_realloc (table->files, amt);
- if (tmp == NULL)
+ if (!line_info_add_file_name (table, cur_file, dir, xtime, size))
goto fail;
- table->files = tmp;
}
- table->files[table->num_files].name = cur_file;
- table->files[table->num_files].dir =
- _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
- line_ptr += bytes_read;
- table->files[table->num_files].time
- = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
line_ptr += bytes_read;
- table->files[table->num_files].size
- = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
- line_ptr += bytes_read;
- table->num_files++;
}
- line_ptr += bytes_read;
-
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
{
unsigned int discriminator = 0;
int is_stmt = lh.default_is_stmt;
int end_sequence = 0;
+ unsigned int dir, xtime, size;
/* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some
compilers generate address sequences that are wildly out of
order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler
bfd_vma high_pc = 0;
/* Decode the table. */
- while (! end_sequence)
+ while (!end_sequence && line_ptr < line_end)
{
op_code = read_1_byte (abfd, line_ptr, line_end);
line_ptr += 1;
case DW_LNE_define_file:
cur_file = read_string (abfd, line_ptr, line_end, &bytes_read);
line_ptr += bytes_read;
- if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
- {
- struct fileinfo *tmp;
-
- amt = table->num_files + FILE_ALLOC_CHUNK;
- amt *= sizeof (struct fileinfo);
- tmp = (struct fileinfo *) bfd_realloc (table->files, amt);
- if (tmp == NULL)
- goto line_fail;
- table->files = tmp;
- }
- table->files[table->num_files].name = cur_file;
- table->files[table->num_files].dir =
- _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
+ dir = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
+ FALSE, line_end);
line_ptr += bytes_read;
- table->files[table->num_files].time =
- _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
+ xtime = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
+ FALSE, line_end);
line_ptr += bytes_read;
- table->files[table->num_files].size =
- _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
+ size = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
+ FALSE, line_end);
line_ptr += bytes_read;
- table->num_files++;
+ if (!line_info_add_file_name (table, cur_file, dir,
+ xtime, size))
+ goto line_fail;
break;
case DW_LNE_set_discriminator:
discriminator =
case DW_LNS_set_basic_block:
break;
case DW_LNS_const_add_pc:
+ if (lh.line_range == 0)
+ goto line_fail;
if (lh.maximum_ops_per_insn == 1)
address += (lh.minimum_instruction_length
* ((255 - lh.opcode_base) / lh.line_range));
return table;
fail:
- if (table->sequences != NULL)
- free (table->sequences);
+ while (table->sequences != NULL)
+ {
+ struct line_sequence* seq = table->sequences;
+ table->sequences = table->sequences->prev_sequence;
+ free (seq);
+ }
if (table->files != NULL)
free (table->files);
if (table->dirs != NULL)
return FALSE;
}
-static char *
+static bfd_boolean
find_abstract_instance_name (struct comp_unit *unit,
+ bfd_byte *orig_info_ptr,
struct attribute *attr_ptr,
+ const char **pname,
bfd_boolean *is_linkage)
{
bfd *abfd = unit->abfd;
struct abbrev_info *abbrev;
bfd_uint64_t die_ref = attr_ptr->u.val;
struct attribute attr;
- char *name = NULL;
+ const 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. */
if (attr_ptr->form == DW_FORM_ref_addr)
{
/* We only support DW_FORM_ref_addr within the same file, so
- any relocations should be resolved already. */
- if (!die_ref)
- abort ();
-
- info_ptr = unit->sec_info_ptr + die_ref;
- info_ptr_end = unit->end_ptr;
+ any relocations should be resolved already. Check this by
+ testing for a zero die_ref; There can't be a valid reference
+ to the header of a .debug_info section.
+ DW_FORM_ref_addr is an offset relative to .debug_info.
+ Normally when using the GNU linker this is accomplished by
+ emitting a symbolic reference to a label, because .debug_info
+ sections are linked at zero. When there are multiple section
+ groups containing .debug_info, as there might be in a
+ relocatable object file, it would be reasonable to assume that
+ a symbolic reference to a label in any .debug_info section
+ might be used. Since we lay out multiple .debug_info
+ sections at non-zero VMAs (see place_sections), and read
+ them contiguously into stash->info_ptr_memory, that means
+ the reference is relative to stash->info_ptr_memory. */
+ size_t total;
+
+ info_ptr = unit->stash->info_ptr_memory;
+ info_ptr_end = unit->stash->info_ptr_end;
+ total = info_ptr_end - info_ptr;
+ if (!die_ref || die_ref >= total)
+ {
+ _bfd_error_handler
+ (_("Dwarf Error: Invalid abstract instance DIE ref."));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ info_ptr += die_ref;
/* Now find the CU containing this pointer. */
if (info_ptr >= unit->info_ptr_unit && info_ptr < unit->end_ptr)
- ;
+ info_ptr_end = unit->end_ptr;
else
{
/* Check other CUs to see if they contain the abbrev. */
break;
if (u)
- unit = u;
+ {
+ unit = u;
+ info_ptr_end = unit->end_ptr;
+ }
/* else FIXME: What do we do now ? */
}
}
if (info_ptr == NULL)
{
_bfd_error_handler
- (_("Dwarf Error: Unable to read alt ref %u."), die_ref);
+ (_("Dwarf Error: Unable to read alt ref %llu."),
+ (long long) die_ref);
bfd_set_error (bfd_error_bad_value);
- return NULL;
+ return FALSE;
}
- info_ptr_end = unit->stash->alt_dwarf_info_buffer + unit->stash->alt_dwarf_info_size;
+ info_ptr_end = (unit->stash->alt_dwarf_info_buffer
+ + unit->stash->alt_dwarf_info_size);
/* FIXME: Do we need to locate the correct CU, in a similar
fashion to the code in the DW_FORM_ref_addr case above ? */
}
else
{
- info_ptr = unit->info_ptr_unit + die_ref;
+ /* DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8 or
+ DW_FORM_ref_udata. These are all references relative to the
+ start of the current CU. */
+ size_t total;
+
+ info_ptr = unit->info_ptr_unit;
info_ptr_end = unit->end_ptr;
+ total = info_ptr_end - info_ptr;
+ if (!die_ref || die_ref >= total)
+ {
+ _bfd_error_handler
+ (_("Dwarf Error: Invalid abstract instance DIE ref."));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ info_ptr += die_ref;
}
abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
_bfd_error_handler
(_("Dwarf Error: Could not find abbrev number %u."), abbrev_number);
bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
else
{
info_ptr, info_ptr_end);
if (info_ptr == NULL)
break;
+ /* It doesn't ever make sense for DW_AT_specification to
+ refer to the same DIE. Stop simple recursion. */
+ if (info_ptr == orig_info_ptr)
+ {
+ _bfd_error_handler
+ (_("Dwarf Error: Abstract instance recursion detected."));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
switch (attr.name)
{
case DW_AT_name:
}
break;
case DW_AT_specification:
- name = find_abstract_instance_name (unit, &attr, is_linkage);
+ if (!find_abstract_instance_name (unit, info_ptr, &attr,
+ pname, is_linkage))
+ return FALSE;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
}
}
}
- return name;
+ *pname = name;
+ return TRUE;
}
static bfd_boolean
bfd *abfd = unit->abfd;
bfd_byte *info_ptr = unit->first_child_die_ptr;
bfd_byte *info_ptr_end = unit->stash->info_ptr_end;
- int nesting_level = 1;
- struct funcinfo **nested_funcs;
+ int nesting_level = 0;
+ struct nest_funcinfo {
+ struct funcinfo *func;
+ } *nested_funcs;
int nested_funcs_size;
/* Maintain a stack of in-scope functions and inlined functions, which we
can use to set the caller_func field. */
nested_funcs_size = 32;
- nested_funcs = (struct funcinfo **)
- bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
+ nested_funcs = (struct nest_funcinfo *)
+ bfd_malloc (nested_funcs_size * sizeof (*nested_funcs));
if (nested_funcs == NULL)
return FALSE;
- nested_funcs[nesting_level] = 0;
+ nested_funcs[nesting_level].func = 0;
- while (nesting_level)
+ while (nesting_level >= 0)
{
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
BFD_ASSERT (!unit->cached);
if (func->tag == DW_TAG_inlined_subroutine)
- for (i = nesting_level - 1; i >= 1; i--)
- if (nested_funcs[i])
+ for (i = nesting_level; i-- != 0; )
+ if (nested_funcs[i].func)
{
- func->caller_func = nested_funcs[i];
+ func->caller_func = nested_funcs[i].func;
break;
}
- nested_funcs[nesting_level] = func;
+ nested_funcs[nesting_level].func = func;
}
else
{
}
/* No inline function in scope at this nesting level. */
- nested_funcs[nesting_level] = 0;
+ nested_funcs[nesting_level].func = 0;
}
for (i = 0; i < abbrev->num_attrs; ++i)
{
- info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, info_ptr_end);
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i],
+ unit, info_ptr, info_ptr_end);
if (info_ptr == NULL)
goto fail;
case DW_AT_abstract_origin:
case DW_AT_specification:
- func->name = find_abstract_instance_name (unit, &attr,
- &func->is_linkage);
+ if (!find_abstract_instance_name (unit, info_ptr, &attr,
+ &func->name,
+ &func->is_linkage))
+ goto fail;
break;
case DW_AT_name:
switch (attr.name)
{
case DW_AT_name:
- var->name = attr.u.str;
+ if (is_str_attr (attr.form))
+ var->name = attr.u.str;
break;
case DW_AT_decl_file:
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_exprloc:
- if (*attr.u.blk->data == DW_OP_addr)
+ if (attr.u.blk->data != NULL
+ && *attr.u.blk->data == DW_OP_addr)
{
var->stack = 0;
if (nesting_level >= nested_funcs_size)
{
- struct funcinfo **tmp;
+ struct nest_funcinfo *tmp;
nested_funcs_size *= 2;
- tmp = (struct funcinfo **)
+ tmp = (struct nest_funcinfo *)
bfd_realloc (nested_funcs,
- nested_funcs_size * sizeof (struct funcinfo *));
+ nested_funcs_size * sizeof (*nested_funcs));
if (tmp == NULL)
goto fail;
nested_funcs = tmp;
}
- nested_funcs[nesting_level] = 0;
+ nested_funcs[nesting_level].func = 0;
}
}
struct comp_unit* unit;
unsigned int version;
bfd_uint64_t abbrev_offset = 0;
- unsigned int addr_size;
+ /* Initialize it just to avoid a GCC false warning. */
+ unsigned int addr_size = -1;
struct abbrev_info** abbrevs;
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
bfd_vma high_pc = 0;
bfd *abfd = stash->bfd_ptr;
bfd_boolean high_pc_relative = FALSE;
+ enum dwarf_unit_type unit_type;
version = read_2_bytes (abfd, info_ptr, end_ptr);
info_ptr += 2;
- BFD_ASSERT (offset_size == 4 || offset_size == 8);
- if (offset_size == 4)
- abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr);
- else
- abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr);
- info_ptr += offset_size;
- addr_size = read_1_byte (abfd, info_ptr, end_ptr);
- info_ptr += 1;
-
- if (version != 2 && version != 3 && version != 4)
+ if (version < 2 || version > 5)
{
/* PR 19872: A version number of 0 probably means that there is padding
at the end of the .debug_info section. Gold puts it there when
{
_bfd_error_handler
(_("Dwarf Error: found dwarf version '%u', this reader"
- " only handles version 2, 3 and 4 information."), version);
+ " only handles version 2, 3, 4 and 5 information."), version);
bfd_set_error (bfd_error_bad_value);
}
return NULL;
}
+ if (version < 5)
+ unit_type = DW_UT_compile;
+ else
+ {
+ unit_type = read_1_byte (abfd, info_ptr, end_ptr);
+ info_ptr += 1;
+
+ addr_size = read_1_byte (abfd, info_ptr, end_ptr);
+ info_ptr += 1;
+ }
+
+ BFD_ASSERT (offset_size == 4 || offset_size == 8);
+ if (offset_size == 4)
+ abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr);
+ else
+ abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr);
+ info_ptr += offset_size;
+
+ if (version < 5)
+ {
+ addr_size = read_1_byte (abfd, info_ptr, end_ptr);
+ info_ptr += 1;
+ }
+
+ if (unit_type == DW_UT_type)
+ {
+ /* Skip type signature. */
+ info_ptr += 8;
+
+ /* Skip type offset. */
+ info_ptr += offset_size;
+ }
+
if (addr_size > sizeof (bfd_vma))
{
_bfd_error_handler
unit->end_ptr = end_ptr;
unit->stash = stash;
unit->info_ptr_unit = info_ptr_unit;
- unit->sec_info_ptr = stash->sec_info_ptr;
for (i = 0; i < abbrev->num_attrs; ++i)
{
break;
case DW_AT_name:
- unit->name = attr.u.str;
+ if (is_str_attr (attr.form))
+ unit->name = attr.u.str;
break;
case DW_AT_low_pc:
free (stash->dwarf_line_buffer);
if (stash->dwarf_str_buffer)
free (stash->dwarf_str_buffer);
+ if (stash->dwarf_line_str_buffer)
+ free (stash->dwarf_line_str_buffer);
if (stash->dwarf_ranges_buffer)
free (stash->dwarf_ranges_buffer);
if (stash->info_ptr_memory)