summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/bfd/dwarf2.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/bfd/dwarf2.c')
-rw-r--r--contrib/binutils/bfd/dwarf2.c474
1 files changed, 361 insertions, 113 deletions
diff --git a/contrib/binutils/bfd/dwarf2.c b/contrib/binutils/bfd/dwarf2.c
index 2161846..6398d4e 100644
--- a/contrib/binutils/bfd/dwarf2.c
+++ b/contrib/binutils/bfd/dwarf2.c
@@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
struct line_head
{
- unsigned int total_length;
+ bfd_vma total_length;
unsigned short version;
unsigned int prologue_length;
unsigned char minimum_instruction_length;
@@ -96,6 +96,14 @@ struct dwarf2_debug
/* Pointer to the end of the .debug_info section memory buffer. */
char* info_ptr_end;
+ /* Pointer to the section and address of the beginning of the
+ section. */
+ asection* sec;
+ char* sec_info_ptr;
+
+ /* Pointer to the symbol table. */
+ asymbol** syms;
+
/* Pointer to the .debug_abbrev section loaded into memory. */
char* dwarf_abbrev_buffer;
@@ -107,6 +115,12 @@ struct dwarf2_debug
/* Length of the loaded .debug_line section. */
unsigned long dwarf_line_size;
+
+ /* Pointer to the .debug_str section loaded into memory. */
+ char* dwarf_str_buffer;
+
+ /* Length of the loaded .debug_str section. */
+ unsigned long dwarf_str_size;
};
struct arange
@@ -161,10 +175,86 @@ struct comp_unit
/* A list of the functions found in this comp. unit. */
struct funcinfo* function_table;
+ /* Pointer to dwarf2_debug structure. */
+ struct dwarf2_debug *stash;
+
/* Address size for this unit - from unit header. */
unsigned char addr_size;
+
+ /* Offset size for this unit - from unit header. */
+ unsigned char offset_size;
+};
+
+/* 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. */
+};
+
+struct attr_abbrev
+{
+ enum dwarf_attribute name;
+ enum dwarf_form form;
};
+#ifndef ABBREV_HASH_SIZE
+#define ABBREV_HASH_SIZE 121
+#endif
+#ifndef ATTR_ALLOC_CHUNK
+#define ATTR_ALLOC_CHUNK 4
+#endif
+
+static unsigned int read_1_byte PARAMS ((bfd *, char *));
+static int read_1_signed_byte PARAMS ((bfd *, char *));
+static unsigned int read_2_bytes PARAMS ((bfd *, char *));
+static unsigned int read_4_bytes PARAMS ((bfd *, char *));
+static bfd_vma read_8_bytes PARAMS ((bfd *, char *));
+static char *read_n_bytes PARAMS ((bfd *, char *, unsigned int));
+static char *read_string PARAMS ((bfd *, char *, unsigned int *));
+static char *read_indirect_string PARAMS ((struct comp_unit *, char *, unsigned int *));
+static unsigned int read_unsigned_leb128
+ PARAMS ((bfd *, char *, unsigned int *));
+static int read_signed_leb128
+ PARAMS ((bfd *, char *, unsigned int *));
+static bfd_vma read_address PARAMS ((struct comp_unit *, char *));
+static struct abbrev_info *lookup_abbrev
+ PARAMS ((unsigned int, struct abbrev_info **));
+static struct abbrev_info **read_abbrevs
+ PARAMS ((bfd *, unsigned int, struct dwarf2_debug *));
+static char *read_attribute
+ PARAMS ((struct attribute *, struct attr_abbrev *,
+ struct comp_unit *, char *));
+static char *read_attribute_value
+ PARAMS ((struct attribute *, unsigned,
+ struct comp_unit *, char *));
+static void add_line_info
+ PARAMS ((struct line_info_table *, bfd_vma, char *,
+ unsigned int, unsigned int, int));
+static char *concat_filename PARAMS ((struct line_info_table *, unsigned int));
+static void arange_add PARAMS ((struct comp_unit *, bfd_vma, bfd_vma));
+static struct line_info_table *decode_line_info
+ PARAMS ((struct comp_unit *, struct dwarf2_debug *));
+static boolean lookup_address_in_line_info_table
+ PARAMS ((struct line_info_table *, bfd_vma, const char **, unsigned int *));
+static boolean lookup_address_in_function_table
+ PARAMS ((struct funcinfo *, bfd_vma, const char **));
+static boolean scan_unit_for_functions PARAMS ((struct comp_unit *));
+static bfd_vma find_rela_addend
+ PARAMS ((bfd *, asection *, bfd_size_type, asymbol**));
+static struct comp_unit *parse_comp_unit
+ PARAMS ((bfd *, struct dwarf2_debug *, bfd_vma, unsigned int));
+static boolean comp_unit_contains_address
+ PARAMS ((struct comp_unit *, bfd_vma));
+static boolean comp_unit_find_nearest_line
+ PARAMS ((struct comp_unit *, bfd_vma, const char **, const char **,
+ unsigned int *, struct dwarf2_debug *));
+static asection *find_debug_info PARAMS ((bfd *, asection *));
+
/* VERBATIM
The following function up to the END VERBATIM mark are
copied directly from dwarf2read.c. */
@@ -227,7 +317,7 @@ read_4_signed_bytes (abfd, buf)
#endif
-static unsigned int
+static bfd_vma
read_8_bytes (abfd, buf)
bfd *abfd;
char *buf;
@@ -253,9 +343,7 @@ read_string (abfd, buf, bytes_read_ptr)
char *buf;
unsigned int *bytes_read_ptr;
{
- /* If the size of a host char is 8 bits, we can return a pointer
- to the string, otherwise we have to copy the string to a buffer
- allocated on the temporary obstack. */
+ /* Return a pointer to the embedded string. */
if (*buf == '\0')
{
*bytes_read_ptr = 1;
@@ -266,6 +354,59 @@ read_string (abfd, buf, bytes_read_ptr)
return buf;
}
+static char *
+read_indirect_string (unit, buf, bytes_read_ptr)
+ struct comp_unit* unit;
+ char *buf;
+ unsigned int *bytes_read_ptr;
+{
+ bfd_vma offset;
+ struct dwarf2_debug *stash = unit->stash;
+
+ if (unit->offset_size == 4)
+ offset = read_4_bytes (unit->abfd, buf);
+ else
+ offset = read_8_bytes (unit->abfd, buf);
+ *bytes_read_ptr = unit->offset_size;
+
+ if (! stash->dwarf_str_buffer)
+ {
+ asection *msec;
+ bfd *abfd = unit->abfd;
+
+ msec = bfd_get_section_by_name (abfd, ".debug_str");
+ if (! msec)
+ {
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Can't find .debug_str section."));
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+
+ stash->dwarf_str_size = msec->_raw_size;
+ stash->dwarf_str_buffer = (char*) bfd_alloc (abfd, msec->_raw_size);
+ if (! stash->dwarf_abbrev_buffer)
+ return NULL;
+
+ if (! bfd_get_section_contents (abfd, msec, stash->dwarf_str_buffer,
+ (bfd_vma) 0, msec->_raw_size))
+ return NULL;
+ }
+
+ if (offset >= stash->dwarf_str_size)
+ {
+ (*_bfd_error_handler) (_("Dwarf Error: DW_FORM_strp offset (%u) greater than or equal to .debug_str size (%u)."),
+ offset, stash->dwarf_str_size );
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+
+ buf = stash->dwarf_str_buffer + offset;
+ if (*buf == '\0')
+ return NULL;
+ return buf;
+}
+
static unsigned int
read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
bfd *abfd ATTRIBUTE_UNUSED;
@@ -349,30 +490,6 @@ read_address (unit, buf)
}
}
-/* 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. */
-};
-
-struct attr_abbrev
-{
- enum dwarf_attribute name;
- enum dwarf_form form;
-};
-
-#ifndef ABBREV_HASH_SIZE
-#define ABBREV_HASH_SIZE 121
-#endif
-#ifndef ATTR_ALLOC_CHUNK
-#define ATTR_ALLOC_CHUNK 4
-#endif
-
/* Lookup an abbrev_info structure in the abbrev hash table. */
static struct abbrev_info *
@@ -413,6 +530,7 @@ read_abbrevs (abfd, offset, stash)
struct abbrev_info *cur_abbrev;
unsigned int abbrev_number, bytes_read, abbrev_name;
unsigned int abbrev_form, hash_number;
+ bfd_size_type amt;
if (! stash->dwarf_abbrev_buffer)
{
@@ -427,13 +545,12 @@ read_abbrevs (abfd, offset, stash)
}
stash->dwarf_abbrev_size = msec->_raw_size;
- stash->dwarf_abbrev_buffer = (char*) bfd_alloc (abfd, stash->dwarf_abbrev_size);
+ stash->dwarf_abbrev_buffer = (char*) bfd_alloc (abfd, msec->_raw_size);
if (! stash->dwarf_abbrev_buffer)
return 0;
- if (! bfd_get_section_contents (abfd, msec,
- stash->dwarf_abbrev_buffer, 0,
- stash->dwarf_abbrev_size))
+ if (! bfd_get_section_contents (abfd, msec, stash->dwarf_abbrev_buffer,
+ (bfd_vma) 0, msec->_raw_size))
return 0;
}
@@ -445,7 +562,8 @@ read_abbrevs (abfd, offset, stash)
return 0;
}
- abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE);
+ amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
+ abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, amt);
abbrev_ptr = stash->dwarf_abbrev_buffer + offset;
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
@@ -454,7 +572,8 @@ read_abbrevs (abfd, offset, stash)
/* Loop until we reach an abbrev number of 0. */
while (abbrev_number)
{
- cur_abbrev = (struct abbrev_info*)bfd_zalloc (abfd, sizeof (struct abbrev_info));
+ amt = sizeof (struct abbrev_info);
+ cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt);
/* Read in abbrev header. */
cur_abbrev->number = abbrev_number;
@@ -473,10 +592,10 @@ read_abbrevs (abfd, offset, stash)
{
if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0)
{
- cur_abbrev->attrs = (struct attr_abbrev *)
- bfd_realloc (cur_abbrev->attrs,
- (cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK)
- * sizeof (struct attr_abbrev));
+ amt = cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK;
+ amt *= sizeof (struct attr_abbrev);
+ cur_abbrev->attrs = ((struct attr_abbrev *)
+ bfd_realloc (cur_abbrev->attrs, amt));
if (! cur_abbrev->attrs)
return 0;
}
@@ -512,31 +631,33 @@ read_abbrevs (abfd, offset, stash)
return abbrevs;
}
-/* Read an attribute described by an abbreviated attribute. */
+/* Read an attribute value described by an attribute form. */
static char *
-read_attribute (attr, abbrev, unit, info_ptr)
+read_attribute_value (attr, form, unit, info_ptr)
struct attribute *attr;
- struct attr_abbrev *abbrev;
+ unsigned form;
struct comp_unit *unit;
char *info_ptr;
{
bfd *abfd = unit->abfd;
unsigned int bytes_read;
struct dwarf_block *blk;
+ bfd_size_type amt;
- attr->name = abbrev->name;
- attr->form = abbrev->form;
+ attr->form = form;
- switch (abbrev->form)
+ switch (form)
{
case DW_FORM_addr:
+ /* FIXME: DWARF3 draft sais DW_FORM_ref_addr is offset_size. */
case DW_FORM_ref_addr:
DW_ADDR (attr) = read_address (unit, info_ptr);
info_ptr += unit->addr_size;
break;
case DW_FORM_block2:
- blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+ amt = sizeof (struct dwarf_block);
+ blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
blk->size = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -544,7 +665,8 @@ read_attribute (attr, abbrev, unit, info_ptr)
DW_BLOCK (attr) = blk;
break;
case DW_FORM_block4:
- blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+ amt = sizeof (struct dwarf_block);
+ blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
blk->size = read_4_bytes (abfd, info_ptr);
info_ptr += 4;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -567,8 +689,13 @@ read_attribute (attr, abbrev, unit, info_ptr)
DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_strp:
+ DW_STRING (attr) = read_indirect_string (unit, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ break;
case DW_FORM_block:
- blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+ amt = sizeof (struct dwarf_block);
+ blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -576,7 +703,8 @@ read_attribute (attr, abbrev, unit, info_ptr)
DW_BLOCK (attr) = blk;
break;
case DW_FORM_block1:
- blk = (struct dwarf_block *) bfd_alloc (abfd, sizeof (struct dwarf_block));
+ amt = sizeof (struct dwarf_block);
+ blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
blk->size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
@@ -619,16 +747,33 @@ read_attribute (attr, abbrev, unit, info_ptr)
DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
- case DW_FORM_strp:
case DW_FORM_indirect:
+ form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ info_ptr = read_attribute_value (attr, form, unit, info_ptr);
+ break;
default:
(*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %d."),
- abbrev->form);
+ form);
bfd_set_error (bfd_error_bad_value);
}
return info_ptr;
}
+/* Read an attribute described by an abbreviated attribute. */
+
+static char *
+read_attribute (attr, abbrev, unit, info_ptr)
+ struct attribute *attr;
+ struct attr_abbrev *abbrev;
+ struct comp_unit *unit;
+ char *info_ptr;
+{
+ attr->name = abbrev->name;
+ info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr);
+ return info_ptr;
+}
+
/* Source line information table routines. */
#define FILE_ALLOC_CHUNK 5
@@ -672,8 +817,8 @@ add_line_info (table, address, filename, line, column, end_sequence)
unsigned int column;
int end_sequence;
{
- struct line_info* info = (struct line_info*)
- bfd_alloc (table->abfd, sizeof (struct line_info));
+ bfd_size_type amt = sizeof (struct line_info);
+ struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, amt);
info->prev_line = table->last_line;
table->last_line = info;
@@ -749,7 +894,7 @@ arange_add (unit, low_pc, high_pc)
}
/* Need to allocate a new arange and insert it into the arange list. */
- arange = bfd_zalloc (unit->abfd, sizeof (*arange));
+ arange = bfd_zalloc (unit->abfd, (bfd_size_type) sizeof (*arange));
arange->low = low_pc;
arange->high = high_pc;
@@ -769,9 +914,10 @@ decode_line_info (unit, stash)
char *line_ptr;
char *line_end;
struct line_head lh;
- unsigned int i, bytes_read;
+ unsigned int i, bytes_read, offset_size;
char *cur_file, *cur_dir;
unsigned char op_code, extended_op, adj_opcode;
+ bfd_size_type amt;
if (! stash->dwarf_line_buffer)
{
@@ -786,13 +932,12 @@ decode_line_info (unit, stash)
}
stash->dwarf_line_size = msec->_raw_size;
- stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, stash->dwarf_line_size);
+ stash->dwarf_line_buffer = (char *) bfd_alloc (abfd, msec->_raw_size);
if (! stash->dwarf_line_buffer)
return 0;
- if (! bfd_get_section_contents (abfd, msec,
- stash->dwarf_line_buffer, 0,
- stash->dwarf_line_size))
+ if (! bfd_get_section_contents (abfd, msec, stash->dwarf_line_buffer,
+ (bfd_vma) 0, msec->_raw_size))
return 0;
/* FIXME: We ought to apply the relocs against this section before
@@ -810,8 +955,8 @@ decode_line_info (unit, stash)
return 0;
}
- table = (struct line_info_table*) bfd_alloc (abfd,
- sizeof (struct line_info_table));
+ amt = sizeof (struct line_info_table);
+ table = (struct line_info_table*) bfd_alloc (abfd, amt);
table->abfd = abfd;
table->comp_dir = unit->comp_dir;
@@ -829,11 +974,21 @@ decode_line_info (unit, stash)
/* Read in the prologue. */
lh.total_length = read_4_bytes (abfd, line_ptr);
line_ptr += 4;
+ offset_size = 4;
+ if (lh.total_length == 0xffffffff)
+ {
+ lh.total_length = read_8_bytes (abfd, line_ptr);
+ line_ptr += 8;
+ offset_size = 8;
+ }
line_end = line_ptr + lh.total_length;
lh.version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
- lh.prologue_length = read_4_bytes (abfd, line_ptr);
- line_ptr += 4;
+ if (offset_size == 4)
+ lh.prologue_length = read_4_bytes (abfd, line_ptr);
+ else
+ lh.prologue_length = read_8_bytes (abfd, line_ptr);
+ line_ptr += offset_size;
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.default_is_stmt = read_1_byte (abfd, line_ptr);
@@ -844,8 +999,8 @@ decode_line_info (unit, stash)
line_ptr += 1;
lh.opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh.standard_opcode_lengths = (unsigned char *)
- bfd_alloc (abfd, lh.opcode_base * sizeof (unsigned char));
+ amt = lh.opcode_base * sizeof (unsigned char);
+ lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt);
lh.standard_opcode_lengths[0] = 1;
@@ -862,9 +1017,9 @@ decode_line_info (unit, stash)
if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0)
{
- table->dirs = (char **)
- bfd_realloc (table->dirs,
- (table->num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
+ amt = table->num_dirs + DIR_ALLOC_CHUNK;
+ amt *= sizeof (char *);
+ table->dirs = (char **) bfd_realloc (table->dirs, amt);
if (! table->dirs)
return 0;
}
@@ -881,10 +1036,9 @@ decode_line_info (unit, stash)
if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
{
- table->files = (struct fileinfo *)
- bfd_realloc (table->files,
- (table->num_files + FILE_ALLOC_CHUNK)
- * sizeof (struct fileinfo));
+ amt = table->num_files + FILE_ALLOC_CHUNK;
+ amt *= sizeof (struct fileinfo);
+ table->files = (struct fileinfo *) bfd_realloc (table->files, amt);
if (! table->files)
return 0;
}
@@ -923,7 +1077,22 @@ decode_line_info (unit, stash)
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- switch (op_code)
+ if (op_code >= lh.opcode_base)
+ { /* Special operand. */
+ adj_opcode = op_code - lh.opcode_base;
+ address += (adj_opcode / lh.line_range)
+ * lh.minimum_instruction_length;
+ line += lh.line_base + (adj_opcode % lh.line_range);
+ /* Append row to matrix using current values. */
+ add_line_info (table, address, filename, line, column, 0);
+ basic_block = 1;
+ if (need_low_pc)
+ {
+ need_low_pc = 0;
+ low_pc = address;
+ }
+ }
+ else switch (op_code)
{
case DW_LNS_extended_op:
line_ptr += 1; /* Ignore length. */
@@ -951,10 +1120,10 @@ decode_line_info (unit, stash)
line_ptr += bytes_read;
if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
{
- table->files = (struct fileinfo *)
- bfd_realloc (table->files,
- (table->num_files + FILE_ALLOC_CHUNK)
- * sizeof (struct fileinfo));
+ amt = table->num_files + FILE_ALLOC_CHUNK;
+ amt *= sizeof (struct fileinfo);
+ table->files =
+ (struct fileinfo *) bfd_realloc (table->files, amt);
if (! table->files)
return 0;
}
@@ -1023,19 +1192,15 @@ decode_line_info (unit, stash)
address += read_2_bytes (abfd, line_ptr);
line_ptr += 2;
break;
- default: /* Special operand. */
- adj_opcode = op_code - lh.opcode_base;
- address += (adj_opcode / lh.line_range)
- * lh.minimum_instruction_length;
- line += lh.line_base + (adj_opcode % lh.line_range);
- /* Append row to matrix using current values. */
- add_line_info (table, address, filename, line, column, 0);
- basic_block = 1;
- if (need_low_pc)
- {
- need_low_pc = 0;
- low_pc = address;
- }
+ default:
+ { /* Unknown standard opcode, ignore it. */
+ int i;
+ for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
+ {
+ (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+ }
+ }
}
}
}
@@ -1158,7 +1323,8 @@ scan_unit_for_functions (unit)
if (abbrev->tag == DW_TAG_subprogram)
{
- func = (struct funcinfo*) bfd_zalloc (abfd, sizeof (struct funcinfo));
+ bfd_size_type amt = sizeof (struct funcinfo);
+ func = (struct funcinfo *) bfd_zalloc (abfd, amt);
func->prev_func = unit->function_table;
unit->function_table = func;
}
@@ -1219,22 +1385,75 @@ scan_unit_for_functions (unit)
return true;
}
+/* Look for a RELA relocation to be applied on OFFSET of section SEC,
+ and return the addend if such a relocation is found. Since this is
+ only used to find relocations referring to the .debug_abbrev
+ section, we make sure the relocation refers to this section, but
+ this is not strictly necessary, and it can probably be safely
+ removed if needed. However, it is important to note that this
+ function only returns the addend, it doesn't serve the purpose of
+ applying a generic relocation.
+
+ If no suitable relocation is found, or if it is not a real RELA
+ relocation, this function returns 0. */
+
+static bfd_vma
+find_rela_addend (abfd, sec, offset, syms)
+ bfd* abfd;
+ asection* sec;
+ bfd_size_type offset;
+ asymbol** syms;
+{
+ long reloc_size = bfd_get_reloc_upper_bound (abfd, sec);
+ arelent **relocs = NULL;
+ long reloc_count, relc;
+
+ if (reloc_size <= 0)
+ return 0;
+
+ relocs = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
+ if (relocs == NULL)
+ return 0;
+
+ reloc_count = bfd_canonicalize_reloc (abfd, sec, relocs, syms);
+
+ if (reloc_count <= 0)
+ {
+ free (relocs);
+ return 0;
+ }
+
+ for (relc = 0; relc < reloc_count; relc++)
+ if (relocs[relc]->address == offset
+ && (*relocs[relc]->sym_ptr_ptr)->flags & BSF_SECTION_SYM
+ && strcmp ((*relocs[relc]->sym_ptr_ptr)->name,
+ ".debug_abbrev") == 0)
+ {
+ bfd_vma addend = (relocs[relc]->howto->partial_inplace
+ ? 0 : relocs[relc]->addend);
+ free (relocs);
+ return addend;
+ }
+
+ free (relocs);
+ return 0;
+}
+
/* Parse a DWARF2 compilation unit starting at INFO_PTR. This
includes the compilation unit header that proceeds the DIE's, but
does not include the length field that preceeds each compilation
unit header. END_PTR points one past the end of this comp unit.
- If ABBREV_LENGTH is 0, then the length of the abbreviation offset
- is assumed to be four bytes. Otherwise, it it is the size given.
+ OFFSET_SIZE is the size of DWARF2 offsets (either 4 or 8 bytes).
This routine does not read the whole compilation unit; only enough
to get to the line number information for the compilation unit. */
static struct comp_unit *
-parse_comp_unit (abfd, stash, unit_length, abbrev_length)
+parse_comp_unit (abfd, stash, unit_length, offset_size)
bfd* abfd;
struct dwarf2_debug *stash;
bfd_vma unit_length;
- unsigned int abbrev_length;
+ unsigned int offset_size;
{
struct comp_unit* unit;
@@ -1249,17 +1468,23 @@ parse_comp_unit (abfd, stash, unit_length, abbrev_length)
char *info_ptr = stash->info_ptr;
char *end_ptr = info_ptr + unit_length;
+ bfd_size_type amt;
+ bfd_size_type off;
version = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
- BFD_ASSERT (abbrev_length == 0
- || abbrev_length == 4
- || abbrev_length == 8);
- if (abbrev_length == 0 || abbrev_length == 4)
+ BFD_ASSERT (offset_size == 4 || offset_size == 8);
+ if (offset_size == 4)
abbrev_offset = read_4_bytes (abfd, info_ptr);
- else if (abbrev_length == 8)
+ else
abbrev_offset = read_8_bytes (abfd, info_ptr);
- info_ptr += abbrev_length;
+ /* The abbrev offset is generally a relocation pointing to
+ .debug_abbrev+offset. On RELA targets, we have to find the
+ relocation and extract the addend to obtain the actual
+ abbrev_offset, so do it here. */
+ off = info_ptr - stash->sec_info_ptr;
+ abbrev_offset += find_rela_addend (abfd, stash->sec, off, stash->syms);
+ info_ptr += offset_size;
addr_size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
@@ -1310,11 +1535,14 @@ parse_comp_unit (abfd, stash, unit_length, abbrev_length)
return 0;
}
- unit = (struct comp_unit*) bfd_zalloc (abfd, sizeof (struct comp_unit));
+ amt = sizeof (struct comp_unit);
+ unit = (struct comp_unit*) bfd_zalloc (abfd, amt);
unit->abfd = abfd;
unit->addr_size = addr_size;
+ unit->offset_size = offset_size;
unit->abbrevs = abbrevs;
unit->end_ptr = end_ptr;
+ unit->stash = stash;
for (i = 0; i < abbrev->num_attrs; ++i)
{
@@ -1499,7 +1727,7 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
addr_size, pinfo)
bfd *abfd;
asection *section;
- asymbol **symbols ATTRIBUTE_UNUSED;
+ asymbol **symbols;
bfd_vma offset;
const char **filename_ptr;
const char **functionname_ptr;
@@ -1535,11 +1763,11 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
if (! stash)
{
- unsigned long total_size;
+ bfd_size_type total_size;
asection *msec;
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
- stash =
- (struct dwarf2_debug*) bfd_zalloc (abfd, sizeof (struct dwarf2_debug));
+ stash = (struct dwarf2_debug*) bfd_zalloc (abfd, amt);
if (! stash)
return false;
@@ -1570,8 +1798,8 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
msec;
msec = find_debug_info (abfd, msec))
{
- unsigned long size;
- unsigned long start;
+ bfd_size_type size;
+ bfd_size_type start;
size = msec->_raw_size;
if (size == 0)
@@ -1579,13 +1807,18 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
start = stash->info_ptr_end - stash->info_ptr;
- if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start, 0, size))
+ if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start,
+ (bfd_vma) 0, size))
continue;
stash->info_ptr_end = stash->info_ptr + start + size;
}
- BFD_ASSERT (stash->info_ptr_end = stash->info_ptr + total_size);
+ BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size);
+
+ stash->sec = find_debug_info (abfd, NULL);
+ stash->sec_info_ptr = stash->info_ptr;
+ stash->syms = symbols;
}
/* FIXME: There is a problem with the contents of the
@@ -1618,21 +1851,36 @@ _bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
/* Read each remaining comp. units checking each as they are read. */
while (stash->info_ptr < stash->info_ptr_end)
{
- struct comp_unit* each;
bfd_vma length;
boolean found;
+ unsigned int offset_size = addr_size;
if (addr_size == 4)
- length = read_4_bytes (abfd, stash->info_ptr);
+ {
+ length = read_4_bytes (abfd, stash->info_ptr);
+ if (length == 0xffffffff)
+ {
+ offset_size = 8;
+ length = read_8_bytes (abfd, stash->info_ptr + 4);
+ stash->info_ptr += 8;
+ }
+ }
else
length = read_8_bytes (abfd, stash->info_ptr);
stash->info_ptr += addr_size;
if (length > 0)
{
- each = parse_comp_unit (abfd, stash, length, addr_size);
+ each = parse_comp_unit (abfd, stash, length, offset_size);
stash->info_ptr += length;
+ if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
+ == stash->sec->_raw_size)
+ {
+ stash->sec = find_debug_info (abfd, stash->sec);
+ stash->sec_info_ptr = stash->info_ptr;
+ }
+
if (each)
{
each->next_unit = stash->all_comp_units;
OpenPOWER on IntegriCloud