/* DWARF 2 support.
- Copyright (C) 1994-2019 Free Software Foundation, Inc.
+ Copyright (C) 1994-2022 Free Software Foundation, Inc.
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
(gavin@cygnus.com).
#include "libbfd.h"
#include "elf-bfd.h"
#include "dwarf2.h"
+#include "hashtab.h"
/* The data in the .debug_line statement prologue looks like this. */
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;
+ /* A pointer to the memory block allocated for .debug_info sections. */
+ bfd_byte *dwarf_info_buffer;
- /* 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, section and address of the beginning of the
- section. The bfd might be different than expected because of
- gnu_debuglink sections. */
- bfd *bfd_ptr;
- 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. */
- bfd_byte *info_ptr_memory;
-
- /* 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
#define STASH_INFO_HASH_DISABLED 2
/* True if we opened bfd_ptr. */
- bfd_boolean close_on_cleanup;
+ bool close_on_cleanup;
};
struct arange
/* 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;
bfd_vma base_address;
/* TRUE if symbols are cached in hash table for faster lookup by name. */
- bfd_boolean cached;
+ bool cached;
};
/* 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. */
+ bool 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,
right type of info in inserted as info is passed as a void* pointer.
This function returns true if there is no error. */
-static bfd_boolean
+static bool
insert_info_hash_table (struct info_hash_table *hash_table,
const char *key,
void *info,
- bfd_boolean copy_p)
+ bool copy_p)
{
struct info_hash_entry *entry;
struct info_list_node *node;
entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base,
- key, TRUE, copy_p);
+ key, true, copy_p);
if (!entry)
- return FALSE;
+ return false;
node = (struct info_list_node *) bfd_hash_allocate (&hash_table->base,
sizeof (*node));
if (!node)
- return FALSE;
+ return false;
node->info = info;
node->next = entry->head;
entry->head = node;
- return TRUE;
+ return true;
}
/* Look up an info entry list from an info hash table. Return NULL
struct info_hash_entry *entry;
entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, key,
- FALSE, FALSE);
+ false, false);
return entry ? entry->head : NULL;
}
section contents, otherwise use bfd_get_section_contents. Fail if
the located section does not contain at least OFFSET bytes. */
-static bfd_boolean
+static bool
read_section (bfd * abfd,
const struct dwarf_debug_section *sec,
asymbol ** syms,
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);
+ 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);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
- *section_size = msec->rawsize ? msec->rawsize : msec->size;
+ amt = bfd_get_section_limit_octets (abfd, msec);
+ filesize = bfd_get_file_size (abfd);
+ /* PR 28834: A compressed debug section could well decompress to a size
+ larger than the file, so we choose an arbitrary modifier of 10x in
+ the test below. If this ever turns out to be insufficient, it can
+ be changed by a future update. */
+ if (amt >= filesize * 10)
+ {
+ /* PR 26946 */
+ _bfd_error_handler (_("DWARF error: section %s is larger than 10x 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;
+ return false;
}
contents = (bfd_byte *) bfd_malloc (amt);
if (contents == NULL)
- return FALSE;
+ return false;
if (syms
? !bfd_simple_get_relocated_section_contents (abfd, msec, contents,
syms)
: !bfd_get_section_contents (abfd, msec, contents, 0, *section_size))
{
free (contents);
- return FALSE;
+ return false;
}
contents[*section_size] = 0;
*section_buffer = contents;
(uint64_t) offset, section_name,
(uint64_t) *section_size);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* Read dwarf information from a buffer. */
+static inline uint64_t
+read_n_bytes (bfd *abfd, bfd_byte **ptr, bfd_byte *end, int n)
+{
+ bfd_byte *buf = *ptr;
+ if (end - buf < n)
+ {
+ *ptr = end;
+ return 0;
+ }
+ *ptr = buf + n;
+ return bfd_get (n * 8, abfd, buf);
+}
+
static unsigned int
-read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end)
+read_1_byte (bfd *abfd, bfd_byte **ptr, bfd_byte *end)
{
- if (buf + 1 > end)
- return 0;
- return bfd_get_8 (abfd, buf);
+ return read_n_bytes (abfd, ptr, end, 1);
}
static int
-read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end)
+read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte **ptr, bfd_byte *end)
{
- if (buf + 1 > end)
- return 0;
+ bfd_byte *buf = *ptr;
+ if (end - buf < 1)
+ {
+ *ptr = end;
+ return 0;
+ }
+ *ptr = buf + 1;
return bfd_get_signed_8 (abfd, buf);
}
static unsigned int
-read_2_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
+read_2_bytes (bfd *abfd, bfd_byte **ptr, bfd_byte *end)
{
- if (buf + 2 > end)
- return 0;
- return bfd_get_16 (abfd, buf);
+ return read_n_bytes (abfd, ptr, end, 2);
}
static unsigned int
-read_4_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
+read_3_bytes (bfd *abfd, bfd_byte **ptr, bfd_byte *end)
{
- if (buf + 4 > end)
- return 0;
- return bfd_get_32 (abfd, buf);
+ unsigned int val = read_1_byte (abfd, ptr, end);
+ val <<= 8;
+ val |= read_1_byte (abfd, ptr, end);
+ val <<= 8;
+ val |= read_1_byte (abfd, ptr, end);
+ if (bfd_little_endian (abfd))
+ val = (((val >> 16) & 0xff)
+ | (val & 0xff00)
+ | ((val & 0xff) << 16));
+ return val;
}
-static bfd_uint64_t
-read_8_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
+static unsigned int
+read_4_bytes (bfd *abfd, bfd_byte **ptr, bfd_byte *end)
{
- if (buf + 8 > end)
- return 0;
- return bfd_get_64 (abfd, buf);
+ return read_n_bytes (abfd, ptr, end, 4);
}
-static bfd_byte *
-read_n_bytes (bfd_byte * buf,
- bfd_byte * end,
- struct dwarf_block * block)
+static uint64_t
+read_8_bytes (bfd *abfd, bfd_byte **ptr, bfd_byte *end)
{
- unsigned int size = block->size;
- bfd_byte * block_end = buf + size;
+ return read_n_bytes (abfd, ptr, end, 8);
+}
+
+static struct dwarf_block *
+read_blk (bfd *abfd, bfd_byte **ptr, bfd_byte *end, size_t size)
+{
+ bfd_byte *buf = *ptr;
+ struct dwarf_block *block;
+
+ block = (struct dwarf_block *) bfd_alloc (abfd, sizeof (*block));
+ if (block == NULL)
+ return NULL;
- if (block_end > end || block_end < buf)
+ if (size > (size_t) (end - buf))
{
+ *ptr = end;
block->data = NULL;
block->size = 0;
- return end;
}
else
{
+ *ptr = buf + size;
block->data = buf;
- return block_end;
+ block->size = size;
}
+ return block;
}
-/* Scans a NUL terminated string starting at BUF, returning a pointer to it.
- Returns the number of characters in the string, *including* the NUL byte,
- in BYTES_READ_PTR. This value is set even if the function fails. Bytes
- at or beyond BUF_END will not be read. Returns NULL if there was a
- problem, or if the string is empty. */
+/* Scans a NUL terminated string starting at *PTR, returning a pointer to it.
+ Bytes at or beyond BUF_END will not be read. Returns NULL if the
+ terminator is not found or if the string is empty. *PTR is
+ incremented over the bytes scanned, including the terminator. */
static char *
-read_string (bfd * abfd ATTRIBUTE_UNUSED,
- bfd_byte * buf,
- bfd_byte * buf_end,
- unsigned int * bytes_read_ptr)
+read_string (bfd_byte **ptr,
+ bfd_byte *buf_end)
{
+ bfd_byte *buf = *ptr;
bfd_byte *str = buf;
- if (buf >= buf_end)
- {
- * bytes_read_ptr = 0;
- return NULL;
- }
-
- if (*str == '\0')
- {
- * bytes_read_ptr = 1;
- return NULL;
- }
-
while (buf < buf_end)
- if (* buf ++ == 0)
+ if (*buf++ == 0)
{
- * bytes_read_ptr = buf - str;
+ if (str == buf - 1)
+ break;
+ *ptr = buf;
return (char *) str;
}
- * bytes_read_ptr = buf - str;
+ *ptr = buf;
return NULL;
}
-/* Reads an offset from BUF and then locates the string at this offset
+/* Reads an offset from *PTR and then locates the string at this offset
inside the debug string section. Returns a pointer to the string.
- Returns the number of bytes read from BUF, *not* the length of the string,
- in BYTES_READ_PTR. This value is set even if the function fails. Bytes
- at or beyond BUF_END will not be read from BUF. Returns NULL if there was
- a problem, or if the string is empty. Does not check for NUL termination
- of the string. */
+ Increments *PTR by the number of bytes read for the offset. This
+ value is set even if the function fails. Bytes at or beyond
+ BUF_END will not be read. Returns NULL if there was a problem, or
+ if the string is empty. Does not check for NUL termination of the
+ string. */
static char *
-read_indirect_string (struct comp_unit * unit,
- bfd_byte * buf,
- bfd_byte * buf_end,
- unsigned int * bytes_read_ptr)
+read_indirect_string (struct comp_unit *unit,
+ bfd_byte **ptr,
+ bfd_byte *buf_end)
{
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)
+ if (unit->offset_size > (size_t) (buf_end - *ptr))
{
- * bytes_read_ptr = 0;
+ *ptr = buf_end;
return NULL;
}
if (unit->offset_size == 4)
- offset = read_4_bytes (unit->abfd, buf, buf_end);
+ offset = read_4_bytes (unit->abfd, ptr, buf_end);
else
- offset = read_8_bytes (unit->abfd, buf, buf_end);
-
- *bytes_read_ptr = unit->offset_size;
+ offset = read_8_bytes (unit->abfd, ptr, buf_end);
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;
- if (offset >= stash->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;
/* 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)
+read_indirect_line_string (struct comp_unit *unit,
+ bfd_byte **ptr,
+ bfd_byte *buf_end)
{
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)
+ if (unit->offset_size > (size_t) (buf_end - *ptr))
{
- * bytes_read_ptr = 0;
+ *ptr = buf_end;
return NULL;
}
if (unit->offset_size == 4)
- offset = read_4_bytes (unit->abfd, buf, buf_end);
+ offset = read_4_bytes (unit->abfd, ptr, buf_end);
else
- offset = read_8_bytes (unit->abfd, buf, buf_end);
-
- *bytes_read_ptr = unit->offset_size;
+ offset = read_8_bytes (unit->abfd, ptr, buf_end);
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;
- if (offset >= stash->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;
Used to impement DW_FORM_GNU_strp_alt. */
static char *
-read_alt_indirect_string (struct comp_unit * unit,
- bfd_byte * buf,
- bfd_byte * buf_end,
- unsigned int * bytes_read_ptr)
+read_alt_indirect_string (struct comp_unit *unit,
+ bfd_byte **ptr,
+ bfd_byte *buf_end)
{
bfd_uint64_t offset;
struct dwarf2_debug *stash = unit->stash;
char *str;
- if (buf + unit->offset_size > buf_end)
+ if (unit->offset_size > (size_t) (buf_end - *ptr))
{
- * bytes_read_ptr = 0;
+ *ptr = buf_end;
return NULL;
}
if (unit->offset_size == 4)
- offset = read_4_bytes (unit->abfd, buf, buf_end);
+ offset = read_4_bytes (unit->abfd, ptr, buf_end);
else
- offset = read_8_bytes (unit->abfd, buf, buf_end);
-
- *bytes_read_ptr = unit->offset_size;
+ offset = read_8_bytes (unit->abfd, ptr, buf_end);
- 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 *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);
+ debug_bfd = bfd_openr (debug_filename, NULL);
+ free (debug_filename);
+ if (debug_bfd == NULL)
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ return NULL;
- /* FIXME: Should we report our failure to follow the debuglink ? */
- free (debug_filename);
+ if (!bfd_check_format (debug_bfd, bfd_object))
+ {
+ 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;
- if (offset >= 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 *debug_bfd;
+ char *debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
if (debug_filename == NULL)
- return FALSE;
+ 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);
+ debug_bfd = bfd_openr (debug_filename, NULL);
+ free (debug_filename);
+ if (debug_bfd == NULL)
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ return NULL;
- /* FIXME: Should we report our failure to follow the debuglink ? */
- free (debug_filename);
+ if (!bfd_check_format (debug_bfd, bfd_object))
+ {
+ 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;
- if (offset >= 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
-read_address (struct comp_unit *unit, bfd_byte *buf, bfd_byte * buf_end)
+read_address (struct comp_unit *unit, bfd_byte **ptr, bfd_byte *buf_end)
{
+ bfd_byte *buf = *ptr;
int signed_vma = 0;
if (bfd_get_flavour (unit->abfd) == bfd_target_elf_flavour)
signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma;
- if (buf + unit->addr_size > buf_end)
- return 0;
+ if (unit->addr_size > (size_t) (buf_end - buf))
+ {
+ *ptr = buf_end;
+ return 0;
+ }
+ *ptr = buf + unit->addr_size;
if (signed_vma)
{
switch (unit->addr_size)
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;
bfd_byte *abbrev_end;
struct abbrev_info *cur_abbrev;
- unsigned int abbrev_number, bytes_read, abbrev_name;
+ unsigned int abbrev_number, 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 (! read_section (abfd, &stash->debug_sections[debug_abbrev],
- stash->syms, offset,
- &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
+ if (ent.offset != offset)
return NULL;
- if (offset >= stash->dwarf_abbrev_size)
+ 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],
+ 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_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
+ 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,
+ false, abbrev_end);
/* Loop until we reach an abbrev number of 0. */
while (abbrev_number)
amt = sizeof (struct abbrev_info);
cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt);
if (cur_abbrev == NULL)
- return NULL;
+ goto fail;
/* Read in abbrev header. */
cur_abbrev->number = abbrev_number;
cur_abbrev->tag = (enum dwarf_tag)
- _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read,
- FALSE, abbrev_end);
- abbrev_ptr += bytes_read;
- cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr, abbrev_end);
- abbrev_ptr += 1;
+ _bfd_safe_read_leb128 (abfd, &abbrev_ptr,
+ false, abbrev_end);
+ cur_abbrev->has_children = read_1_byte (abfd, &abbrev_ptr, abbrev_end);
/* Now read in declarations. */
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;
+ abbrev_name = _bfd_safe_read_leb128 (abfd, &abbrev_ptr,
+ false, abbrev_end);
+ abbrev_form = _bfd_safe_read_leb128 (abfd, &abbrev_ptr,
+ false, abbrev_end);
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;
- }
-
+ implicit_const = _bfd_safe_read_leb128 (abfd, &abbrev_ptr,
+ true, abbrev_end);
if (abbrev_name == 0)
break;
amt *= sizeof (struct attr_abbrev);
tmp = (struct attr_abbrev *) bfd_realloc (cur_abbrev->attrs, amt);
if (tmp == NULL)
- {
- 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;
- }
- }
- return NULL;
- }
+ goto fail;
cur_abbrev->attrs = tmp;
}
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 ((unsigned int) (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);
- abbrev_ptr += bytes_read;
+ abbrev_number = _bfd_safe_read_leb128 (abfd, &abbrev_ptr,
+ 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:
+ if (abbrevs != NULL)
+ {
+ 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 (abbrevs);
+ }
+ return NULL;
}
/* Returns true if the form is one which has a string value. */
-static inline bfd_boolean
-is_str_attr (enum dwarf_form form)
+static bool
+is_str_form (const struct attribute *attr)
{
- return (form == DW_FORM_string || form == DW_FORM_strp
- || form == DW_FORM_line_strp || form == DW_FORM_GNU_strp_alt);
+ switch (attr->form)
+ {
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_line_strp:
+ case DW_FORM_GNU_strp_alt:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns true if the form is one which has an integer value. */
+
+static bool
+is_int_form (const struct attribute *attr)
+{
+ switch (attr->form)
+ {
+ case DW_FORM_addr:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_sec_offset:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_addrx:
+ case DW_FORM_implicit_const:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4:
+ case DW_FORM_GNU_ref_alt:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+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_byte * info_ptr_end)
{
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)
{
_bfd_error_handler (_("DWARF error: info pointer extends beyond end of attributes"));
bfd_set_error (bfd_error_bad_value);
- return info_ptr;
+ return NULL;
}
attr->form = (enum dwarf_form) form;
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);
+ attr->u.val = read_4_bytes (unit->abfd, &info_ptr, info_ptr_end);
else
- attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end);
- info_ptr += unit->offset_size;
+ attr->u.val = read_8_bytes (unit->abfd, &info_ptr, info_ptr_end);
break;
}
/* FALLTHROUGH */
case DW_FORM_addr:
- attr->u.val = read_address (unit, info_ptr, info_ptr_end);
- info_ptr += unit->addr_size;
+ attr->u.val = read_address (unit, &info_ptr, info_ptr_end);
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, info_ptr_end);
+ attr->u.val = read_4_bytes (unit->abfd, &info_ptr, info_ptr_end);
else
- attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end);
- info_ptr += unit->offset_size;
+ attr->u.val = read_8_bytes (unit->abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_block2:
- amt = sizeof (struct dwarf_block);
- blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
- if (blk == NULL)
+ amt = read_2_bytes (abfd, &info_ptr, info_ptr_end);
+ attr->u.blk = read_blk (abfd, &info_ptr, info_ptr_end, amt);
+ if (attr->u.blk == NULL)
return NULL;
- blk->size = read_2_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 2;
- info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk);
- attr->u.blk = blk;
break;
case DW_FORM_block4:
- amt = sizeof (struct dwarf_block);
- blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
- if (blk == NULL)
+ amt = read_4_bytes (abfd, &info_ptr, info_ptr_end);
+ attr->u.blk = read_blk (abfd, &info_ptr, info_ptr_end, amt);
+ if (attr->u.blk == NULL)
return NULL;
- blk->size = read_4_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 4;
- 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);
break;
case DW_FORM_data2:
- attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 2;
+ case DW_FORM_addrx2:
+ case DW_FORM_ref2:
+ attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
+ break;
+ case DW_FORM_addrx3:
+ attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
break;
+ case DW_FORM_ref4:
case DW_FORM_data4:
- attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 4;
+ case DW_FORM_addrx4:
+ attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_data8:
- attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
- info_ptr += 8;
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ attr->u.val = read_8_bytes (abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_string:
- attr->u.str = read_string (abfd, info_ptr, info_ptr_end, &bytes_read);
- info_ptr += bytes_read;
+ attr->u.str = read_string (&info_ptr, info_ptr_end);
break;
case DW_FORM_strp:
- attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
- info_ptr += bytes_read;
+ attr->u.str = read_indirect_string (unit, &info_ptr, info_ptr_end);
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;
+ attr->u.str = read_indirect_line_string (unit, &info_ptr, info_ptr_end);
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;
+ attr->u.str = read_alt_indirect_string (unit, &info_ptr, info_ptr_end);
+ break;
+ case DW_FORM_strx1:
+ attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
+ 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);
+ attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+ break;
+ case DW_FORM_strx3:
+ attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
+ 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);
+ 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,
+ false, info_ptr_end);
+ 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);
- blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
- if (blk == NULL)
+ amt = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, info_ptr_end);
+ attr->u.blk = read_blk (abfd, &info_ptr, info_ptr_end, amt);
+ if (attr->u.blk == NULL)
return NULL;
- blk->size = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
- info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk);
- attr->u.blk = blk;
break;
case DW_FORM_block1:
- amt = sizeof (struct dwarf_block);
- blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
- if (blk == NULL)
+ amt = read_1_byte (abfd, &info_ptr, info_ptr_end);
+ attr->u.blk = read_blk (abfd, &info_ptr, info_ptr_end, amt);
+ if (attr->u.blk == NULL)
return NULL;
- blk->size = read_1_byte (abfd, info_ptr, info_ptr_end);
- info_ptr += 1;
- 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;
+ attr->u.sval = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ true, info_ptr_end);
break;
case DW_FORM_ref_udata:
- attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
+ case DW_FORM_udata:
+ case DW_FORM_addrx:
+ attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, info_ptr_end);
break;
case DW_FORM_indirect:
- form = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
+ form = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, 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;
- }
+ implicit_const = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ true, info_ptr_end);
info_ptr = read_attribute_value (attr, form, implicit_const, unit,
info_ptr, info_ptr_end);
break;
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. */
+ attr->u.blk = read_blk (abfd, &info_ptr, info_ptr_end, 16);
+ if (attr->u.blk == NULL)
+ return NULL;
+ break;
+
default:
_bfd_error_handler (_("DWARF error: invalid or unhandled FORM value: %#x"),
form);
/* Return whether DW_AT_name will return the same as DW_AT_linkage_name
for a function. */
-static bfd_boolean
+static bool
non_mangled (int lang)
{
switch (lang)
{
default:
- return FALSE;
+ return false;
case DW_LANG_C89:
case DW_LANG_C:
case DW_LANG_PLI:
case DW_LANG_UPC:
case DW_LANG_C11:
- return TRUE;
+ return true;
}
}
/* Source location line number. */
int line;
int tag;
- bfd_boolean is_linkage;
+ bool is_linkage;
const char * name;
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
The highest address of all prior functions after the lookup table is
sorted, which is used for binary search. */
bfd_vma high_addr;
+ /* Index of this function, used to ensure qsort is stable. */
+ unsigned int idx;
};
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? */
+ bool stack;
};
/* Return TRUE if NEW_LINE should sort after LINE. */
-static inline bfd_boolean
+static inline bool
new_line_sorts_after (struct line_info *new_line, struct line_info *line)
{
return (new_line->address > line->address
highest to lowest VMA (with possible duplicates); that is,
line_info->prev_line always accesses an equal or smaller VMA. */
-static bfd_boolean
+static bool
add_line_info (struct line_info_table *table,
bfd_vma address,
unsigned char op_index,
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);
if (info == NULL)
- return FALSE;
+ return false;
/* Set member data of 'info'. */
info->prev_line = NULL;
{
info->filename = (char *) bfd_alloc (table->abfd, strlen (filename) + 1);
if (info->filename == NULL)
- return FALSE;
+ return false;
strcpy (info->filename, filename);
}
else
amt = sizeof (struct line_sequence);
seq = (struct line_sequence *) bfd_malloc (amt);
if (seq == NULL)
- return FALSE;
+ return false;
seq->low_pc = address;
seq->prev_sequence = table->sequences;
seq->last_line = info;
if (address < seq->low_pc)
seq->low_pc = address;
}
- return TRUE;
+ return true;
}
/* Extract a fully qualified filename from a line info table.
return strdup (filename);
}
-static bfd_boolean
+static bool
arange_add (const struct comp_unit *unit, struct arange *first_arange,
bfd_vma low_pc, bfd_vma high_pc)
{
/* Ignore empty ranges. */
if (low_pc == high_pc)
- return TRUE;
+ return true;
/* If the first arange is empty, use it. */
if (first_arange->high == 0)
{
first_arange->low = low_pc;
first_arange->high = high_pc;
- return TRUE;
+ return true;
}
/* Next see if we can cheaply extend an existing range. */
if (low_pc == arange->high)
{
arange->high = high_pc;
- return TRUE;
+ return true;
}
if (high_pc == arange->low)
{
arange->low = low_pc;
- return TRUE;
+ return true;
}
arange = arange->next;
}
Order isn't significant, so just insert after the first arange. */
arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange));
if (arange == NULL)
- return FALSE;
+ return false;
arange->low = low_pc;
arange->high = high_pc;
arange->next = first_arange->next;
first_arange->next = arange;
- return TRUE;
+ return true;
}
/* Compare function for line sequences. */
if (seq1->last_line->op_index > seq2->last_line->op_index)
return -1;
+ /* num_lines is initially an index, to make the sort stable. */
+ if (seq1->num_lines < seq2->num_lines)
+ return -1;
+ if (seq1->num_lines > seq2->num_lines)
+ return 1;
return 0;
}
/* Construct the line information table for quick lookup. */
-static bfd_boolean
+static bool
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;
+ return true;
/* Count the number of line information entries. We could do this while
scanning the debug information, but some entries may be added via
for (each_line = seq->last_line; each_line; each_line = each_line->prev_line)
num_lines++;
+ seq->num_lines = num_lines;
if (num_lines == 0)
- return TRUE;
+ return true;
/* Allocate space for the line information lookup table. */
amt = sizeof (struct line_info*) * num_lines;
line_info_lookup = (struct line_info**) bfd_alloc (table->abfd, amt);
+ seq->line_info_lookup = line_info_lookup;
if (line_info_lookup == NULL)
- return FALSE;
+ return false;
/* Create the line information lookup table. */
line_index = num_lines;
line_info_lookup[--line_index] = each_line;
BFD_ASSERT (line_index == 0);
-
- seq->num_lines = num_lines;
- seq->line_info_lookup = line_info_lookup;
-
- return TRUE;
+ return true;
}
/* Sort the line sequences for quick lookup. */
-static bfd_boolean
+static bool
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;
+ return true;
/* Allocate space for an array of sequences. */
amt = sizeof (struct line_sequence) * num_sequences;
sequences = (struct line_sequence *) bfd_alloc (table->abfd, amt);
if (sequences == NULL)
- return FALSE;
+ return false;
/* Copy the linked list into the array, freeing the original nodes. */
seq = table->sequences;
sequences[n].prev_sequence = NULL;
sequences[n].last_line = seq->last_line;
sequences[n].line_info_lookup = NULL;
- sequences[n].num_lines = 0;
+ sequences[n].num_lines = n;
seq = seq->prev_sequence;
free (last_seq);
}
table->sequences = sequences;
table->num_sequences = num_sequences;
- return TRUE;
+ return true;
}
/* Add directory to TABLE. CUR_DIR memory ownership is taken by TABLE. */
-static bfd_boolean
+static bool
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;
+ size_t amt;
amt = table->num_dirs + DIR_ALLOC_CHUNK;
amt *= sizeof (char *);
tmp = (char **) bfd_realloc (table->dirs, amt);
if (tmp == NULL)
- return FALSE;
+ return false;
table->dirs = tmp;
}
table->dirs[table->num_dirs++] = cur_dir;
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
line_info_add_include_dir_stub (struct line_info_table *table, char *cur_dir,
unsigned int dir ATTRIBUTE_UNUSED,
unsigned int xtime ATTRIBUTE_UNUSED,
/* Add file to TABLE. CUR_FILE memory ownership is taken by TABLE. */
-static bfd_boolean
+static bool
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;
+ size_t 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;
+ return false;
table->files = tmp;
}
table->files[table->num_files].time = xtime;
table->files[table->num_files].size = size;
table->num_files++;
- return TRUE;
+ return true;
}
/* Read directory or file name entry format, starting with byte of
entries count and the entries themselves in the described entry
format. */
-static bfd_boolean
+static bool
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))
+ bool (*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_count = read_1_byte (abfd, &buf, buf_end);
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;
+ _bfd_safe_read_leb128 (abfd, &buf, false, buf_end);
+ _bfd_safe_read_leb128 (abfd, &buf, false, buf_end);
}
- data_count = _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end);
- buf += bytes_read;
+ data_count = _bfd_safe_read_leb128 (abfd, &buf, false, buf_end);
if (format_count == 0 && data_count != 0)
{
_bfd_error_handler (_("DWARF error: zero format count"));
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
/* PR 22210. Paranoia check. Don't bother running the loop
(_("DWARF error: data count (%" PRIx64 ") larger than buffer size"),
(uint64_t) data_count);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
for (datai = 0; datai < data_count; datai++)
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;
+ content_type = _bfd_safe_read_leb128 (abfd, &format, false, buf_end);
switch (content_type)
{
case DW_LNCT_path:
(_("DWARF error: unknown format content type %" PRIu64),
(uint64_t) content_type);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
- form = _bfd_safe_read_leb128 (abfd, format, &bytes_read, FALSE,
- buf_end);
- format += bytes_read;
-
+ form = _bfd_safe_read_leb128 (abfd, &format, false, buf_end);
buf = read_attribute_value (&attr, form, 0, unit, buf, buf_end);
if (buf == NULL)
- return FALSE;
+ return false;
switch (form)
{
case DW_FORM_string:
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;
- return TRUE;
+ return true;
}
/* 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;
struct line_head lh;
- unsigned int i, bytes_read, offset_size;
+ unsigned int i, offset_size;
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 += 4;
+ lh.total_length = read_4_bytes (abfd, &line_ptr, line_end);
offset_size = 4;
if (lh.total_length == 0xffffffff)
{
- lh.total_length = read_8_bytes (abfd, line_ptr, line_end);
- line_ptr += 8;
+ lh.total_length = read_8_bytes (abfd, &line_ptr, line_end);
offset_size = 8;
}
else if (lh.total_length == 0 && unit->addr_size == 8)
{
/* Handle (non-standard) 64-bit DWARF2 formats. */
- lh.total_length = read_4_bytes (abfd, line_ptr, line_end);
- line_ptr += 4;
+ lh.total_length = read_4_bytes (abfd, &line_ptr, line_end);
offset_size = 8;
}
line_end = line_ptr + lh.total_length;
- lh.version = read_2_bytes (abfd, line_ptr, line_end);
+ lh.version = read_2_bytes (abfd, &line_ptr, line_end);
if (lh.version < 2 || lh.version > 5)
{
_bfd_error_handler
bfd_set_error (bfd_error_bad_value);
return NULL;
}
- line_ptr += 2;
if (line_ptr + offset_size + (lh.version >= 5 ? 8 : (lh.version >= 4 ? 6 : 5))
>= line_end)
unsigned int segment_selector_size;
/* Skip address size. */
- read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ read_1_byte (abfd, &line_ptr, line_end);
- segment_selector_size = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ segment_selector_size = read_1_byte (abfd, &line_ptr, line_end);
if (segment_selector_size != 0)
{
_bfd_error_handler
}
if (offset_size == 4)
- lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end);
+ lh.prologue_length = read_4_bytes (abfd, &line_ptr, line_end);
else
- lh.prologue_length = read_8_bytes (abfd, line_ptr, line_end);
- line_ptr += offset_size;
+ lh.prologue_length = read_8_bytes (abfd, &line_ptr, line_end);
- lh.minimum_instruction_length = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ lh.minimum_instruction_length = read_1_byte (abfd, &line_ptr, line_end);
if (lh.version >= 4)
- {
- lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
- }
+ lh.maximum_ops_per_insn = read_1_byte (abfd, &line_ptr, line_end);
else
lh.maximum_ops_per_insn = 1;
return NULL;
}
- lh.default_is_stmt = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
-
- lh.line_base = read_1_signed_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
-
- lh.line_range = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
-
- lh.opcode_base = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ lh.default_is_stmt = read_1_byte (abfd, &line_ptr, line_end);
+ lh.line_base = read_1_signed_byte (abfd, &line_ptr, line_end);
+ lh.line_range = read_1_byte (abfd, &line_ptr, line_end);
+ lh.opcode_base = read_1_byte (abfd, &line_ptr, line_end);
if (line_ptr + (lh.opcode_base - 1) >= line_end)
{
lh.standard_opcode_lengths[0] = 1;
for (i = 1; i < lh.opcode_base; ++i)
- {
- lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
- }
+ lh.standard_opcode_lengths[i] = read_1_byte (abfd, &line_ptr, line_end);
+
+ 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)
{
else
{
/* Read directory table. */
- while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
+ while ((cur_dir = read_string (&line_ptr, line_end)) != NULL)
{
- line_ptr += bytes_read;
-
if (!line_info_add_include_dir (table, cur_dir))
goto fail;
}
- line_ptr += bytes_read;
-
/* Read file name table. */
- while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
+ while ((cur_file = read_string (&line_ptr, line_end)) != NULL)
{
unsigned int dir, xtime, size;
- line_ptr += bytes_read;
-
- 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;
+ dir = _bfd_safe_read_leb128 (abfd, &line_ptr, false, line_end);
+ xtime = _bfd_safe_read_leb128 (abfd, &line_ptr, false, line_end);
+ size = _bfd_safe_read_leb128 (abfd, &line_ptr, false, line_end);
if (!line_info_add_file_name (table, cur_file, dir, xtime, size))
goto fail;
}
-
- line_ptr += bytes_read;
}
/* Read the statement sequences until there's nothing left. */
/* Decode the table. */
while (!end_sequence && line_ptr < line_end)
{
- op_code = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ op_code = read_1_byte (abfd, &line_ptr, line_end);
if (op_code >= lh.opcode_base)
{
else switch (op_code)
{
case DW_LNS_extended_op:
- exop_len = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
- line_ptr += bytes_read;
- extended_op = read_1_byte (abfd, line_ptr, line_end);
- line_ptr += 1;
+ exop_len = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
+ extended_op = read_1_byte (abfd, &line_ptr, line_end);
switch (extended_op)
{
goto line_fail;
break;
case DW_LNE_set_address:
- address = read_address (unit, line_ptr, line_end);
+ address = read_address (unit, &line_ptr, line_end);
op_index = 0;
- line_ptr += unit->addr_size;
break;
case DW_LNE_define_file:
- cur_file = read_string (abfd, line_ptr, line_end, &bytes_read);
- line_ptr += bytes_read;
- 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;
+ cur_file = read_string (&line_ptr, line_end);
+ dir = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
+ xtime = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
+ size = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
if (!line_info_add_file_name (table, cur_file, dir,
xtime, size))
goto line_fail;
break;
case DW_LNE_set_discriminator:
discriminator =
- _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
- line_ptr += bytes_read;
+ _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
break;
case DW_LNE_HP_source_file_correlation:
line_ptr += exop_len - 1;
(_("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;
case DW_LNS_advance_pc:
if (lh.maximum_ops_per_insn == 1)
address += (lh.minimum_instruction_length
- * _bfd_safe_read_leb128 (abfd, line_ptr,
- &bytes_read,
- FALSE, line_end));
+ * _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end));
else
{
- bfd_vma adjust = _bfd_safe_read_leb128 (abfd, line_ptr,
- &bytes_read,
- FALSE, line_end);
+ bfd_vma adjust = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
address = ((op_index + adjust) / lh.maximum_ops_per_insn
* lh.minimum_instruction_length);
op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
}
- line_ptr += bytes_read;
break;
case DW_LNS_advance_line:
- line += _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- TRUE, line_end);
- line_ptr += bytes_read;
+ line += _bfd_safe_read_leb128 (abfd, &line_ptr,
+ true, line_end);
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);
- line_ptr += bytes_read;
- if (filename)
- free (filename);
- filename = concat_filename (table, file);
+ filenum = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
+ free (filename);
+ filename = concat_filename (table, filenum);
break;
}
case DW_LNS_set_column:
- column = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
- line_ptr += bytes_read;
+ column = _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
break;
case DW_LNS_negate_stmt:
is_stmt = (!is_stmt);
}
break;
case DW_LNS_fixed_advance_pc:
- address += read_2_bytes (abfd, line_ptr, line_end);
+ address += read_2_bytes (abfd, &line_ptr, line_end);
op_index = 0;
- line_ptr += 2;
break;
default:
/* Unknown standard opcode, ignore it. */
for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
- {
- (void) _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read,
- FALSE, line_end);
- line_ptr += bytes_read;
- }
+ (void) _bfd_safe_read_leb128 (abfd, &line_ptr,
+ false, line_end);
break;
}
}
- 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;
}
/* Read in the .debug_ranges section for future reference. */
-static bfd_boolean
+static bool
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 bool
+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. */
if (lookup1->high_addr > lookup2->high_addr)
return 1;
+ if (lookup1->idx < lookup2->idx)
+ return -1;
+ if (lookup1->idx > lookup2->idx)
+ return 1;
return 0;
}
-static bfd_boolean
+static bool
build_lookup_funcinfo_table (struct comp_unit * unit)
{
struct lookup_funcinfo *lookup_funcinfo_table = unit->lookup_funcinfo_table;
bfd_vma low_addr, high_addr;
if (lookup_funcinfo_table || number_of_functions == 0)
- return TRUE;
+ return true;
/* Create the function info lookup table. */
lookup_funcinfo_table = (struct lookup_funcinfo *)
bfd_malloc (number_of_functions * sizeof (struct lookup_funcinfo));
if (lookup_funcinfo_table == NULL)
- return FALSE;
+ return false;
/* Populate the function info lookup table. */
func_index = number_of_functions;
{
entry = &lookup_funcinfo_table[--func_index];
entry->funcinfo = each;
+ entry->idx = func_index;
/* Calculate the lowest and highest address for this function entry. */
low_addr = entry->funcinfo->arange.low;
}
unit->lookup_funcinfo_table = lookup_funcinfo_table;
- return TRUE;
+ return true;
}
/* If ADDR is within UNIT's function tables, set FUNCTION_PTR, and return
that contains ADDR, to handle inlined functions without depending upon
them being ordered in TABLE by increasing range. */
-static bfd_boolean
+static bool
lookup_address_in_function_table (struct comp_unit *unit,
bfd_vma addr,
struct funcinfo **function_ptr)
struct arange *arange;
if (number_of_functions == 0)
- return FALSE;
+ return false;
if (!build_lookup_funcinfo_table (unit))
- return FALSE;
+ return false;
if (unit->lookup_funcinfo_table[number_of_functions - 1].high_addr < addr)
- return FALSE;
+ return false;
/* Find the first function in the lookup table which may contain the
specified address. */
}
if (!best_fit)
- return FALSE;
+ return false;
*function_ptr = best_fit;
- return TRUE;
+ return true;
}
/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR
and LINENUMBER_PTR, and return TRUE. */
-static bfd_boolean
+static bool
lookup_symbol_in_function_table (struct comp_unit *unit,
asymbol *sym,
bfd_vma addr,
bfd_vma best_fit_len = 0;
struct arange *arange;
const char *name = bfd_asymbol_name (sym);
- asection *sec = bfd_get_section (sym);
+ asection *sec = bfd_asymbol_section (sym);
for (each_func = unit->function_table;
each_func;
best_fit->sec = sec;
*filename_ptr = best_fit->file;
*linenumber_ptr = best_fit->line;
- return TRUE;
+ return true;
}
else
- return FALSE;
+ return false;
}
/* Variable table functions. */
/* If SYM is within variable table of UNIT, set FILENAME_PTR and
LINENUMBER_PTR, and return TRUE. */
-static bfd_boolean
+static bool
lookup_symbol_in_variable_table (struct comp_unit *unit,
asymbol *sym,
bfd_vma addr,
unsigned int *linenumber_ptr)
{
const char *name = bfd_asymbol_name (sym);
- asection *sec = bfd_get_section (sym);
+ asection *sec = bfd_asymbol_section (sym);
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
each->sec = sec;
*filename_ptr = each->file;
*linenumber_ptr = each->line;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *,
- struct dwarf2_debug *);
-
-static bfd_boolean
-find_abstract_instance (struct comp_unit * unit,
- bfd_byte * orig_info_ptr,
- struct attribute * attr_ptr,
- const char ** pname,
- bfd_boolean * is_linkage,
- char ** filename_ptr,
- int * linenumber_ptr)
+static struct comp_unit *stash_comp_unit (struct dwarf2_debug *,
+ struct dwarf2_debug_file *);
+static bool comp_unit_maybe_decode_line_info (struct comp_unit *);
+
+static bool
+find_abstract_instance (struct comp_unit *unit,
+ struct attribute *attr_ptr,
+ unsigned int recur_count,
+ const char **pname,
+ bool *is_linkage,
+ char **filename_ptr,
+ 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;
+ unsigned int abbrev_number, i;
struct abbrev_info *abbrev;
bfd_uint64_t die_ref = attr_ptr->u.val;
struct attribute attr;
const char *name = NULL;
+ if (recur_count == 100)
+ {
+ _bfd_error_handler
+ (_("DWARF error: abstract instance recursion detected"));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
/* 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)
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 true;
else if (die_ref >= total)
{
_bfd_error_handler
(_("DWARF error: invalid abstract instance DIE ref"));
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
info_ptr += die_ref;
+ }
+ else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
+ {
+ bool 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;
- if (u)
+ 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)
{
- unit = u;
- info_ptr_end = unit->end_ptr;
+ _bfd_error_handler
+ (_("DWARF error: unable to locate abstract instance DIE ref %"
+ PRIu64), (uint64_t) die_ref);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
- /* else FIXME: What do we do now ? */
+ unit = u;
+ 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
_bfd_error_handler
(_("DWARF error: invalid abstract instance DIE ref"));
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
info_ptr += die_ref;
}
- abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
-
+ abbrev_number = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, info_ptr_end);
if (abbrev_number)
{
abbrev = lookup_abbrev (abbrev_number, unit->abbrevs);
_bfd_error_handler
(_("DWARF error: could not find abbrev number %u"), abbrev_number);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ 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:
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
over DW_AT_name. */
- if (name == NULL && is_str_attr (attr.form))
+ if (name == NULL && is_str_form (&attr))
{
name = attr.u.str;
if (non_mangled (unit->lang))
- *is_linkage = TRUE;
+ *is_linkage = true;
}
break;
case DW_AT_specification:
- if (!find_abstract_instance (unit, info_ptr, &attr,
- &name, is_linkage,
- filename_ptr, linenumber_ptr))
- return FALSE;
+ if (is_int_form (&attr)
+ && !find_abstract_instance (unit, &attr, recur_count + 1,
+ &name, is_linkage,
+ filename_ptr, linenumber_ptr))
+ return false;
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
/* PR 16949: Corrupt debug info can place
non-string forms into these attributes. */
- if (is_str_attr (attr.form))
+ if (is_str_form (&attr))
{
name = attr.u.str;
- *is_linkage = TRUE;
+ *is_linkage = true;
}
break;
case DW_AT_decl_file:
- *filename_ptr = concat_filename (unit->line_table,
- attr.u.val);
+ if (!comp_unit_maybe_decode_line_info (unit))
+ return false;
+ if (is_int_form (&attr))
+ *filename_ptr = concat_filename (unit->line_table,
+ attr.u.val);
break;
case DW_AT_decl_line:
- *linenumber_ptr = attr.u.val;
+ if (is_int_form (&attr))
+ *linenumber_ptr = attr.u.val;
break;
default:
break;
}
}
*pname = name;
- return TRUE;
+ return true;
}
-static bfd_boolean
-read_rangelist (struct comp_unit *unit, struct arange *arange,
- bfd_uint64_t offset)
+static bool
+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;
+ return false;
}
- ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
- if (ranges_ptr < unit->stash->dwarf_ranges_buffer)
- return FALSE;
- ranges_end = unit->stash->dwarf_ranges_buffer + unit->stash->dwarf_ranges_size;
+ if (offset > unit->file->dwarf_ranges_size)
+ return false;
+ ranges_ptr = unit->file->dwarf_ranges_buffer + offset;
+ ranges_end = unit->file->dwarf_ranges_buffer + unit->file->dwarf_ranges_size;
for (;;)
{
bfd_vma high_pc;
/* PR 17512: file: 62cada7d. */
- if (ranges_ptr + 2 * unit->addr_size > ranges_end)
- return FALSE;
+ if (2u * unit->addr_size > (size_t) (ranges_end - ranges_ptr))
+ return false;
- low_pc = read_address (unit, ranges_ptr, ranges_end);
- ranges_ptr += unit->addr_size;
- high_pc = read_address (unit, ranges_ptr, ranges_end);
- ranges_ptr += unit->addr_size;
+ low_pc = read_address (unit, &ranges_ptr, ranges_end);
+ high_pc = read_address (unit, &ranges_ptr, ranges_end);
if (low_pc == 0 && high_pc == 0)
break;
{
if (!arange_add (unit, arange,
base_address + low_pc, base_address + high_pc))
- return FALSE;
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+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;
+
+ if (rngs_ptr >= rngs_end)
+ return false;
+
+ rlet = read_1_byte (abfd, &rngs_ptr, rngs_end);
+
+ switch (rlet)
+ {
+ case DW_RLE_end_of_list:
+ return true;
+
+ case DW_RLE_base_address:
+ if (unit->addr_size > (size_t) (rngs_end - rngs_ptr))
+ return false;
+ base_address = read_address (unit, &rngs_ptr, rngs_end);
+ continue;
+
+ case DW_RLE_start_length:
+ if (unit->addr_size > (size_t) (rngs_end - rngs_ptr))
+ return false;
+ low_pc = read_address (unit, &rngs_ptr, rngs_end);
+ high_pc = low_pc;
+ high_pc += _bfd_safe_read_leb128 (abfd, &rngs_ptr,
+ false, rngs_end);
+ break;
+
+ case DW_RLE_offset_pair:
+ low_pc = base_address;
+ low_pc += _bfd_safe_read_leb128 (abfd, &rngs_ptr,
+ false, rngs_end);
+ high_pc = base_address;
+ high_pc += _bfd_safe_read_leb128 (abfd, &rngs_ptr,
+ false, rngs_end);
+ break;
+
+ case DW_RLE_start_end:
+ if (2u * unit->addr_size > (size_t) (rngs_end - rngs_ptr))
+ return false;
+ low_pc = read_address (unit, &rngs_ptr, rngs_end);
+ high_pc = read_address (unit, &rngs_ptr, rngs_end);
+ 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 bool
+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 TRUE;
+
+ return NULL;
}
+
/* DWARF2 Compilation unit functions. */
/* Scan over each die in a comp. unit looking for functions to add
to the function table and variables to the variable table. */
-static bfd_boolean
+static bool
scan_unit_for_symbols (struct comp_unit *unit)
{
bfd *abfd = unit->abfd;
bfd_byte *info_ptr = unit->first_child_die_ptr;
- bfd_byte *info_ptr_end = unit->stash->info_ptr_end;
+ 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;
nested_funcs = (struct nest_funcinfo *)
bfd_malloc (nested_funcs_size * sizeof (*nested_funcs));
if (nested_funcs == NULL)
- return FALSE;
+ 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;
+ unsigned int abbrev_number, 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;
- abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, info_ptr_end);
- info_ptr += bytes_read;
-
- if (! abbrev_number)
+ current_offset = info_ptr - unit->info_ptr_unit;
+ abbrev_number = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, info_ptr_end);
+ 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, i;
+ struct abbrev_info *abbrev;
+ struct attribute attr;
+ struct funcinfo *func;
+ struct varinfo *var;
+ bfd_vma low_pc = 0;
+ bfd_vma high_pc = 0;
+ bool 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,
+ false, info_ptr_end);
+ 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_call_file:
- func->caller_file = concat_filename (unit->line_table,
- attr.u.val);
+ if (is_int_form (&attr))
+ func->caller_file = concat_filename (unit->line_table,
+ attr.u.val);
break;
case DW_AT_call_line:
- func->caller_line = attr.u.val;
+ if (is_int_form (&attr))
+ func->caller_line = attr.u.val;
break;
case DW_AT_abstract_origin:
case DW_AT_specification:
- if (!find_abstract_instance (unit, info_ptr, &attr,
- &func->name,
- &func->is_linkage,
- &func->file,
- &func->line))
+ if (is_int_form (&attr)
+ && !find_abstract_instance (unit, &attr, 0,
+ &func->name,
+ &func->is_linkage,
+ &func->file,
+ &func->line))
goto fail;
break;
case DW_AT_name:
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
over DW_AT_name. */
- if (func->name == NULL && is_str_attr (attr.form))
+ if (func->name == NULL && is_str_form (&attr))
{
func->name = attr.u.str;
if (non_mangled (unit->lang))
- func->is_linkage = TRUE;
+ func->is_linkage = true;
}
break;
case DW_AT_MIPS_linkage_name:
/* PR 16949: Corrupt debug info can place
non-string forms into these attributes. */
- if (is_str_attr (attr.form))
+ if (is_str_form (&attr))
{
func->name = attr.u.str;
- func->is_linkage = TRUE;
+ func->is_linkage = true;
}
break;
case DW_AT_low_pc:
- low_pc = attr.u.val;
+ if (is_int_form (&attr))
+ low_pc = attr.u.val;
break;
case DW_AT_high_pc:
- high_pc = attr.u.val;
- high_pc_relative = attr.form != DW_FORM_addr;
+ if (is_int_form (&attr))
+ {
+ high_pc = attr.u.val;
+ high_pc_relative = attr.form != DW_FORM_addr;
+ }
break;
case DW_AT_ranges:
- if (!read_rangelist (unit, &func->arange, attr.u.val))
+ if (is_int_form (&attr)
+ && !read_rangelist (unit, &func->arange, attr.u.val))
goto fail;
break;
case DW_AT_decl_file:
- func->file = concat_filename (unit->line_table,
- attr.u.val);
+ if (is_int_form (&attr))
+ func->file = concat_filename (unit->line_table,
+ attr.u.val);
break;
case DW_AT_decl_line:
- func->line = attr.u.val;
+ if (is_int_form (&attr))
+ func->line = attr.u.val;
break;
default:
{
switch (attr.name)
{
+ case DW_AT_specification:
+ if (is_int_form (&attr) && 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))
+ if (is_str_form (&attr))
var->name = attr.u.str;
break;
case DW_AT_decl_file:
- var->file = concat_filename (unit->line_table,
- attr.u.val);
+ if (is_int_form (&attr))
+ var->file = concat_filename (unit->line_table,
+ attr.u.val);
break;
case DW_AT_decl_line:
- var->line = attr.u.val;
+ if (is_int_form (&attr))
+ var->line = attr.u.val;
break;
case DW_AT_external:
- if (attr.u.val != 0)
- var->stack = 0;
+ if (is_int_form (&attr) && attr.u.val != 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);
- return TRUE;
+ return true;
fail:
free (nested_funcs);
- return FALSE;
+ return false;
}
-/* Parse a DWARF2 compilation unit starting at INFO_PTR. This
+/* Parse a DWARF2 compilation unit starting at INFO_PTR. UNIT_LENGTH
includes the compilation unit header that proceeds the DIE's, but
does not include the length field that precedes each compilation
unit header. END_PTR points one past the end of this comp unit.
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)
/* 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;
+ unsigned int abbrev_number, 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_boolean high_pc_relative = FALSE;
+ bfd *abfd = file->bfd_ptr;
+ bool high_pc_relative = false;
enum dwarf_unit_type unit_type;
- version = read_2_bytes (abfd, info_ptr, end_ptr);
- info_ptr += 2;
+ version = read_2_bytes (abfd, &info_ptr, end_ptr);
if (version < 2 || version > 5)
{
/* PR 19872: A version number of 0 probably means that there is padding
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;
+ unit_type = read_1_byte (abfd, &info_ptr, end_ptr);
+ addr_size = read_1_byte (abfd, &info_ptr, end_ptr);
}
BFD_ASSERT (offset_size == 4 || offset_size == 8);
if (offset_size == 4)
- abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr);
+ 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;
+ abbrev_offset = read_8_bytes (abfd, &info_ptr, end_ptr);
if (version < 5)
- {
- addr_size = read_1_byte (abfd, info_ptr, end_ptr);
- info_ptr += 1;
- }
+ addr_size = read_1_byte (abfd, &info_ptr, end_ptr);
if (unit_type == DW_UT_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;
- abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
- FALSE, end_ptr);
- info_ptr += bytes_read;
+ abbrev_number = _bfd_safe_read_leb128 (abfd, &info_ptr,
+ false, end_ptr);
if (! abbrev_number)
{
/* PR 19872: An abbrev number of 0 probably means that there is padding
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)
switch (attr.name)
{
case DW_AT_stmt_list:
- unit->stmtlist = 1;
- unit->line_offset = attr.u.val;
+ if (is_int_form (&attr))
+ {
+ unit->stmtlist = 1;
+ unit->line_offset = attr.u.val;
+ }
break;
case DW_AT_name:
- if (is_str_attr (attr.form))
+ if (is_str_form (&attr))
unit->name = attr.u.str;
break;
case DW_AT_low_pc:
- low_pc = attr.u.val;
- /* If the compilation unit DIE has a DW_AT_low_pc attribute,
- this is the base address to use when reading location
- lists or range lists. */
- if (abbrev->tag == DW_TAG_compile_unit)
- unit->base_address = low_pc;
+ if (is_int_form (&attr))
+ {
+ low_pc = attr.u.val;
+ /* If the compilation unit DIE has a DW_AT_low_pc attribute,
+ this is the base address to use when reading location
+ lists or range lists. */
+ if (abbrev->tag == DW_TAG_compile_unit)
+ unit->base_address = low_pc;
+ }
break;
case DW_AT_high_pc:
- high_pc = attr.u.val;
- high_pc_relative = attr.form != DW_FORM_addr;
+ if (is_int_form (&attr))
+ {
+ high_pc = attr.u.val;
+ high_pc_relative = attr.form != DW_FORM_addr;
+ }
break;
case DW_AT_ranges:
- if (!read_rangelist (unit, &unit->arange, attr.u.val))
+ if (is_int_form (&attr)
+ && !read_rangelist (unit, &unit->arange, attr.u.val))
return NULL;
break;
char *comp_dir = attr.u.str;
/* PR 17512: file: 1fe726be. */
- if (! is_str_attr (attr.form))
+ if (!is_str_form (&attr))
{
_bfd_error_handler
(_("DWARF error: DW_AT_comp_dir attribute encountered with a non-string form"));
}
case DW_AT_language:
- unit->lang = attr.u.val;
+ if (is_int_form (&attr))
+ unit->lang = attr.u.val;
break;
default:
need to consult the line info table to see if a compilation unit
really contains the given address. */
-static bfd_boolean
+static bool
comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr)
{
struct arange *arange;
if (unit->error)
- return FALSE;
+ return false;
arange = &unit->arange;
do
{
if (addr >= arange->low && addr < arange->high)
- return TRUE;
+ return true;
arange = arange->next;
}
while (arange);
- return FALSE;
+ return false;
}
/* If UNIT contains ADDR, set the output parameters to the values for
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;
+ bool func_p;
- if (!comp_unit_maybe_decode_line_info (unit, stash))
- return FALSE;
+ 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,
If not, decode it. Returns TRUE if no errors were encountered;
FALSE otherwise. */
-static bfd_boolean
-comp_unit_maybe_decode_line_info (struct comp_unit *unit,
- struct dwarf2_debug *stash)
+static bool
+comp_unit_maybe_decode_line_info (struct comp_unit *unit)
{
if (unit->error)
- return FALSE;
+ return false;
if (! unit->line_table)
{
if (! unit->stmtlist)
{
unit->error = 1;
- return FALSE;
+ return false;
}
- unit->line_table = decode_line_info (unit, stash);
+ unit->line_table = decode_line_info (unit);
if (! unit->line_table)
{
unit->error = 1;
- return FALSE;
+ return false;
}
if (unit->first_child_die_ptr < unit->end_ptr
&& ! scan_unit_for_symbols (unit))
{
unit->error = 1;
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/* If UNIT contains SYM at ADDR, set the output parameters to the
Return TRUE if UNIT contains SYM, and no errors were encountered;
FALSE otherwise. */
-static bfd_boolean
+static bool
comp_unit_find_line (struct comp_unit *unit,
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))
- return FALSE;
+ if (!comp_unit_maybe_decode_line_info (unit))
+ return false;
if (sym->flags & BSF_FUNCTION)
return lookup_symbol_in_function_table (unit, sym, addr,
unit into hash tables for faster lookup. Returns TRUE if no
errors were enountered; FALSE otherwise. */
-static bfd_boolean
+static bool
comp_unit_hash_info (struct dwarf2_debug *stash,
struct comp_unit *unit,
struct info_hash_table *funcinfo_hash_table,
{
struct funcinfo* each_func;
struct varinfo* each_var;
- bfd_boolean okay = TRUE;
+ bool okay = true;
BFD_ASSERT (stash->info_hash_status != STASH_INFO_HASH_DISABLED);
- if (!comp_unit_maybe_decode_line_info (unit, stash))
- return FALSE;
+ if (!comp_unit_maybe_decode_line_info (unit))
+ return false;
BFD_ASSERT (!unit->cached);
name string is either in the dwarf string buffer or
info in the stash. */
okay = insert_info_hash_table (funcinfo_hash_table, each_func->name,
- (void*) each_func, FALSE);
+ (void*) each_func, false);
}
unit->function_table = reverse_funcinfo_list (unit->function_table);
if (!okay)
- return FALSE;
+ return false;
/* We do the same for variable infos. */
unit->variable_table = reverse_varinfo_list (unit->variable_table);
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
name string is either in the dwarf string buffer or
info in the stash. */
okay = insert_info_hash_table (varinfo_hash_table, each_var->name,
- (void*) each_var, FALSE);
+ (void*) each_var, false);
}
unit->variable_table = reverse_varinfo_list (unit->variable_table);
- unit->cached = TRUE;
+ unit->cached = true;
return okay;
}
return msec;
look = debug_sections[debug_info].compressed_name;
- if (look != NULL)
- {
- msec = bfd_get_section_by_name (abfd, look);
- if (msec != NULL)
- return msec;
- }
+ msec = bfd_get_section_by_name (abfd, look);
+ if (msec != NULL)
+ return msec;
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;
}
}
}
+/* If the dwarf2 info was found in a separate debug file, return the
+ debug file section corresponding to the section in the original file
+ and the debug file symbols. */
+
+static void
+_bfd_dwarf2_stash_syms (struct dwarf2_debug *stash, bfd *abfd,
+ asection **sec, asymbol ***syms)
+{
+ if (stash->f.bfd_ptr != abfd)
+ {
+ asection *s, *d;
+
+ if (*sec == NULL)
+ {
+ *syms = stash->f.syms;
+ return;
+ }
+
+ for (s = abfd->sections, d = stash->f.bfd_ptr->sections;
+ s != NULL && d != NULL;
+ s = s->next, d = d->next)
+ {
+ if ((d->flags & SEC_DEBUGGING) != 0)
+ break;
+ if (s == *sec
+ && strcmp (s->name, d->name) == 0)
+ {
+ *sec = d;
+ *syms = stash->f.syms;
+ break;
+ }
+ }
+ }
+}
+
/* Unset vmas for adjusted sections in STASH. */
static void
logical section. ??? We should probably do the same for other
debug sections. */
-static bfd_boolean
+static bool
place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
{
bfd *abfd;
p = stash->adjusted_sections;
for (; i > 0; i--, p++)
p->section->vma = p->adj_vma;
- return TRUE;
+ return true;
}
debug_info_name = stash->debug_sections[debug_info].uncompressed_name;
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)
- return FALSE;
+ return false;
stash->adjusted_sections = p;
stash->adjusted_section_count = i;
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;
+ return true;
}
/* Look up a funcinfo by name using the given info hash table. If found,
This function returns TRUE if a funcinfo that matches the given symbol
and address is found with any error; otherwise it returns FALSE. */
-static bfd_boolean
+static bool
info_hash_lookup_funcinfo (struct info_hash_table *hash_table,
asymbol *sym,
bfd_vma addr,
struct info_list_node *node;
struct arange *arange;
const char *name = bfd_asymbol_name (sym);
- asection *sec = bfd_get_section (sym);
+ asection *sec = bfd_asymbol_section (sym);
for (node = lookup_info_hash_table (hash_table, name);
node;
best_fit->sec = sec;
*filename_ptr = best_fit->file;
*linenumber_ptr = best_fit->line;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/* Look up a varinfo by name using the given info hash table. If found,
This function returns TRUE if a varinfo that matches the given symbol
and address is found with any error; otherwise it returns FALSE. */
-static bfd_boolean
+static bool
info_hash_lookup_varinfo (struct info_hash_table *hash_table,
asymbol *sym,
bfd_vma addr,
unsigned int *linenumber_ptr)
{
const char *name = bfd_asymbol_name (sym);
- asection *sec = bfd_get_section (sym);
+ asection *sec = bfd_asymbol_section (sym);
struct varinfo* each;
struct info_list_node *node;
each->sec = sec;
*filename_ptr = each->file;
*linenumber_ptr = each->line;
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/* Update the funcinfo and varinfo info hash tables if they are
not up to date. Returns TRUE if there is no error; otherwise
returns FALSE and disable the info hash tables. */
-static bfd_boolean
+static bool
stash_maybe_update_info_hash_tables (struct dwarf2_debug *stash)
{
struct comp_unit *each;
/* Exit if hash tables are up-to-date. */
- if (stash->all_comp_units == stash->hash_units_head)
- return TRUE;
+ 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)
{
stash->varinfo_hash_table))
{
stash->info_hash_status = STASH_INFO_HASH_DISABLED;
- return FALSE;
+ return false;
}
each = each->prev_unit;
}
- stash->hash_units_head = stash->all_comp_units;
- return TRUE;
+ stash->hash_units_head = stash->f.all_comp_units;
+ return true;
}
/* Check consistency of info hash tables. This is for debugging only. */
struct funcinfo *each_func;
struct varinfo *each_var;
struct info_list_node *node;
- bfd_boolean found;
+ bool found;
- for (each_unit = stash->all_comp_units;
+ for (each_unit = stash->f.all_comp_units;
each_unit;
each_unit = each_unit->next_unit)
{
node = lookup_info_hash_table (stash->funcinfo_hash_table,
each_func->name);
BFD_ASSERT (node);
- found = FALSE;
+ found = false;
while (node && !found)
{
found = node->info == each_func;
node = lookup_info_hash_table (stash->varinfo_hash_table,
each_var->name);
BFD_ASSERT (node);
- found = FALSE;
+ found = false;
while (node && !found)
{
found = node->info == each_var;
/* We need a forced update so that the info hash tables will
be created even though there is no compilation unit. That
happens if STASH_INFO_HASH_TRIGGER is 0. */
- stash_maybe_update_info_hash_tables (stash);
- stash->info_hash_status = STASH_INFO_HASH_ON;
+ if (stash_maybe_update_info_hash_tables (stash))
+ stash->info_hash_status = STASH_INFO_HASH_ON;
}
/* Find the file and line associated with a symbol and address using the
TRUE and update the locations pointed to by filename_ptr and linenumber_ptr;
otherwise it returns FALSE. */
-static bfd_boolean
+static bool
stash_find_line_fast (struct dwarf2_debug *stash,
asymbol *sym,
bfd_vma addr,
/* Save current section VMAs. */
-static bfd_boolean
+static bool
save_section_vma (const bfd *abfd, struct dwarf2_debug *stash)
{
asection *s;
unsigned int i;
if (abfd->section_count == 0)
- return TRUE;
+ return true;
stash->sec_vma = bfd_malloc (sizeof (*stash->sec_vma) * abfd->section_count);
if (stash->sec_vma == NULL)
- return FALSE;
+ return false;
stash->sec_vma_count = abfd->section_count;
for (i = 0, s = abfd->sections;
s != NULL && i < abfd->section_count;
else
stash->sec_vma[i] = s->vma;
}
- return TRUE;
+ return true;
}
/* Compare current section VMAs against those at the time the stash
sections, so the stashed section contents depend on symbol values,
which in turn depend on section VMAs. */
-static bfd_boolean
+static bool
section_vma_same (const bfd *abfd, const struct dwarf2_debug *stash)
{
asection *s;
when the stash was created and now, then we cannot trust the
stashed vma information. */
if (abfd->section_count != stash->sec_vma_count)
- return FALSE;
+ return false;
for (i = 0, s = abfd->sections;
s != NULL && i < abfd->section_count;
else
vma = s->vma;
if (vma != stash->sec_vma[i])
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified.
or its gnu_debuglink. The results will be stored in PINFO.
The function returns TRUE iff debug information is ready. */
-bfd_boolean
+bool
_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
const struct dwarf_debug_section *debug_sections,
asymbol **symbols,
void **pinfo,
- bfd_boolean do_place)
+ bool 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;
- return TRUE;
+ return false;
+ return true;
}
- return FALSE;
+ return false;
}
_bfd_dwarf2_cleanup_debug_info (abfd, pinfo);
memset (stash, 0, amt);
{
stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
if (! stash)
- return FALSE;
+ 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;
+ 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;
Note that at this point the stash has been allocated, but
contains zeros. This lets future calls to this function
fail more quickly. */
- return FALSE;
+ return false;
+
+ debug_bfd = bfd_openr (debug_filename, NULL);
+ free (debug_filename);
+ if (debug_bfd == NULL)
+ /* FIXME: Should we report our failure to follow the debuglink ? */
+ return false;
/* Set BFD_DECOMPRESS to decompress debug sections. */
- if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
- || !(debug_bfd->flags |= BFD_DECOMPRESS,
- bfd_check_format (debug_bfd, bfd_object))
+ debug_bfd->flags |= BFD_DECOMPRESS;
+ if (!bfd_check_format (debug_bfd, bfd_object)
|| (msec = find_debug_info (debug_bfd,
debug_sections, NULL)) == NULL
|| !bfd_generic_link_read_symbols (debug_bfd))
{
- if (debug_bfd)
- bfd_close (debug_bfd);
- /* FIXME: Should we report our failure to follow the debuglink ? */
- free (debug_filename);
- return FALSE;
+ bfd_close (debug_bfd);
+ return false;
}
symbols = bfd_get_outsymbols (debug_bfd);
- stash->syms = symbols;
- stash->close_on_cleanup = TRUE;
+ 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))
- return FALSE;
+ return false;
/* 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
total_size = msec->size;
if (! read_section (debug_bfd, &stash->debug_sections[debug_info],
symbols, 0,
- &stash->info_ptr_memory, &total_size))
- return FALSE;
+ &stash->f.dwarf_info_buffer, &total_size))
+ return false;
}
else
{
for (total_size = 0;
msec;
msec = find_debug_info (debug_bfd, debug_sections, msec))
- total_size += msec->size;
+ {
+ /* Catch PR25070 testcase overflowing size calculation here. */
+ if (total_size + msec->size < total_size
+ || total_size + msec->size < msec->size)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ total_size += msec->size;
+ }
- stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size);
- if (stash->info_ptr_memory == NULL)
- return FALSE;
+ stash->f.dwarf_info_buffer = (bfd_byte *) bfd_malloc (total_size);
+ if (stash->f.dwarf_info_buffer == NULL)
+ return false;
total_size = 0;
for (msec = find_debug_info (debug_bfd, debug_sections, NULL);
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;
+ return false;
total_size += size;
}
}
- stash->info_ptr = stash->info_ptr_memory;
- stash->info_ptr_end = stash->info_ptr + total_size;
- stash->sec = find_debug_info (debug_bfd, debug_sections, NULL);
- stash->sec_info_ptr = stash->info_ptr;
- return TRUE;
+ 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 FILE->INFO_PTR. */
+
+static struct comp_unit *
+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 = file->info_ptr;
+ bfd_byte *info_ptr_end = file->dwarf_info_buffer + file->dwarf_info_size;
+
+ if (file->info_ptr >= info_ptr_end)
+ return NULL;
+
+ 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 (file->bfd_ptr, &file->info_ptr, info_ptr_end);
+ }
+ /* A zero length is the IRIX way of indicating 64-bit offsets,
+ mostly because the 64-bit length will generally fit in 32
+ bits, and the endianness helps. */
+ else if (length == 0)
+ {
+ offset_size = 8;
+ length = read_4_bytes (file->bfd_ptr, &file->info_ptr, info_ptr_end);
+ }
+ /* In the absence of the hints above, we assume 32-bit DWARF2
+ offsets even for targets with 64-bit addresses, because:
+ a) most of the time these targets will not have generated
+ more than 2Gb of debug info and so will not need 64-bit
+ offsets,
+ and
+ b) if they do use 64-bit offsets but they are not using
+ the size hints that are tested for above then they are
+ not conforming to the DWARF3 standard anyway. */
+ else
+ offset_size = 4;
+
+ if (length != 0
+ && length <= (size_t) (info_ptr_end - file->info_ptr))
+ {
+ struct comp_unit *each = parse_comp_unit (stash, file,
+ file->info_ptr, length,
+ info_ptr_unit, offset_size);
+ if (each)
+ {
+ if (file->all_comp_units)
+ file->all_comp_units->prev_unit = each;
+ else
+ file->last_comp_unit = each;
+
+ each->next_unit = file->all_comp_units;
+ file->all_comp_units = each;
+
+ file->info_ptr += length;
+ return each;
+ }
+ }
+
+ /* Don't trust any of the DWARF info after a corrupted length or
+ parse error. */
+ file->info_ptr = info_ptr_end;
+ return NULL;
+}
+
+/* Hash function for an asymbol. */
+
+static hashval_t
+hash_asymbol (const void *sym)
+{
+ const asymbol *asym = sym;
+ return htab_hash_string (asym->name);
+}
+
+/* Equality function for asymbols. */
+
+static int
+eq_asymbol (const void *a, const void *b)
+{
+ const asymbol *sa = a;
+ const asymbol *sb = b;
+ return strcmp (sa->name, sb->name) == 0;
}
/* Scan the debug information in PINFO looking for a DW_TAG_subprogram
{
struct dwarf2_debug *stash;
struct comp_unit * unit;
+ htab_t sym_hash;
+ bfd_signed_vma result = 0;
+ asymbol ** psym;
stash = (struct dwarf2_debug *) *pinfo;
if (stash == NULL || symbols == NULL)
return 0;
- for (unit = stash->all_comp_units; unit; unit = unit->next_unit)
+ sym_hash = htab_create_alloc (10, hash_asymbol, eq_asymbol,
+ NULL, xcalloc, free);
+ for (psym = symbols; * psym != NULL; psym++)
+ {
+ asymbol * sym = * psym;
+
+ if (sym->flags & BSF_FUNCTION && sym->section != NULL)
+ {
+ void **slot = htab_find_slot (sym_hash, sym, INSERT);
+ *slot = sym;
+ }
+ }
+
+ 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)
{
- asymbol ** psym;
+ asymbol search, *sym;
/* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */
- for (psym = symbols; * psym != NULL; psym++)
+ search.name = func->name;
+ sym = htab_find (sym_hash, &search);
+ if (sym != NULL)
{
- asymbol * sym = * psym;
-
- if (sym->flags & BSF_FUNCTION
- && sym->section != NULL
- && strcmp (sym->name, func->name) == 0)
- return ((bfd_signed_vma) func->arange.low) -
- ((bfd_signed_vma) (sym->value + sym->section->vma));
+ result = ((bfd_signed_vma) func->arange.low) -
+ ((bfd_signed_vma) (sym->value + sym->section->vma));
+ goto done;
}
}
}
- return 0;
+ done:
+ htab_delete (sym_hash);
+ return result;
}
/* Find the source code location of SYMBOL. If SYMBOL is NULL
then find the nearest source code location corresponding to
the address SECTION + OFFSET.
- Returns TRUE if the line is found without error and fills in
+ Returns 1 if the line is found without error and fills in
FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was
NULL the FUNCTIONNAME_PTR is also filled in.
+ Returns 2 if partial information from _bfd_elf_find_function is
+ returned (function and maybe file) by looking at symbols. DWARF2
+ info is present but not regarding the requested code location.
+ Returns 0 otherwise.
SYMBOLS contains the symbol table for ABFD.
- DEBUG_SECTIONS contains the name of the dwarf debug sections.
- field and in the abbreviation offset, or zero to indicate that the
- default value should be used. */
+ DEBUG_SECTIONS contains the name of the dwarf debug sections. */
-bfd_boolean
+int
_bfd_dwarf2_find_nearest_line (bfd *abfd,
asymbol **symbols,
asymbol *symbol,
bfd_vma addr;
struct comp_unit* each;
struct funcinfo *function = NULL;
- bfd_boolean found = FALSE;
- bfd_boolean do_line;
+ int found = false;
+ bool do_line;
*filename_ptr = NULL;
if (functionname_ptr != NULL)
if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, debug_sections,
symbols, pinfo,
(abfd->flags & (EXEC_P | DYNAMIC)) == 0))
- return FALSE;
+ return false;
stash = (struct dwarf2_debug *) *pinfo;
if (do_line)
{
BFD_ASSERT (section == NULL && offset == 0 && functionname_ptr == NULL);
- section = bfd_get_section (symbol);
+ section = bfd_asymbol_section (symbol);
addr = symbol->value;
}
else
&& ((*tmp)->flags & BSF_SECTION_SYM) == 0)
{
symbol = *tmp;
- do_line = TRUE;
+ do_line = true;
/* For local symbols, keep going in the hope we find a
global. */
if ((symbol->flags & BSF_GLOBAL) != 0)
/* A null info_ptr indicates that there is no dwarf2 info
(or that an error occured while setting up the stash). */
- if (! stash->info_ptr)
- return FALSE;
+ 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
if (* linenumber_ptr)
{
- found = TRUE;
+ found = true;
goto done;
}
}
/* Read each remaining comp. units checking each as they are read. */
- while (stash->info_ptr < stash->info_ptr_end)
+ while ((each = stash_comp_unit (stash, &stash->f)) != NULL)
{
- bfd_vma length;
- unsigned int offset_size;
- bfd_byte *info_ptr_unit = stash->info_ptr;
-
- length = read_4_bytes (stash->bfd_ptr, stash->info_ptr, stash->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;
- }
- /* A zero length is the IRIX way of indicating 64-bit offsets,
- mostly because the 64-bit length will generally fit in 32
- bits, and the endianness helps. */
- else if (length == 0)
- {
- offset_size = 8;
- length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end);
- stash->info_ptr += 8;
- }
- /* In the absence of the hints above, we assume 32-bit DWARF2
- offsets even for targets with 64-bit addresses, because:
- a) most of the time these targets will not have generated
- more than 2Gb of debug info and so will not need 64-bit
- offsets,
- and
- b) if they do use 64-bit offsets but they are not using
- the size hints that are tested for above then they are
- not conforming to the DWARF3 standard anyway. */
+ /* DW_AT_low_pc and DW_AT_high_pc are optional for
+ compilation units. If we don't have them (i.e.,
+ unit->high == 0), we need to consult the line info table
+ to see if a compilation unit contains the given
+ address. */
+ if (do_line)
+ found = (((symbol->flags & BSF_FUNCTION) == 0
+ || each->arange.high == 0
+ || comp_unit_contains_address (each, addr))
+ && comp_unit_find_line (each, symbol, addr,
+ filename_ptr, linenumber_ptr));
else
- {
- offset_size = 4;
- stash->info_ptr += 4;
- }
-
- if (length > 0)
- {
- bfd_byte * new_ptr;
-
- /* PR 21151 */
- if (stash->info_ptr + length > stash->info_ptr_end)
- return FALSE;
-
- each = parse_comp_unit (stash, length, info_ptr_unit,
- offset_size);
- if (!each)
- /* The dwarf information is damaged, don't trust it any
- more. */
- break;
-
- new_ptr = stash->info_ptr + length;
- /* PR 17512: file: 1500698c. */
- if (new_ptr < stash->info_ptr)
- {
- /* A corrupt length value - do not trust the info any more. */
- found = FALSE;
- break;
- }
- else
- stash->info_ptr = new_ptr;
-
- if (stash->all_comp_units)
- 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
- to see if a compilation unit contains the given
- address. */
- if (do_line)
- found = (((symbol->flags & BSF_FUNCTION) == 0
- || each->arange.high == 0
- || comp_unit_contains_address (each, addr))
- && comp_unit_find_line (each, symbol, addr,
- filename_ptr,
- linenumber_ptr,
- stash));
- else
- found = ((each->arange.high == 0
- || comp_unit_contains_address (each, addr))
- && comp_unit_find_nearest_line (each, addr,
- filename_ptr,
- &function,
- linenumber_ptr,
- discriminator_ptr,
- stash) != 0);
-
- if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
- == stash->sec->size)
- {
- stash->sec = find_debug_info (stash->bfd_ptr, debug_sections,
- stash->sec);
- stash->sec_info_ptr = stash->info_ptr;
- }
-
- if (found)
- goto done;
- }
+ found = ((each->arange.high == 0
+ || comp_unit_contains_address (each, addr))
+ && comp_unit_find_nearest_line (each, addr,
+ filename_ptr,
+ &function,
+ linenumber_ptr,
+ discriminator_ptr) != 0);
+
+ if (found)
+ break;
}
done:
- if (function)
+ if (functionname_ptr && function && function->is_linkage)
+ *functionname_ptr = function->name;
+ else if (functionname_ptr
+ && (!*functionname_ptr
+ || (function && !function->is_linkage)))
{
- if (!function->is_linkage)
+ asymbol *fun;
+ asymbol **syms = symbols;
+ asection *sec = section;
+
+ _bfd_dwarf2_stash_syms (stash, abfd, &sec, &syms);
+ fun = _bfd_elf_find_function (abfd, syms, sec, offset,
+ *filename_ptr ? NULL : filename_ptr,
+ functionname_ptr);
+
+ if (!found && fun != NULL)
+ found = 2;
+
+ if (function && !function->is_linkage)
{
- asymbol *fun;
bfd_vma sec_vma;
- fun = _bfd_elf_find_function (abfd, symbols, section, offset,
- *filename_ptr ? NULL : filename_ptr,
- functionname_ptr);
sec_vma = section->vma;
if (section->output_section != NULL)
sec_vma = section->output_section->vma + section->output_offset;
function->name = *functionname_ptr;
/* Even if we didn't find a linkage name, say that we have
to stop a repeated search of symbols. */
- function->is_linkage = TRUE;
+ function->is_linkage = true;
}
- *functionname_ptr = function->name;
}
+
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
unset_sections (stash);
return found;
}
-bfd_boolean
+bool
_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
const char **filename_ptr,
const char **functionname_ptr,
*functionname_ptr = func->caller_func->name;
*linenumber_ptr = func->caller_line;
stash->inliner_chain = func->caller_func;
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
void
{
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,