/* DWARF 2 support.
- Copyright (C) 1994-2019 Free Software Foundation, Inc.
+ Copyright (C) 1994-2021 Free Software Foundation, Inc.
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
(gavin@cygnus.com).
bfd_vma adj_vma;
};
-struct dwarf2_debug
+struct dwarf2_debug_file
{
- /* A list of all previously read comp_units. */
- struct comp_unit *all_comp_units;
-
- /* Last comp unit in list above. */
- struct comp_unit *last_comp_unit;
+ /* The actual bfd from which debug info was loaded. Might be
+ different to orig_bfd because of gnu_debuglink sections. */
+ bfd *bfd_ptr;
- /* Names of the debug sections. */
- const struct dwarf_debug_section *debug_sections;
+ /* Pointer to the symbol table. */
+ asymbol **syms;
- /* 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. */
+ /* The current info pointer for the .debug_info section being parsed. */
bfd_byte *info_ptr;
- /* Pointer to the end of the .debug_info section memory buffer. */
- bfd_byte *info_ptr_end;
-
- /* Pointer to the original bfd for which debug was loaded. This is what
- we use to compare and so check that the cached debug data is still
- valid - it saves having to possibly dereference the gnu_debuglink each
- time. */
- bfd *orig_bfd;
-
- /* Pointer to the bfd. The bfd might be different than expected
- because of gnu_debuglink sections. */
- bfd *bfd_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 .debug_info sections. */
- bfd_byte *info_ptr_memory;
+ bfd_byte *dwarf_info_buffer;
- /* Pointer to the symbol table. */
- asymbol **syms;
+ /* Length of the loaded .debug_info sections. */
+ bfd_size_type dwarf_info_size;
/* Pointer to the .debug_abbrev section loaded into memory. */
bfd_byte *dwarf_abbrev_buffer;
/* Length of the loaded .debug_ranges section. */
bfd_size_type dwarf_ranges_size;
+ /* Pointer to the .debug_rnglists section loaded into memory. */
+ bfd_byte *dwarf_rnglists_buffer;
+
+ /* Length of the loaded .debug_rnglists section. */
+ bfd_size_type dwarf_rnglists_size;
+
+ /* A list of all previously read comp_units. */
+ struct comp_unit *all_comp_units;
+
+ /* Last comp unit in list above. */
+ struct comp_unit *last_comp_unit;
+
+ /* Line table at line_offset zero. */
+ struct line_info_table *line_table;
+
+ /* Hash table to map offsets to decoded abbrevs. */
+ htab_t abbrev_offsets;
+};
+
+struct dwarf2_debug
+{
+ /* Names of the debug sections. */
+ const struct dwarf_debug_section *debug_sections;
+
+ /* Per-file stuff. */
+ struct dwarf2_debug_file f, alt;
+
+ /* Pointer to the original bfd for which debug was loaded. This is what
+ we use to compare and so check that the cached debug data is still
+ valid - it saves having to possibly dereference the gnu_debuglink each
+ time. */
+ bfd *orig_bfd;
+
/* If the most recent call to bfd_find_nearest_line was given an
address in an inlined function, preserve a pointer into the
calling chain for subsequent calls to bfd_find_inliner_info to
/* A list of the variables found in this comp. unit. */
struct varinfo *variable_table;
- /* Pointer to dwarf2_debug structure. */
+ /* Pointers to dwarf2_debug structures. */
struct dwarf2_debug *stash;
+ struct dwarf2_debug_file *file;
/* DWARF format version for this unit - from unit header. */
int version;
/* This data structure holds the information of an abbrev. */
struct abbrev_info
{
- unsigned int number; /* Number identifying abbrev. */
- enum dwarf_tag tag; /* DWARF tag. */
- int has_children; /* Boolean. */
- unsigned int num_attrs; /* Number of attributes. */
- struct attr_abbrev *attrs; /* An array of attribute descriptions. */
- struct abbrev_info *next; /* Next in chain. */
+ unsigned int number; /* Number identifying abbrev. */
+ enum dwarf_tag tag; /* DWARF tag. */
+ bfd_boolean has_children; /* TRUE if the abbrev has children. */
+ unsigned int num_attrs; /* Number of attributes. */
+ struct attr_abbrev * attrs; /* An array of attribute descriptions. */
+ struct abbrev_info * next; /* Next in chain. */
};
struct attr_abbrev
{ ".debug_pubnames", ".zdebug_pubnames" },
{ ".debug_pubtypes", ".zdebug_pubtypes" },
{ ".debug_ranges", ".zdebug_ranges" },
+ { ".debug_rnglists", ".zdebug_rnglist" },
{ ".debug_static_func", ".zdebug_static_func" },
{ ".debug_static_vars", ".zdebug_static_vars" },
{ ".debug_str", ".zdebug_str", },
debug_pubnames,
debug_pubtypes,
debug_ranges,
+ debug_rnglists,
debug_static_func,
debug_static_vars,
debug_str,
bfd_byte ** section_buffer,
bfd_size_type * section_size)
{
- asection *msec;
const char *section_name = sec->uncompressed_name;
bfd_byte *contents = *section_buffer;
- bfd_size_type amt;
/* The section may have already been read. */
if (contents == NULL)
{
+ bfd_size_type amt;
+ asection *msec;
+ ufile_ptr filesize;
+
msec = bfd_get_section_by_name (abfd, section_name);
- if (! msec)
+ if (msec == NULL)
{
section_name = sec->compressed_name;
if (section_name != NULL)
msec = bfd_get_section_by_name (abfd, section_name);
}
- if (! msec)
+ if (msec == NULL)
{
_bfd_error_handler (_("DWARF error: can't find %s section."),
sec->uncompressed_name);
return FALSE;
}
- *section_size = msec->rawsize ? msec->rawsize : msec->size;
+ amt = bfd_get_section_limit_octets (abfd, msec);
+ filesize = bfd_get_file_size (abfd);
+ if (amt >= filesize)
+ {
+ /* PR 26946 */
+ _bfd_error_handler (_("DWARF error: section %s is larger than its filesize! (0x%lx vs 0x%lx)"),
+ section_name, (long) amt, (long) filesize);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ *section_size = amt;
/* Paranoia - alloc one extra so that we can make sure a string
section is NUL terminated. */
- amt = *section_size + 1;
+ amt += 1;
if (amt == 0)
{
+ /* Paranoia - this should never happen. */
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
{
bfd_uint64_t offset;
struct dwarf2_debug *stash = unit->stash;
+ struct dwarf2_debug_file *file = unit->file;
char *str;
if (buf + unit->offset_size > buf_end)
*bytes_read_ptr = unit->offset_size;
if (! read_section (unit->abfd, &stash->debug_sections[debug_str],
- stash->syms, offset,
- &stash->dwarf_str_buffer, &stash->dwarf_str_size))
+ file->syms, offset,
+ &file->dwarf_str_buffer, &file->dwarf_str_size))
return NULL;
- str = (char *) stash->dwarf_str_buffer + offset;
+ str = (char *) file->dwarf_str_buffer + offset;
if (*str == '\0')
return NULL;
return str;
{
bfd_uint64_t offset;
struct dwarf2_debug *stash = unit->stash;
+ struct dwarf2_debug_file *file = unit->file;
char *str;
if (buf + unit->offset_size > 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))
+ file->syms, offset,
+ &file->dwarf_line_str_buffer,
+ &file->dwarf_line_str_size))
return NULL;
- str = (char *) stash->dwarf_line_str_buffer + offset;
+ str = (char *) file->dwarf_line_str_buffer + offset;
if (*str == '\0')
return NULL;
return str;
*bytes_read_ptr = unit->offset_size;
- if (stash->alt_bfd_ptr == NULL)
+ if (stash->alt.bfd_ptr == NULL)
{
bfd *debug_bfd;
char *debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
bfd_close (debug_bfd);
return NULL;
}
- stash->alt_bfd_ptr = debug_bfd;
+ stash->alt.bfd_ptr = debug_bfd;
}
- if (! read_section (unit->stash->alt_bfd_ptr,
+ 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))
+ stash->alt.syms, offset,
+ &stash->alt.dwarf_str_buffer,
+ &stash->alt.dwarf_str_size))
return NULL;
- str = (char *) stash->alt_dwarf_str_buffer + offset;
+ str = (char *) stash->alt.dwarf_str_buffer + offset;
if (*str == '\0')
return NULL;
{
struct dwarf2_debug *stash = unit->stash;
- if (stash->alt_bfd_ptr == NULL)
+ if (stash->alt.bfd_ptr == NULL)
{
bfd *debug_bfd;
char *debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
bfd_close (debug_bfd);
return NULL;
}
- stash->alt_bfd_ptr = debug_bfd;
+ stash->alt.bfd_ptr = debug_bfd;
}
- if (! read_section (unit->stash->alt_bfd_ptr,
+ 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))
+ stash->alt.syms, offset,
+ &stash->alt.dwarf_info_buffer,
+ &stash->alt.dwarf_info_size))
return NULL;
- return stash->alt_dwarf_info_buffer + offset;
+ return stash->alt.dwarf_info_buffer + offset;
}
static bfd_uint64_t
return NULL;
}
+/* We keep a hash table to map .debug_abbrev section offsets to the
+ array of abbrevs, so that compilation units using the same set of
+ abbrevs do not waste memory. */
+
+struct abbrev_offset_entry
+{
+ size_t offset;
+ struct abbrev_info **abbrevs;
+};
+
+static hashval_t
+hash_abbrev (const void *p)
+{
+ const struct abbrev_offset_entry *ent = p;
+ return htab_hash_pointer ((void *) ent->offset);
+}
+
+static int
+eq_abbrev (const void *pa, const void *pb)
+{
+ const struct abbrev_offset_entry *a = pa;
+ const struct abbrev_offset_entry *b = pb;
+ return a->offset == b->offset;
+}
+
+static void
+del_abbrev (void *p)
+{
+ struct abbrev_offset_entry *ent = p;
+ struct abbrev_info **abbrevs = ent->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;
+ }
+ }
+ free (ent);
+}
+
/* In DWARF version 2, the description of the debugging information is
stored in a separate .debug_abbrev section. Before we read any
dies from a section we read in all abbreviations and install them
in a hash table. */
static struct abbrev_info**
-read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
+read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash,
+ struct dwarf2_debug_file *file)
{
struct abbrev_info **abbrevs;
bfd_byte *abbrev_ptr;
struct abbrev_info *cur_abbrev;
unsigned int abbrev_number, bytes_read, abbrev_name;
unsigned int abbrev_form, hash_number;
- bfd_size_type amt;
+ size_t amt;
+ void **slot;
+ struct abbrev_offset_entry ent = { offset, NULL };
+
+ if (ent.offset != offset)
+ return NULL;
+
+ slot = htab_find_slot (file->abbrev_offsets, &ent, INSERT);
+ if (slot == NULL)
+ return NULL;
+ if (*slot != NULL)
+ return ((struct abbrev_offset_entry *) (*slot))->abbrevs;
if (! read_section (abfd, &stash->debug_sections[debug_abbrev],
- stash->syms, offset,
- &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
+ file->syms, offset,
+ &file->dwarf_abbrev_buffer,
+ &file->dwarf_abbrev_size))
return NULL;
amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
if (abbrevs == NULL)
return NULL;
- abbrev_ptr = stash->dwarf_abbrev_buffer + offset;
- abbrev_end = stash->dwarf_abbrev_buffer + stash->dwarf_abbrev_size;
+ abbrev_ptr = file->dwarf_abbrev_buffer + offset;
+ abbrev_end = file->dwarf_abbrev_buffer + file->dwarf_abbrev_size;
abbrev_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
FALSE, abbrev_end);
abbrev_ptr += bytes_read;
already read (which means we are about to read the abbreviations
for the next compile unit) or if the end of the abbreviation
table is reached. */
- if ((size_t) (abbrev_ptr - stash->dwarf_abbrev_buffer)
- >= stash->dwarf_abbrev_size)
+ if ((size_t) (abbrev_ptr - file->dwarf_abbrev_buffer)
+ >= file->dwarf_abbrev_size)
break;
abbrev_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr,
&bytes_read, FALSE, abbrev_end);
if (lookup_abbrev (abbrev_number, abbrevs) != NULL)
break;
}
+
+ *slot = bfd_malloc (sizeof ent);
+ if (!*slot)
+ goto fail;
+ ent.abbrevs = abbrevs;
+ memcpy (*slot, &ent, sizeof ent);
return abbrevs;
fail:
static inline bfd_boolean
is_str_attr (enum dwarf_form form)
{
- return (form == DW_FORM_string || form == DW_FORM_strp
- || form == DW_FORM_line_strp || form == DW_FORM_GNU_strp_alt);
+ return (form == DW_FORM_string
+ || form == DW_FORM_strp
+ || form == DW_FORM_strx
+ || form == DW_FORM_strx1
+ || form == DW_FORM_strx2
+ || form == DW_FORM_strx3
+ || form == DW_FORM_strx4
+ || form == DW_FORM_line_strp
+ || form == DW_FORM_GNU_strp_alt);
+}
+
+static const char *
+read_indexed_string (bfd_uint64_t idx ATTRIBUTE_UNUSED,
+ struct comp_unit * unit ATTRIBUTE_UNUSED)
+{
+ /* FIXME: Add support for indexed strings. */
+ return "<indexed strings not yet supported>";
}
/* Read and fill in the value of attribute ATTR as described by FORM.
bfd *abfd = unit->abfd;
unsigned int bytes_read;
struct dwarf_block *blk;
- bfd_size_type amt;
+ size_t amt;
if (info_ptr >= info_ptr_end && form != DW_FORM_flag_present)
{
switch (form)
{
+ case DW_FORM_flag_present:
+ attr->u.val = 1;
+ break;
case DW_FORM_ref_addr:
/* DW_FORM_ref_addr is an address in DWARF2, and an offset in
DWARF3. */
- if (unit->version == 3 || unit->version == 4)
+ if (unit->version >= 3)
{
if (unit->offset_size == 4)
attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end);
info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk);
attr->u.blk = blk;
break;
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_addrx1:
+ attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
+ info_ptr += 1;
+ break;
case DW_FORM_data2:
+ case DW_FORM_ref2:
attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
info_ptr += 2;
break;
+ case DW_FORM_addrx3:
+ attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
+ attr->u.val &= 0xffffff;
+ info_ptr += 3;
+ break;
+ case DW_FORM_ref4:
case DW_FORM_data4:
+ case DW_FORM_addrx4:
attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
info_ptr += 4;
break;
case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
info_ptr += 8;
break;
attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_strx1:
+ attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
+ info_ptr += 1;
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
+ case DW_FORM_strx2:
+ attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
+ info_ptr += 2;
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
+ case DW_FORM_strx3:
+ attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
+ info_ptr += 3;
+ attr->u.val &= 0xffffff;
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
+ case DW_FORM_strx4:
+ attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
+ info_ptr += 4;
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
+ case DW_FORM_strx:
+ attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
+ FALSE, info_ptr_end);
+ info_ptr += bytes_read;
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
case DW_FORM_exprloc:
case DW_FORM_block:
amt = sizeof (struct dwarf_block);
info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk);
attr->u.blk = blk;
break;
- case DW_FORM_data1:
- attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
- info_ptr += 1;
- break;
- case DW_FORM_flag:
- attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
- info_ptr += 1;
- break;
- case DW_FORM_flag_present:
- attr->u.val = 1;
- break;
case DW_FORM_sdata:
attr->u.sval = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
TRUE, info_ptr_end);
info_ptr += bytes_read;
break;
- case DW_FORM_udata:
- attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
- break;
- case DW_FORM_ref1:
- attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
- info_ptr += 1;
- break;
- case DW_FORM_ref2:
- attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 2;
- break;
- case DW_FORM_ref4:
- attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 4;
- break;
- case DW_FORM_ref8:
- attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 8;
- break;
- case DW_FORM_ref_sig8:
- attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 8;
- break;
case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ case DW_FORM_addrx:
attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
FALSE, info_ptr_end);
info_ptr += bytes_read;
attr->form = DW_FORM_sdata;
attr->u.sval = implicit_const;
break;
+ case DW_FORM_data16:
+ /* This is really a "constant", but there is no way to store that
+ so pretend it is a 16 byte block instead. */
+ amt = sizeof (struct dwarf_block);
+ blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
+ if (blk == NULL)
+ return NULL;
+ blk->size = 16;
+ info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk);
+ attr->u.blk = blk;
+ break;
+
default:
_bfd_error_handler (_("DWARF error: invalid or unhandled FORM value: %#x"),
form);
struct arange arange;
/* Where the symbol is defined. */
asection * sec;
+ /* The offset of the funcinfo from the start of the unit. */
+ bfd_uint64_t unit_offset;
};
struct lookup_funcinfo
struct varinfo
{
- /* Pointer to previous variable in list of all variables */
+ /* Pointer to previous variable in list of all variables. */
struct varinfo *prev_var;
- /* Source location file name */
+ /* The offset of the varinfo from the start of the unit. */
+ bfd_uint64_t unit_offset;
+ /* Source location file name. */
char *file;
- /* Source location line number */
+ /* Source location line number. */
int line;
+ /* The type of this variable. */
int tag;
+ /* The name of the variable, if it has one. */
char *name;
+ /* The address of the variable. */
bfd_vma addr;
- /* Where the symbol is defined */
+ /* Where the symbol is defined. */
asection *sec;
- /* Is this a stack variable? */
- unsigned int stack: 1;
+ /* Is this a stack variable? */
+ bfd_boolean stack;
};
/* Return TRUE if NEW_LINE should sort after LINE. */
unsigned int discriminator,
int end_sequence)
{
- bfd_size_type amt = sizeof (struct line_info);
+ size_t amt = sizeof (struct line_info);
struct line_sequence* seq = table->sequences;
struct line_info* info = (struct line_info *) bfd_alloc (table->abfd, amt);
build_line_info_table (struct line_info_table * table,
struct line_sequence * seq)
{
- bfd_size_type amt;
- struct line_info** line_info_lookup;
- struct line_info* each_line;
- unsigned int num_lines;
- unsigned int line_index;
+ size_t amt;
+ struct line_info **line_info_lookup;
+ struct line_info *each_line;
+ unsigned int num_lines;
+ unsigned int line_index;
if (seq->line_info_lookup != NULL)
return TRUE;
static bfd_boolean
sort_line_sequences (struct line_info_table* table)
{
- bfd_size_type amt;
- struct line_sequence* sequences;
- struct line_sequence* seq;
- unsigned int n = 0;
- unsigned int num_sequences = table->num_sequences;
- bfd_vma last_high_pc;
+ size_t amt;
+ struct line_sequence *sequences;
+ struct line_sequence *seq;
+ unsigned int n = 0;
+ unsigned int num_sequences = table->num_sequences;
+ bfd_vma last_high_pc;
if (num_sequences == 0)
return TRUE;
if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0)
{
char **tmp;
- bfd_size_type amt;
+ size_t amt;
amt = table->num_dirs + DIR_ALLOC_CHUNK;
amt *= sizeof (char *);
if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
{
struct fileinfo *tmp;
- bfd_size_type amt;
+ size_t amt;
amt = table->num_files + FILE_ALLOC_CHUNK;
amt *= sizeof (struct fileinfo);
case DW_FORM_udata:
*uintp = attr.u.val;
break;
+
+ case DW_FORM_data16:
+ /* MD5 data is in the attr.blk, but we are ignoring those. */
+ break;
}
}
- if (!callback (table, fe.name, fe.dir, fe.time, fe.size))
- return FALSE;
+ /* Skip the first "zero entry", which is the compilation dir/file. */
+ if (datai != 0)
+ if (!callback (table, fe.name, fe.dir, fe.time, fe.size))
+ return FALSE;
}
*bufp = buf;
/* Decode the line number information for UNIT. */
static struct line_info_table*
-decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
+decode_line_info (struct comp_unit *unit)
{
bfd *abfd = unit->abfd;
+ struct dwarf2_debug *stash = unit->stash;
+ struct dwarf2_debug_file *file = unit->file;
struct line_info_table* table;
bfd_byte *line_ptr;
bfd_byte *line_end;
char *cur_file, *cur_dir;
unsigned char op_code, extended_op, adj_opcode;
unsigned int exop_len;
- bfd_size_type amt;
+ size_t amt;
- if (! read_section (abfd, &stash->debug_sections[debug_line],
- stash->syms, unit->line_offset,
- &stash->dwarf_line_buffer, &stash->dwarf_line_size))
- return NULL;
+ if (unit->line_offset == 0 && file->line_table)
+ return file->line_table;
- amt = sizeof (struct line_info_table);
- table = (struct line_info_table *) bfd_alloc (abfd, amt);
- if (table == NULL)
+ if (! read_section (abfd, &stash->debug_sections[debug_line],
+ file->syms, unit->line_offset,
+ &file->dwarf_line_buffer, &file->dwarf_line_size))
return NULL;
- table->abfd = abfd;
- table->comp_dir = unit->comp_dir;
- table->num_files = 0;
- table->files = NULL;
-
- table->num_dirs = 0;
- table->dirs = NULL;
-
- table->num_sequences = 0;
- table->sequences = NULL;
-
- table->lcl_head = NULL;
-
- if (stash->dwarf_line_size < 16)
+ if (file->dwarf_line_size < 16)
{
_bfd_error_handler
(_("DWARF error: line info section is too small (%" PRId64 ")"),
- (int64_t) stash->dwarf_line_size);
+ (int64_t) file->dwarf_line_size);
bfd_set_error (bfd_error_bad_value);
return NULL;
}
- line_ptr = stash->dwarf_line_buffer + unit->line_offset;
- line_end = stash->dwarf_line_buffer + stash->dwarf_line_size;
+ line_ptr = file->dwarf_line_buffer + unit->line_offset;
+ line_end = file->dwarf_line_buffer + file->dwarf_line_size;
/* Read in the prologue. */
lh.total_length = read_4_bytes (abfd, line_ptr, line_end);
line_ptr += 1;
}
+ amt = sizeof (struct line_info_table);
+ table = (struct line_info_table *) bfd_alloc (abfd, amt);
+ if (table == NULL)
+ return NULL;
+ table->abfd = abfd;
+ table->comp_dir = unit->comp_dir;
+
+ table->num_files = 0;
+ table->files = NULL;
+
+ table->num_dirs = 0;
+ table->dirs = NULL;
+
+ table->num_sequences = 0;
+ table->sequences = NULL;
+
+ table->lcl_head = NULL;
+
if (lh.version >= 5)
{
/* Read directory table. */
(_("DWARF error: mangled line number section"));
bfd_set_error (bfd_error_bad_value);
line_fail:
- if (filename != NULL)
- free (filename);
+ free (filename);
goto fail;
}
break;
break;
case DW_LNS_set_file:
{
- unsigned int file;
+ unsigned int filenum;
/* The file and directory tables are 0
based, the references are 1 based. */
- file = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
+ filenum = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
+ FALSE, line_end);
line_ptr += bytes_read;
- if (filename)
- free (filename);
- filename = concat_filename (table, file);
+ free (filename);
+ filename = concat_filename (table, filenum);
break;
}
case DW_LNS_set_column:
}
}
- if (filename)
- free (filename);
+ free (filename);
}
+ if (unit->line_offset == 0)
+ file->line_table = table;
if (sort_line_sequences (table))
return table;
table->sequences = table->sequences->prev_sequence;
free (seq);
}
- if (table->files != NULL)
- free (table->files);
- if (table->dirs != NULL)
- free (table->dirs);
+ free (table->files);
+ free (table->dirs);
return NULL;
}
return seq->last_line->address - seq->low_pc;
}
-fail:
+ fail:
*filename_ptr = NULL;
return 0;
}
static bfd_boolean
read_debug_ranges (struct comp_unit * unit)
{
- struct dwarf2_debug * stash = unit->stash;
+ struct dwarf2_debug *stash = unit->stash;
+ struct dwarf2_debug_file *file = unit->file;
return read_section (unit->abfd, &stash->debug_sections[debug_ranges],
- stash->syms, 0,
- &stash->dwarf_ranges_buffer,
- &stash->dwarf_ranges_size);
+ file->syms, 0,
+ &file->dwarf_ranges_buffer, &file->dwarf_ranges_size);
+}
+
+/* Read in the .debug_rnglists section for future reference. */
+
+static bfd_boolean
+read_debug_rnglists (struct comp_unit * unit)
+{
+ struct dwarf2_debug *stash = unit->stash;
+ struct dwarf2_debug_file *file = unit->file;
+
+ return read_section (unit->abfd, &stash->debug_sections[debug_rnglists],
+ file->syms, 0,
+ &file->dwarf_rnglists_buffer, &file->dwarf_rnglists_size);
}
/* Function table functions. */
struct varinfo* each;
for (each = unit->variable_table; each; each = each->prev_var)
- if (each->stack == 0
+ if (! each->stack
&& each->file != NULL
&& each->name != NULL
&& each->addr == addr
return FALSE;
}
-static struct comp_unit *stash_comp_unit (struct dwarf2_debug *);
-static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *,
- struct dwarf2_debug *);
+static struct comp_unit *stash_comp_unit (struct dwarf2_debug *,
+ struct dwarf2_debug_file *);
+static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *);
static bfd_boolean
find_abstract_instance (struct comp_unit *unit,
int *linenumber_ptr)
{
bfd *abfd = unit->abfd;
- bfd_byte *info_ptr;
+ bfd_byte *info_ptr = NULL;
bfd_byte *info_ptr_end;
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
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. */
+ them contiguously into dwarf_info_buffer, that means the
+ reference is relative to dwarf_info_buffer. */
size_t total;
- info_ptr = unit->stash->info_ptr_memory;
- info_ptr_end = unit->stash->info_ptr_end;
+ info_ptr = unit->file->dwarf_info_buffer;
+ info_ptr_end = info_ptr + unit->file->dwarf_info_size;
total = info_ptr_end - info_ptr;
if (!die_ref)
return TRUE;
return FALSE;
}
info_ptr += die_ref;
+ }
+ else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
+ {
+ bfd_boolean first_time = unit->stash->alt.dwarf_info_buffer == NULL;
+
+ info_ptr = read_alt_indirect_ref (unit, die_ref);
+ if (first_time)
+ unit->stash->alt.info_ptr = unit->stash->alt.dwarf_info_buffer;
+ if (info_ptr == NULL)
+ {
+ _bfd_error_handler
+ (_("DWARF error: unable to read alt ref %" PRIu64),
+ (uint64_t) die_ref);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ info_ptr_end = (unit->stash->alt.dwarf_info_buffer
+ + unit->stash->alt.dwarf_info_size);
+ if (unit->stash->alt.all_comp_units)
+ unit = unit->stash->alt.all_comp_units;
+ }
+ if (attr_ptr->form == DW_FORM_ref_addr
+ || attr_ptr->form == DW_FORM_GNU_ref_alt)
+ {
/* 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. */
- struct comp_unit * u;
+ struct comp_unit *u;
for (u = unit->prev_unit; u != NULL; u = u->prev_unit)
if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
break;
- while (u == NULL)
- {
- u = stash_comp_unit (unit->stash);
- if (u == NULL)
- break;
- if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
- break;
- u = NULL;
- }
+ if (attr_ptr->form == DW_FORM_ref_addr)
+ while (u == NULL)
+ {
+ u = stash_comp_unit (unit->stash, &unit->stash->f);
+ if (u == NULL)
+ break;
+ if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
+ break;
+ u = NULL;
+ }
+
+ if (attr_ptr->form == DW_FORM_GNU_ref_alt)
+ while (u == NULL)
+ {
+ u = stash_comp_unit (unit->stash, &unit->stash->alt);
+ if (u == NULL)
+ break;
+ if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
+ break;
+ u = NULL;
+ }
if (u == NULL)
{
info_ptr_end = unit->end_ptr;
}
}
- 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 %" PRIu64),
- (uint64_t) die_ref);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- 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
{
/* DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8 or
}
break;
case DW_AT_decl_file:
- if (!comp_unit_maybe_decode_line_info (unit, unit->stash))
+ if (!comp_unit_maybe_decode_line_info (unit))
return FALSE;
*filename_ptr = concat_filename (unit->line_table,
attr.u.val);
}
static bfd_boolean
-read_rangelist (struct comp_unit *unit, struct arange *arange,
- bfd_uint64_t offset)
+read_ranges (struct comp_unit *unit, struct arange *arange,
+ bfd_uint64_t offset)
{
bfd_byte *ranges_ptr;
bfd_byte *ranges_end;
bfd_vma base_address = unit->base_address;
- if (! unit->stash->dwarf_ranges_buffer)
+ if (! unit->file->dwarf_ranges_buffer)
{
if (! read_debug_ranges (unit))
return FALSE;
}
- ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
- if (ranges_ptr < unit->stash->dwarf_ranges_buffer)
+ ranges_ptr = unit->file->dwarf_ranges_buffer + offset;
+ if (ranges_ptr < unit->file->dwarf_ranges_buffer)
return FALSE;
- ranges_end = unit->stash->dwarf_ranges_buffer + unit->stash->dwarf_ranges_size;
+ ranges_end = unit->file->dwarf_ranges_buffer + unit->file->dwarf_ranges_size;
for (;;)
{
return TRUE;
}
+static bfd_boolean
+read_rnglists (struct comp_unit *unit, struct arange *arange,
+ bfd_uint64_t offset)
+{
+ bfd_byte *rngs_ptr;
+ bfd_byte *rngs_end;
+ bfd_vma base_address = unit->base_address;
+ bfd_vma low_pc;
+ bfd_vma high_pc;
+ bfd *abfd = unit->abfd;
+
+ if (! unit->file->dwarf_rnglists_buffer)
+ {
+ if (! read_debug_rnglists (unit))
+ return FALSE;
+ }
+
+ rngs_ptr = unit->file->dwarf_rnglists_buffer + offset;
+ if (rngs_ptr < unit->file->dwarf_rnglists_buffer)
+ return FALSE;
+ rngs_end = unit->file->dwarf_rnglists_buffer;
+ rngs_end += unit->file->dwarf_rnglists_size;
+
+ for (;;)
+ {
+ enum dwarf_range_list_entry rlet;
+ unsigned int bytes_read;
+
+ if (rngs_ptr + 1 > rngs_end)
+ return FALSE;
+
+ rlet = read_1_byte (abfd, rngs_ptr, rngs_end);
+ rngs_ptr++;
+
+ switch (rlet)
+ {
+ case DW_RLE_end_of_list:
+ return TRUE;
+
+ case DW_RLE_base_address:
+ if (rngs_ptr + unit->addr_size > rngs_end)
+ return FALSE;
+ base_address = read_address (unit, rngs_ptr, rngs_end);
+ rngs_ptr += unit->addr_size;
+ continue;
+
+ case DW_RLE_start_length:
+ if (rngs_ptr + unit->addr_size > rngs_end)
+ return FALSE;
+ low_pc = read_address (unit, rngs_ptr, rngs_end);
+ rngs_ptr += unit->addr_size;
+ high_pc = low_pc;
+ high_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+ FALSE, rngs_end);
+ rngs_ptr += bytes_read;
+ break;
+
+ case DW_RLE_offset_pair:
+ low_pc = base_address;
+ low_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+ FALSE, rngs_end);
+ rngs_ptr += bytes_read;
+ high_pc = base_address;
+ high_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+ FALSE, rngs_end);
+ rngs_ptr += bytes_read;
+ break;
+
+ case DW_RLE_start_end:
+ if (rngs_ptr + 2 * unit->addr_size > rngs_end)
+ return FALSE;
+ low_pc = read_address (unit, rngs_ptr, rngs_end);
+ rngs_ptr += unit->addr_size;
+ high_pc = read_address (unit, rngs_ptr, rngs_end);
+ rngs_ptr += unit->addr_size;
+ break;
+
+ /* TODO x-variants need .debug_addr support used for split-dwarf. */
+ case DW_RLE_base_addressx:
+ case DW_RLE_startx_endx:
+ case DW_RLE_startx_length:
+ default:
+ return FALSE;
+ }
+
+ if (!arange_add (unit, arange, low_pc, high_pc))
+ return FALSE;
+ }
+}
+
+static bfd_boolean
+read_rangelist (struct comp_unit *unit, struct arange *arange,
+ bfd_uint64_t offset)
+{
+ if (unit->version <= 4)
+ return read_ranges (unit, arange, offset);
+ else
+ return read_rnglists (unit, arange, offset);
+}
+
+static struct funcinfo *
+lookup_func_by_offset (bfd_uint64_t offset, struct funcinfo * table)
+{
+ for (; table != NULL; table = table->prev_func)
+ if (table->unit_offset == offset)
+ return table;
+ return NULL;
+}
+
+static struct varinfo *
+lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table)
+{
+ while (table)
+ {
+ if (table->unit_offset == offset)
+ return table;
+ table = table->prev_var;
+ }
+
+ return NULL;
+}
+
+
/* DWARF2 Compilation unit functions. */
/* Scan over each die in a comp. unit looking for functions to add
bfd_byte *info_ptr = unit->first_child_die_ptr;
bfd_byte *info_ptr_end = unit->end_ptr;
int nesting_level = 0;
- struct nest_funcinfo {
+ struct nest_funcinfo
+ {
struct funcinfo *func;
} *nested_funcs;
int nested_funcs_size;
return FALSE;
nested_funcs[nesting_level].func = 0;
+ /* PR 27484: We must scan the DIEs twice. The first time we look for
+ function and variable tags and accumulate them into their respective
+ tables. The second time through we process the attributes of the
+ functions/variables and augment the table entries. */
while (nesting_level >= 0)
{
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
- struct attribute attr;
struct funcinfo *func;
struct varinfo *var;
- bfd_vma low_pc = 0;
- bfd_vma high_pc = 0;
- bfd_boolean high_pc_relative = FALSE;
+ bfd_uint64_t current_offset;
/* PR 17512: file: 9f405d9d. */
if (info_ptr >= info_ptr_end)
goto fail;
+ current_offset = info_ptr - unit->info_ptr_unit;
abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
FALSE, info_ptr_end);
info_ptr += bytes_read;
- if (! abbrev_number)
+ if (abbrev_number == 0)
{
nesting_level--;
continue;
goto fail;
}
- var = NULL;
if (abbrev->tag == DW_TAG_subprogram
|| abbrev->tag == DW_TAG_entry_point
|| abbrev->tag == DW_TAG_inlined_subroutine)
{
- bfd_size_type amt = sizeof (struct funcinfo);
+ size_t amt = sizeof (struct funcinfo);
+
+ var = NULL;
func = (struct funcinfo *) bfd_zalloc (abfd, amt);
if (func == NULL)
goto fail;
func->tag = abbrev->tag;
func->prev_func = unit->function_table;
+ func->unit_offset = current_offset;
unit->function_table = func;
unit->number_of_functions++;
BFD_ASSERT (!unit->cached);
else
{
func = NULL;
- if (abbrev->tag == DW_TAG_variable)
+ if (abbrev->tag == DW_TAG_variable
+ || abbrev->tag == DW_TAG_member)
{
- bfd_size_type amt = sizeof (struct varinfo);
+ size_t amt = sizeof (struct varinfo);
+
var = (struct varinfo *) bfd_zalloc (abfd, amt);
if (var == NULL)
goto fail;
var->tag = abbrev->tag;
- var->stack = 1;
+ var->stack = TRUE;
var->prev_var = unit->variable_table;
unit->variable_table = var;
+ var->unit_offset = current_offset;
/* PR 18205: Missing debug information can cause this
var to be attached to an already cached unit. */
}
+ else
+ var = NULL;
/* No inline function in scope at this nesting level. */
nested_funcs[nesting_level].func = 0;
}
+ for (i = 0; i < abbrev->num_attrs; ++i)
+ {
+ struct attribute attr;
+
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i],
+ unit, info_ptr, info_ptr_end);
+ if (info_ptr == NULL)
+ goto fail;
+ }
+
+ if (abbrev->has_children)
+ {
+ nesting_level++;
+
+ if (nesting_level >= nested_funcs_size)
+ {
+ struct nest_funcinfo *tmp;
+
+ nested_funcs_size *= 2;
+ tmp = (struct nest_funcinfo *)
+ bfd_realloc (nested_funcs,
+ nested_funcs_size * sizeof (*nested_funcs));
+ if (tmp == NULL)
+ goto fail;
+ nested_funcs = tmp;
+ }
+ nested_funcs[nesting_level].func = 0;
+ }
+ }
+
+ /* This is the second pass over the abbrevs. */
+ info_ptr = unit->first_child_die_ptr;
+ nesting_level = 0;
+
+ while (nesting_level >= 0)
+ {
+ unsigned int abbrev_number, bytes_read, i;
+ struct abbrev_info *abbrev;
+ struct attribute attr;
+ struct funcinfo *func;
+ struct varinfo *var;
+ bfd_vma low_pc = 0;
+ bfd_vma high_pc = 0;
+ bfd_boolean high_pc_relative = FALSE;
+ bfd_uint64_t current_offset;
+
+ /* PR 17512: file: 9f405d9d. */
+ if (info_ptr >= info_ptr_end)
+ goto fail;
+
+ current_offset = info_ptr - unit->info_ptr_unit;
+ abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
+ FALSE, info_ptr_end);
+ info_ptr += bytes_read;
+
+ if (! abbrev_number)
+ {
+ nesting_level--;
+ continue;
+ }
+
+ abbrev = lookup_abbrev (abbrev_number, unit->abbrevs);
+ /* This should have been handled above. */
+ BFD_ASSERT (abbrev != NULL);
+
+ func = NULL;
+ var = NULL;
+ if (abbrev->tag == DW_TAG_subprogram
+ || abbrev->tag == DW_TAG_entry_point
+ || abbrev->tag == DW_TAG_inlined_subroutine)
+ {
+ func = lookup_func_by_offset (current_offset, unit->function_table);
+ if (func == NULL)
+ goto fail;
+ }
+ else if (abbrev->tag == DW_TAG_variable
+ || abbrev->tag == DW_TAG_member)
+ {
+ var = lookup_var_by_offset (current_offset, unit->variable_table);
+ if (var == NULL)
+ goto fail;
+ }
+
for (i = 0; i < abbrev->num_attrs; ++i)
{
info_ptr = read_attribute (&attr, &abbrev->attrs[i],
{
switch (attr.name)
{
+ case DW_AT_specification:
+ if (attr.u.val)
+ {
+ struct varinfo * spec_var;
+
+ spec_var = lookup_var_by_offset (attr.u.val,
+ unit->variable_table);
+ if (spec_var == NULL)
+ {
+ _bfd_error_handler (_("DWARF error: could not find "
+ "variable specification "
+ "at offset 0x%lx"),
+ (unsigned long) attr.u.val);
+ break;
+ }
+
+ if (var->name == NULL)
+ var->name = spec_var->name;
+ if (var->file == NULL && spec_var->file != NULL)
+ var->file = strdup (spec_var->file);
+ if (var->line == 0)
+ var->line = spec_var->line;
+ if (var->sec == NULL)
+ var->sec = spec_var->sec;
+ }
+ break;
+
case DW_AT_name:
if (is_str_attr (attr.form))
var->name = attr.u.str;
case DW_AT_external:
if (attr.u.val != 0)
- var->stack = 0;
+ var->stack = FALSE;
break;
case DW_AT_location:
if (attr.u.blk->data != NULL
&& *attr.u.blk->data == DW_OP_addr)
{
- var->stack = 0;
+ var->stack = FALSE;
/* Verify that DW_OP_addr is the only opcode in the
location, in which case the block size will be 1
}
}
+ if (abbrev->has_children)
+ nesting_level++;
+
if (high_pc_relative)
high_pc += low_pc;
if (!arange_add (unit, &func->arange, low_pc, high_pc))
goto fail;
}
-
- if (abbrev->has_children)
- {
- nesting_level++;
-
- if (nesting_level >= nested_funcs_size)
- {
- struct nest_funcinfo *tmp;
-
- nested_funcs_size *= 2;
- tmp = (struct nest_funcinfo *)
- bfd_realloc (nested_funcs,
- nested_funcs_size * sizeof (*nested_funcs));
- if (tmp == NULL)
- goto fail;
- nested_funcs = tmp;
- }
- nested_funcs[nesting_level].func = 0;
- }
}
free (nested_funcs);
static struct comp_unit *
parse_comp_unit (struct dwarf2_debug *stash,
+ struct dwarf2_debug_file *file,
+ bfd_byte *info_ptr,
bfd_vma unit_length,
bfd_byte *info_ptr_unit,
unsigned int offset_size)
unsigned int abbrev_number, bytes_read, i;
struct abbrev_info *abbrev;
struct attribute attr;
- bfd_byte *info_ptr = stash->info_ptr;
bfd_byte *end_ptr = info_ptr + unit_length;
- bfd_size_type amt;
+ size_t amt;
bfd_vma low_pc = 0;
bfd_vma high_pc = 0;
- bfd *abfd = stash->bfd_ptr;
+ bfd *abfd = file->bfd_ptr;
bfd_boolean high_pc_relative = FALSE;
enum dwarf_unit_type unit_type;
}
/* Read the abbrevs for this compilation unit into a table. */
- abbrevs = read_abbrevs (abfd, abbrev_offset, stash);
+ abbrevs = read_abbrevs (abfd, abbrev_offset, stash, file);
if (! abbrevs)
return NULL;
unit->abbrevs = abbrevs;
unit->end_ptr = end_ptr;
unit->stash = stash;
+ unit->file = file;
unit->info_ptr_unit = info_ptr_unit;
for (i = 0; i < abbrev->num_attrs; ++i)
const char **filename_ptr,
struct funcinfo **function_ptr,
unsigned int *linenumber_ptr,
- unsigned int *discriminator_ptr,
- struct dwarf2_debug *stash)
+ unsigned int *discriminator_ptr)
{
bfd_boolean func_p;
- if (!comp_unit_maybe_decode_line_info (unit, stash))
+ if (!comp_unit_maybe_decode_line_info (unit))
return FALSE;
*function_ptr = NULL;
func_p = lookup_address_in_function_table (unit, addr, function_ptr);
if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine)
- stash->inliner_chain = *function_ptr;
+ unit->stash->inliner_chain = *function_ptr;
return lookup_address_in_line_info_table (unit->line_table, addr,
filename_ptr,
FALSE otherwise. */
static bfd_boolean
-comp_unit_maybe_decode_line_info (struct comp_unit *unit,
- struct dwarf2_debug *stash)
+comp_unit_maybe_decode_line_info (struct comp_unit *unit)
{
if (unit->error)
return FALSE;
return FALSE;
}
- unit->line_table = decode_line_info (unit, stash);
+ unit->line_table = decode_line_info (unit);
if (! unit->line_table)
{
asymbol *sym,
bfd_vma addr,
const char **filename_ptr,
- unsigned int *linenumber_ptr,
- struct dwarf2_debug *stash)
+ unsigned int *linenumber_ptr)
{
- if (!comp_unit_maybe_decode_line_info (unit, stash))
+ if (!comp_unit_maybe_decode_line_info (unit))
return FALSE;
if (sym->flags & BSF_FUNCTION)
BFD_ASSERT (stash->info_hash_status != STASH_INFO_HASH_DISABLED);
- if (!comp_unit_maybe_decode_line_info (unit, stash))
+ if (!comp_unit_maybe_decode_line_info (unit))
return FALSE;
BFD_ASSERT (!unit->cached);
each_var = each_var->prev_var)
{
/* Skip stack vars and vars with no files or names. */
- if (each_var->stack == 0
+ if (! each_var->stack
&& each_var->file != NULL
&& each_var->name != NULL)
/* There is no need to copy name string into hash table as
}
for (msec = abfd->sections; msec != NULL; msec = msec->next)
- if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
+ if (startswith (msec->name, GNU_LINKONCE_INFO))
return msec;
return NULL;
if (look != NULL && strcmp (msec->name, look) == 0)
return msec;
- if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
+ if (startswith (msec->name, GNU_LINKONCE_INFO))
return msec;
}
_bfd_dwarf2_stash_syms (struct dwarf2_debug *stash, bfd *abfd,
asection **sec, asymbol ***syms)
{
- if (stash->bfd_ptr != abfd)
+ if (stash->f.bfd_ptr != abfd)
{
asection *s, *d;
if (*sec == NULL)
{
- *syms = stash->syms;
+ *syms = stash->f.syms;
return;
}
- for (s = abfd->sections, d = stash->bfd_ptr->sections;
+ for (s = abfd->sections, d = stash->f.bfd_ptr->sections;
s != NULL && d != NULL;
s = s->next, d = d->next)
{
&& strcmp (s->name, d->name) == 0)
{
*sec = d;
- *syms = stash->syms;
+ *syms = stash->f.syms;
break;
}
}
continue;
is_debug_info = (strcmp (sect->name, debug_info_name) == 0
- || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO));
+ || startswith (sect->name, GNU_LINKONCE_INFO));
if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd)
&& !is_debug_info)
i++;
}
- if (abfd == stash->bfd_ptr)
+ if (abfd == stash->f.bfd_ptr)
break;
- abfd = stash->bfd_ptr;
+ abfd = stash->f.bfd_ptr;
}
if (i <= 1)
else
{
bfd_vma last_vma = 0, last_dwarf = 0;
- bfd_size_type amt = i * sizeof (struct adjusted_section);
+ size_t amt = i * sizeof (struct adjusted_section);
p = (struct adjusted_section *) bfd_malloc (amt);
if (p == NULL)
continue;
is_debug_info = (strcmp (sect->name, debug_info_name) == 0
- || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO));
+ || startswith (sect->name, GNU_LINKONCE_INFO));
if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd)
&& !is_debug_info)
p->adj_vma = sect->vma;
p++;
}
- if (abfd == stash->bfd_ptr)
+ if (abfd == stash->f.bfd_ptr)
break;
- abfd = stash->bfd_ptr;
+ abfd = stash->f.bfd_ptr;
}
}
- if (orig_bfd != stash->bfd_ptr)
- set_debug_vma (orig_bfd, stash->bfd_ptr);
+ if (orig_bfd != stash->f.bfd_ptr)
+ set_debug_vma (orig_bfd, stash->f.bfd_ptr);
return TRUE;
}
struct comp_unit *each;
/* Exit if hash tables are up-to-date. */
- if (stash->all_comp_units == stash->hash_units_head)
+ if (stash->f.all_comp_units == stash->hash_units_head)
return TRUE;
if (stash->hash_units_head)
each = stash->hash_units_head->prev_unit;
else
- each = stash->last_comp_unit;
+ each = stash->f.last_comp_unit;
while (each)
{
each = each->prev_unit;
}
- stash->hash_units_head = stash->all_comp_units;
+ stash->hash_units_head = stash->f.all_comp_units;
return TRUE;
}
struct info_list_node *node;
bfd_boolean found;
- for (each_unit = stash->all_comp_units;
+ for (each_unit = stash->f.all_comp_units;
each_unit;
each_unit = each_unit->next_unit)
{
void **pinfo,
bfd_boolean do_place)
{
- bfd_size_type amt = sizeof (struct dwarf2_debug);
+ size_t amt = sizeof (struct dwarf2_debug);
bfd_size_type total_size;
asection *msec;
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
{
/* Check that we did previously find some debug information
before attempting to make use of it. */
- if (stash->bfd_ptr != NULL)
+ if (stash->f.bfd_ptr != NULL)
{
if (do_place && !place_sections (abfd, stash))
return FALSE;
}
stash->orig_bfd = abfd;
stash->debug_sections = debug_sections;
- stash->syms = symbols;
+ stash->f.syms = symbols;
if (!save_section_vma (abfd, stash))
return FALSE;
+ stash->f.abbrev_offsets = htab_create_alloc (10, hash_abbrev, eq_abbrev,
+ del_abbrev, calloc, free);
+ if (!stash->f.abbrev_offsets)
+ return FALSE;
+
+ stash->alt.abbrev_offsets = htab_create_alloc (10, hash_abbrev, eq_abbrev,
+ del_abbrev, calloc, free);
+ if (!stash->alt.abbrev_offsets)
+ return FALSE;
+
*pinfo = stash;
if (debug_bfd == NULL)
}
symbols = bfd_get_outsymbols (debug_bfd);
- stash->syms = symbols;
+ stash->f.syms = symbols;
stash->close_on_cleanup = TRUE;
}
- stash->bfd_ptr = debug_bfd;
+ stash->f.bfd_ptr = debug_bfd;
if (do_place
&& !place_sections (abfd, stash))
total_size = msec->size;
if (! read_section (debug_bfd, &stash->debug_sections[debug_info],
symbols, 0,
- &stash->info_ptr_memory, &total_size))
+ &stash->f.dwarf_info_buffer, &total_size))
return FALSE;
}
else
total_size += msec->size;
}
- stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size);
- if (stash->info_ptr_memory == NULL)
+ stash->f.dwarf_info_buffer = (bfd_byte *) bfd_malloc (total_size);
+ if (stash->f.dwarf_info_buffer == NULL)
return FALSE;
total_size = 0;
continue;
if (!(bfd_simple_get_relocated_section_contents
- (debug_bfd, msec, stash->info_ptr_memory + total_size,
+ (debug_bfd, msec, stash->f.dwarf_info_buffer + total_size,
symbols)))
return FALSE;
}
}
- stash->info_ptr = stash->info_ptr_memory;
- stash->info_ptr_end = stash->info_ptr + total_size;
+ stash->f.info_ptr = stash->f.dwarf_info_buffer;
+ stash->f.dwarf_info_size = total_size;
return TRUE;
}
-/* Parse the next DWARF2 compilation unit at STASH->INFO_PTR. */
+/* Parse the next DWARF2 compilation unit at FILE->INFO_PTR. */
static struct comp_unit *
-stash_comp_unit (struct dwarf2_debug *stash)
+stash_comp_unit (struct dwarf2_debug *stash, struct dwarf2_debug_file *file)
{
bfd_size_type length;
unsigned int offset_size;
- bfd_byte *info_ptr_unit = stash->info_ptr;
+ bfd_byte *info_ptr_unit = file->info_ptr;
+ bfd_byte *info_ptr_end = file->dwarf_info_buffer + file->dwarf_info_size;
- if (stash->info_ptr >= stash->info_ptr_end)
+ if (file->info_ptr >= info_ptr_end)
return NULL;
- length = read_4_bytes (stash->bfd_ptr, stash->info_ptr,
- stash->info_ptr_end);
+ length = read_4_bytes (file->bfd_ptr, file->info_ptr, info_ptr_end);
/* A 0xffffff length is the DWARF3 way of indicating
we use 64-bit offsets, instead of 32-bit offsets. */
if (length == 0xffffffff)
{
offset_size = 8;
- length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4,
- stash->info_ptr_end);
- stash->info_ptr += 12;
+ length = read_8_bytes (file->bfd_ptr, file->info_ptr + 4,
+ info_ptr_end);
+ file->info_ptr += 12;
}
/* A zero length is the IRIX way of indicating 64-bit offsets,
mostly because the 64-bit length will generally fit in 32
else if (length == 0)
{
offset_size = 8;
- length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4,
- stash->info_ptr_end);
- stash->info_ptr += 8;
+ length = read_4_bytes (file->bfd_ptr, file->info_ptr + 4,
+ info_ptr_end);
+ file->info_ptr += 8;
}
/* In the absence of the hints above, we assume 32-bit DWARF2
offsets even for targets with 64-bit addresses, because:
else
{
offset_size = 4;
- stash->info_ptr += 4;
+ file->info_ptr += 4;
}
if (length != 0
- && stash->info_ptr + length <= stash->info_ptr_end
- && stash->info_ptr + length > stash->info_ptr)
+ && file->info_ptr + length <= info_ptr_end
+ && file->info_ptr + length > file->info_ptr)
{
- struct comp_unit *each = parse_comp_unit (stash, length, info_ptr_unit,
- offset_size);
+ struct comp_unit *each = parse_comp_unit (stash, file,
+ file->info_ptr, length,
+ info_ptr_unit, offset_size);
if (each)
{
- if (stash->all_comp_units)
- stash->all_comp_units->prev_unit = each;
+ if (file->all_comp_units)
+ file->all_comp_units->prev_unit = each;
else
- stash->last_comp_unit = each;
+ file->last_comp_unit = each;
- each->next_unit = stash->all_comp_units;
- stash->all_comp_units = each;
+ each->next_unit = file->all_comp_units;
+ file->all_comp_units = each;
- stash->info_ptr += length;
+ file->info_ptr += length;
return each;
}
}
/* Don't trust any of the DWARF info after a corrupted length or
parse error. */
- stash->info_ptr = stash->info_ptr_end;
+ file->info_ptr = info_ptr_end;
return NULL;
}
}
}
- for (unit = stash->all_comp_units; unit; unit = unit->next_unit)
+ for (unit = stash->f.all_comp_units; unit; unit = unit->next_unit)
{
struct funcinfo * func;
- comp_unit_maybe_decode_line_info (unit, stash);
+ comp_unit_maybe_decode_line_info (unit);
for (func = unit->function_table; func != NULL; func = func->prev_func)
if (func->name && func->arange.low)
/* 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)
+ if (! stash->f.info_ptr)
return FALSE;
stash->inliner_chain = NULL;
else
{
/* Check the previously read comp. units first. */
- for (each = stash->all_comp_units; each; each = each->next_unit)
+ for (each = stash->f.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,
- linenumber_ptr, stash);
+ linenumber_ptr);
if (found)
goto done;
}
unsigned int local_linenumber = 0;
unsigned int local_discriminator = 0;
- for (each = stash->all_comp_units; each; each = each->next_unit)
+ for (each = stash->f.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))
- && (range = comp_unit_find_nearest_line (each, addr,
- & local_filename,
- & local_function,
- & local_linenumber,
- & local_discriminator,
- stash)) != 0);
+ && (range = (comp_unit_find_nearest_line
+ (each, addr, &local_filename,
+ &local_function, &local_linenumber,
+ &local_discriminator))) != 0);
if (found)
{
/* PRs 15935 15994: Bogus debug information may have provided us
}
/* Read each remaining comp. units checking each as they are read. */
- while ((each = stash_comp_unit (stash)) != NULL)
+ while ((each = stash_comp_unit (stash, &stash->f)) != NULL)
{
/* DW_AT_low_pc and DW_AT_high_pc are optional for
compilation units. If we don't have them (i.e.,
|| each->arange.high == 0
|| comp_unit_contains_address (each, addr))
&& comp_unit_find_line (each, symbol, addr,
- filename_ptr,
- linenumber_ptr,
- stash));
+ filename_ptr, linenumber_ptr));
else
found = ((each->arange.high == 0
|| comp_unit_contains_address (each, addr))
filename_ptr,
&function,
linenumber_ptr,
- discriminator_ptr,
- stash) != 0);
+ discriminator_ptr) != 0);
if (found)
break;
{
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
struct comp_unit *each;
+ struct dwarf2_debug_file *file;
if (abfd == NULL || stash == NULL)
return;
- for (each = stash->all_comp_units; each; each = each->next_unit)
- {
- struct abbrev_info **abbrevs = each->abbrevs;
- struct funcinfo *function_table = each->function_table;
- struct varinfo *variable_table = each->variable_table;
- size_t i;
+ if (stash->varinfo_hash_table)
+ bfd_hash_table_free (&stash->varinfo_hash_table->base);
+ if (stash->funcinfo_hash_table)
+ bfd_hash_table_free (&stash->funcinfo_hash_table->base);
- for (i = 0; i < ABBREV_HASH_SIZE; i++)
+ file = &stash->f;
+ while (1)
+ {
+ for (each = file->all_comp_units; each; each = each->next_unit)
{
- struct abbrev_info *abbrev = abbrevs[i];
+ struct funcinfo *function_table = each->function_table;
+ struct varinfo *variable_table = each->variable_table;
- while (abbrev)
+ if (each->line_table && each->line_table != file->line_table)
{
- free (abbrev->attrs);
- abbrev = abbrev->next;
+ free (each->line_table->files);
+ free (each->line_table->dirs);
}
- }
- if (each->line_table)
- {
- free (each->line_table->dirs);
- free (each->line_table->files);
- }
+ free (each->lookup_funcinfo_table);
+ each->lookup_funcinfo_table = NULL;
- while (function_table)
- {
- if (function_table->file)
+ while (function_table)
{
free (function_table->file);
function_table->file = NULL;
- }
-
- if (function_table->caller_file)
- {
free (function_table->caller_file);
function_table->caller_file = NULL;
+ function_table = function_table->prev_func;
}
- function_table = function_table->prev_func;
- }
- if (each->lookup_funcinfo_table)
- {
- free (each->lookup_funcinfo_table);
- each->lookup_funcinfo_table = NULL;
- }
-
- while (variable_table)
- {
- if (variable_table->file)
+ while (variable_table)
{
free (variable_table->file);
variable_table->file = NULL;
+ variable_table = variable_table->prev_var;
}
+ }
- variable_table = variable_table->prev_var;
+ if (file->line_table)
+ {
+ free (file->line_table->files);
+ free (file->line_table->dirs);
}
+ htab_delete (file->abbrev_offsets);
+
+ free (file->dwarf_line_str_buffer);
+ free (file->dwarf_str_buffer);
+ free (file->dwarf_ranges_buffer);
+ free (file->dwarf_line_buffer);
+ free (file->dwarf_abbrev_buffer);
+ free (file->dwarf_info_buffer);
+ if (file == &stash->alt)
+ break;
+ file = &stash->alt;
}
-
- if (stash->funcinfo_hash_table)
- bfd_hash_table_free (&stash->funcinfo_hash_table->base);
- if (stash->varinfo_hash_table)
- bfd_hash_table_free (&stash->varinfo_hash_table->base);
- if (stash->dwarf_abbrev_buffer)
- free (stash->dwarf_abbrev_buffer);
- if (stash->dwarf_line_buffer)
- 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)
- free (stash->info_ptr_memory);
+ free (stash->sec_vma);
+ free (stash->adjusted_sections);
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->sec_vma)
- free (stash->sec_vma);
- if (stash->adjusted_sections)
- free (stash->adjusted_sections);
- if (stash->alt_bfd_ptr)
- bfd_close (stash->alt_bfd_ptr);
+ bfd_close (stash->f.bfd_ptr);
+ if (stash->alt.bfd_ptr)
+ bfd_close (stash->alt.bfd_ptr);
}
/* Find the function to a particular section and offset,