1,5 → 1,5 |
/* DWARF 2 support. |
Copyright 1994-2013 Free Software Foundation, Inc. |
Copyright (C) 1994-2015 Free Software Foundation, Inc. |
|
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions |
(gavin@cygnus.com). |
156,8 → 156,11 |
use. */ |
struct funcinfo *inliner_chain; |
|
/* Section VMAs at the time the stash was built. */ |
bfd_vma *sec_vma; |
|
/* Number of sections whose VMA we must adjust. */ |
unsigned int adjusted_section_count; |
int adjusted_section_count; |
|
/* Array of sections with adjusted VMA. */ |
struct adjusted_section *adjusted_sections; |
219,6 → 222,9 |
/* The abbrev hash table. */ |
struct abbrev_info **abbrevs; |
|
/* DW_AT_language. */ |
int lang; |
|
/* Note that an error was found by comp_unit_find_nearest_line. */ |
int error; |
|
550,39 → 556,45 |
return TRUE; |
} |
|
/* VERBATIM |
The following function up to the END VERBATIM mark are |
copied directly from dwarf2read.c. */ |
|
/* Read dwarf information from a buffer. */ |
|
static unsigned int |
read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) |
read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) |
{ |
if (buf + 1 > end) |
return 0; |
return bfd_get_8 (abfd, buf); |
} |
|
static int |
read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf) |
read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) |
{ |
if (buf + 1 > end) |
return 0; |
return bfd_get_signed_8 (abfd, buf); |
} |
|
static unsigned int |
read_2_bytes (bfd *abfd, bfd_byte *buf) |
read_2_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) |
{ |
if (buf + 2 > end) |
return 0; |
return bfd_get_16 (abfd, buf); |
} |
|
static unsigned int |
read_4_bytes (bfd *abfd, bfd_byte *buf) |
read_4_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) |
{ |
if (buf + 4 > end) |
return 0; |
return bfd_get_32 (abfd, buf); |
} |
|
static bfd_uint64_t |
read_8_bytes (bfd *abfd, bfd_byte *buf) |
read_8_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) |
{ |
if (buf + 8 > end) |
return 0; |
return bfd_get_64 (abfd, buf); |
} |
|
589,19 → 601,34 |
static bfd_byte * |
read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
bfd_byte *end, |
unsigned int size ATTRIBUTE_UNUSED) |
{ |
if (buf + size > end) |
return NULL; |
return buf; |
} |
|
/* 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. */ |
|
static char * |
read_string (bfd *abfd ATTRIBUTE_UNUSED, |
bfd_byte *buf, |
bfd_byte * buf_end, |
unsigned int *bytes_read_ptr) |
{ |
/* Return a pointer to the embedded string. */ |
char *str = (char *) buf; |
bfd_byte *str = buf; |
|
if (buf >= buf_end) |
{ |
* bytes_read_ptr = 0; |
return NULL; |
} |
|
if (*str == '\0') |
{ |
*bytes_read_ptr = 1; |
608,15 → 635,29 |
return NULL; |
} |
|
*bytes_read_ptr = strlen (str) + 1; |
return str; |
while (buf < buf_end) |
if (* buf ++ == 0) |
{ |
* bytes_read_ptr = buf - str; |
return (char *) str; |
} |
|
/* END VERBATIM */ |
* bytes_read_ptr = buf - str; |
return NULL; |
} |
|
/* Reads an offset from BUF 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. */ |
|
static char * |
read_indirect_string (struct comp_unit * unit, |
bfd_byte * buf, |
bfd_byte * buf_end, |
unsigned int * bytes_read_ptr) |
{ |
bfd_uint64_t offset; |
623,10 → 664,16 |
struct dwarf2_debug *stash = unit->stash; |
char *str; |
|
if (buf + unit->offset_size > buf_end) |
{ |
* bytes_read_ptr = 0; |
return NULL; |
} |
|
if (unit->offset_size == 4) |
offset = read_4_bytes (unit->abfd, buf); |
offset = read_4_bytes (unit->abfd, buf, buf_end); |
else |
offset = read_8_bytes (unit->abfd, buf); |
offset = read_8_bytes (unit->abfd, buf, buf_end); |
|
*bytes_read_ptr = unit->offset_size; |
|
635,6 → 682,8 |
&stash->dwarf_str_buffer, &stash->dwarf_str_size)) |
return NULL; |
|
if (offset >= stash->dwarf_str_size) |
return NULL; |
str = (char *) stash->dwarf_str_buffer + offset; |
if (*str == '\0') |
return NULL; |
642,12 → 691,13 |
} |
|
/* Like read_indirect_string but uses a .debug_str located in |
an alternate filepointed to by the .gnu_debuglink section. |
an alternate file pointed to by the .gnu_debugaltlink section. |
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) |
{ |
bfd_uint64_t offset; |
654,10 → 704,16 |
struct dwarf2_debug *stash = unit->stash; |
char *str; |
|
if (buf + unit->offset_size > buf_end) |
{ |
* bytes_read_ptr = 0; |
return NULL; |
} |
|
if (unit->offset_size == 4) |
offset = read_4_bytes (unit->abfd, buf); |
offset = read_4_bytes (unit->abfd, buf, buf_end); |
else |
offset = read_8_bytes (unit->abfd, buf); |
offset = read_8_bytes (unit->abfd, buf, buf_end); |
|
*bytes_read_ptr = unit->offset_size; |
|
690,6 → 746,8 |
&stash->alt_dwarf_str_size)) |
return NULL; |
|
if (offset >= stash->alt_dwarf_str_size) |
return NULL; |
str = (char *) stash->alt_dwarf_str_buffer + offset; |
if (*str == '\0') |
return NULL; |
736,14 → 794,22 |
&stash->alt_dwarf_info_size)) |
return NULL; |
|
if (offset >= stash->alt_dwarf_info_size) |
return NULL; |
return stash->alt_dwarf_info_buffer + offset; |
} |
|
static bfd_uint64_t |
read_address (struct comp_unit *unit, bfd_byte *buf) |
read_address (struct comp_unit *unit, bfd_byte *buf, bfd_byte * buf_end) |
{ |
int signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; |
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 (signed_vma) |
{ |
switch (unit->addr_size) |
806,6 → 872,7 |
{ |
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_form, hash_number; |
816,6 → 883,9 |
&stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size)) |
return NULL; |
|
if (offset >= stash->dwarf_abbrev_size) |
return NULL; |
|
amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; |
abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt); |
if (abbrevs == NULL) |
822,7 → 892,8 |
return NULL; |
|
abbrev_ptr = stash->dwarf_abbrev_buffer + offset; |
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_end = stash->dwarf_abbrev_buffer + stash->dwarf_abbrev_size; |
abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
|
/* Loop until we reach an abbrev number of 0. */ |
836,15 → 907,15 |
/* Read in abbrev header. */ |
cur_abbrev->number = abbrev_number; |
cur_abbrev->tag = (enum dwarf_tag) |
read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
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); |
cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr, abbrev_end); |
abbrev_ptr += 1; |
|
/* Now read in declarations. */ |
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
|
while (abbrev_name) |
879,9 → 950,9 |
= (enum dwarf_attribute) abbrev_name; |
cur_abbrev->attrs[cur_abbrev->num_attrs++].form |
= (enum dwarf_form) abbrev_form; |
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
} |
|
899,7 → 970,7 |
if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer) |
>= stash->dwarf_abbrev_size) |
break; |
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); |
abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end); |
abbrev_ptr += bytes_read; |
if (lookup_abbrev (abbrev_number,abbrevs) != NULL) |
break; |
908,13 → 979,24 |
return abbrevs; |
} |
|
/* Read an attribute value described by an attribute form. */ |
/* Returns true if the form is one which has a string value. */ |
|
static inline bfd_boolean |
is_str_attr (enum dwarf_form form) |
{ |
return form == DW_FORM_string || form == DW_FORM_strp || form == DW_FORM_GNU_strp_alt; |
} |
|
/* Read and fill in the value of attribute ATTR as described by FORM. |
Read data starting from INFO_PTR, but never at or beyond INFO_PTR_END. |
Returns an updated INFO_PTR taking into account the amount of data read. */ |
|
static bfd_byte * |
read_attribute_value (struct attribute *attr, |
unsigned form, |
struct comp_unit *unit, |
bfd_byte *info_ptr) |
bfd_byte * info_ptr, |
bfd_byte * info_ptr_end) |
{ |
bfd *abfd = unit->abfd; |
unsigned int bytes_read; |
921,6 → 1003,13 |
struct dwarf_block *blk; |
bfd_size_type amt; |
|
if (info_ptr >= info_ptr_end) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Info pointer extends beyond end of attributes")); |
bfd_set_error (bfd_error_bad_value); |
return info_ptr; |
} |
|
attr->form = (enum dwarf_form) form; |
|
switch (form) |
931,23 → 1020,23 |
if (unit->version == 3 || unit->version == 4) |
{ |
if (unit->offset_size == 4) |
attr->u.val = read_4_bytes (unit->abfd, info_ptr); |
attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); |
else |
attr->u.val = read_8_bytes (unit->abfd, info_ptr); |
attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); |
info_ptr += unit->offset_size; |
break; |
} |
/* FALLTHROUGH */ |
case DW_FORM_addr: |
attr->u.val = read_address (unit, info_ptr); |
attr->u.val = read_address (unit, info_ptr, info_ptr_end); |
info_ptr += unit->addr_size; |
break; |
case DW_FORM_GNU_ref_alt: |
case DW_FORM_sec_offset: |
if (unit->offset_size == 4) |
attr->u.val = read_4_bytes (unit->abfd, info_ptr); |
attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); |
else |
attr->u.val = read_8_bytes (unit->abfd, info_ptr); |
attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); |
info_ptr += unit->offset_size; |
break; |
case DW_FORM_block2: |
955,9 → 1044,9 |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_2_bytes (abfd, info_ptr); |
blk->size = read_2_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 2; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
966,34 → 1055,34 |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_4_bytes (abfd, info_ptr); |
blk->size = read_4_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 4; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_data2: |
attr->u.val = read_2_bytes (abfd, info_ptr); |
attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 2; |
break; |
case DW_FORM_data4: |
attr->u.val = read_4_bytes (abfd, info_ptr); |
attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 4; |
break; |
case DW_FORM_data8: |
attr->u.val = read_8_bytes (abfd, info_ptr); |
attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 8; |
break; |
case DW_FORM_string: |
attr->u.str = read_string (abfd, info_ptr, &bytes_read); |
attr->u.str = read_string (abfd, info_ptr, info_ptr_end, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_strp: |
attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read); |
attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_GNU_strp_alt: |
attr->u.str = read_alt_indirect_string (unit, info_ptr, &bytes_read); |
attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); |
info_ptr += bytes_read; |
break; |
case DW_FORM_exprloc: |
1002,9 → 1091,9 |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
blk->size = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); |
info_ptr += bytes_read; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
1013,18 → 1102,18 |
blk = (struct dwarf_block *) bfd_alloc (abfd, amt); |
if (blk == NULL) |
return NULL; |
blk->size = read_1_byte (abfd, info_ptr); |
blk->size = read_1_byte (abfd, info_ptr, info_ptr_end); |
info_ptr += 1; |
blk->data = read_n_bytes (abfd, info_ptr, blk->size); |
blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); |
info_ptr += blk->size; |
attr->u.blk = blk; |
break; |
case DW_FORM_data1: |
attr->u.val = read_1_byte (abfd, info_ptr); |
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); |
attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); |
info_ptr += 1; |
break; |
case DW_FORM_flag_present: |
1031,41 → 1120,41 |
attr->u.val = 1; |
break; |
case DW_FORM_sdata: |
attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read); |
attr->u.sval = safe_read_leb128 (abfd, info_ptr, &bytes_read, TRUE, info_ptr_end); |
info_ptr += bytes_read; |
break; |
case DW_FORM_udata: |
attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
attr->u.val = 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); |
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); |
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); |
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); |
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); |
attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); |
info_ptr += 8; |
break; |
case DW_FORM_ref_udata: |
attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
attr->u.val = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); |
info_ptr += bytes_read; |
break; |
case DW_FORM_indirect: |
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
form = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); |
info_ptr += bytes_read; |
info_ptr = read_attribute_value (attr, form, unit, info_ptr); |
info_ptr = read_attribute_value (attr, form, unit, info_ptr, info_ptr_end); |
break; |
default: |
(*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), |
1082,13 → 1171,41 |
read_attribute (struct attribute *attr, |
struct attr_abbrev *abbrev, |
struct comp_unit *unit, |
bfd_byte *info_ptr) |
bfd_byte * info_ptr, |
bfd_byte * info_ptr_end) |
{ |
attr->name = abbrev->name; |
info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr); |
info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, info_ptr_end); |
return info_ptr; |
} |
|
/* Return whether DW_AT_name will return the same as DW_AT_linkage_name |
for a function. */ |
|
static bfd_boolean |
non_mangled (int lang) |
{ |
switch (lang) |
{ |
default: |
return FALSE; |
|
case DW_LANG_C89: |
case DW_LANG_C: |
case DW_LANG_Ada83: |
case DW_LANG_Cobol74: |
case DW_LANG_Cobol85: |
case DW_LANG_Fortran77: |
case DW_LANG_Pascal83: |
case DW_LANG_C99: |
case DW_LANG_Ada95: |
case DW_LANG_PLI: |
case DW_LANG_UPC: |
case DW_LANG_C11: |
return TRUE; |
} |
} |
|
/* Source line information table routines. */ |
|
#define FILE_ALLOC_CHUNK 5 |
1147,14 → 1264,15 |
struct funcinfo *caller_func; |
/* Source location file name where caller_func inlines this func. */ |
char *caller_file; |
/* Source location file name. */ |
char *file; |
/* Source location line number where caller_func inlines this func. */ |
int caller_line; |
/* Source location file name. */ |
char *file; |
/* Source location line number. */ |
int line; |
int tag; |
char *name; |
bfd_boolean is_linkage; |
const char *name; |
struct arange arange; |
/* Where the symbol is defined. */ |
asection *sec; |
1342,7 → 1460,11 |
char *name; |
size_t len; |
|
if (table->files[file - 1].dir) |
if (table->files[file - 1].dir |
/* PR 17512: file: 0317e960. */ |
&& table->files[file - 1].dir <= table->num_dirs |
/* PR 17512: file: 7f3d2e4b. */ |
&& table->dirs != NULL) |
subdir_name = table->dirs[table->files[file - 1].dir - 1]; |
|
if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) |
1563,15 → 1685,24 |
|
table->lcl_head = NULL; |
|
if (stash->dwarf_line_size < 16) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Line info section is too small (%ld)"), |
(long) stash->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; |
|
/* Read in the prologue. */ |
lh.total_length = read_4_bytes (abfd, line_ptr); |
lh.total_length = read_4_bytes (abfd, line_ptr, line_end); |
line_ptr += 4; |
offset_size = 4; |
if (lh.total_length == 0xffffffff) |
{ |
lh.total_length = read_8_bytes (abfd, line_ptr); |
lh.total_length = read_8_bytes (abfd, line_ptr, line_end); |
line_ptr += 8; |
offset_size = 8; |
} |
1578,12 → 1709,23 |
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); |
lh.total_length = read_4_bytes (abfd, line_ptr, line_end); |
line_ptr += 4; |
offset_size = 8; |
} |
|
if (lh.total_length > stash->dwarf_line_size) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Line info data is bigger (0x%lx) than the section (0x%lx)"), |
(long) lh.total_length, (long) stash->dwarf_line_size); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
|
line_end = line_ptr + lh.total_length; |
lh.version = read_2_bytes (abfd, line_ptr); |
|
lh.version = read_2_bytes (abfd, line_ptr, line_end); |
if (lh.version < 2 || lh.version > 4) |
{ |
(*_bfd_error_handler) |
1592,20 → 1734,32 |
return NULL; |
} |
line_ptr += 2; |
|
if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: Ran out of room reading prologue")); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
|
if (offset_size == 4) |
lh.prologue_length = read_4_bytes (abfd, line_ptr); |
lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end); |
else |
lh.prologue_length = read_8_bytes (abfd, line_ptr); |
lh.prologue_length = read_8_bytes (abfd, line_ptr, line_end); |
line_ptr += offset_size; |
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); |
|
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
|
if (lh.version >= 4) |
{ |
lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr); |
lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
} |
else |
lh.maximum_ops_per_insn = 1; |
|
if (lh.maximum_ops_per_insn == 0) |
{ |
(*_bfd_error_handler) |
1613,14 → 1767,26 |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
lh.default_is_stmt = read_1_byte (abfd, line_ptr); |
|
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); |
|
lh.line_base = read_1_signed_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
lh.line_range = read_1_byte (abfd, line_ptr); |
|
lh.line_range = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
lh.opcode_base = read_1_byte (abfd, line_ptr); |
|
lh.opcode_base = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
|
if (line_ptr + (lh.opcode_base - 1) >= line_end) |
{ |
(*_bfd_error_handler) (_("Dwarf Error: Ran out of room reading opcodes")); |
bfd_set_error (bfd_error_bad_value); |
return NULL; |
} |
|
amt = lh.opcode_base * sizeof (unsigned char); |
lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt); |
|
1628,12 → 1794,12 |
|
for (i = 1; i < lh.opcode_base; ++i) |
{ |
lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); |
lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
} |
|
/* Read directory table. */ |
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) |
while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) |
{ |
line_ptr += bytes_read; |
|
1656,7 → 1822,7 |
line_ptr += bytes_read; |
|
/* Read file name table. */ |
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) |
while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) |
{ |
line_ptr += bytes_read; |
|
1675,13 → 1841,11 |
|
table->files[table->num_files].name = cur_file; |
table->files[table->num_files].dir = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->files[table->num_files].time = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
table->files[table->num_files].time = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->files[table->num_files].size = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
table->files[table->num_files].size = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->num_files++; |
} |
1711,7 → 1875,7 |
/* Decode the table. */ |
while (! end_sequence) |
{ |
op_code = read_1_byte (abfd, line_ptr); |
op_code = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
|
if (op_code >= lh.opcode_base) |
1718,6 → 1882,8 |
{ |
/* Special operand. */ |
adj_opcode = op_code - lh.opcode_base; |
if (lh.line_range == 0) |
goto line_fail; |
if (lh.maximum_ops_per_insn == 1) |
address += (adj_opcode / lh.line_range |
* lh.minimum_instruction_length); |
1743,9 → 1909,9 |
else switch (op_code) |
{ |
case DW_LNS_extended_op: |
exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
exop_len = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
extended_op = read_1_byte (abfd, line_ptr); |
extended_op = read_1_byte (abfd, line_ptr, line_end); |
line_ptr += 1; |
|
switch (extended_op) |
1764,12 → 1930,12 |
goto line_fail; |
break; |
case DW_LNE_set_address: |
address = read_address (unit, line_ptr); |
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, &bytes_read); |
cur_file = read_string (abfd, line_ptr, line_end, &bytes_read); |
line_ptr += bytes_read; |
if ((table->num_files % FILE_ALLOC_CHUNK) == 0) |
{ |
1784,19 → 1950,19 |
} |
table->files[table->num_files].name = cur_file; |
table->files[table->num_files].dir = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->files[table->num_files].time = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->files[table->num_files].size = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
table->num_files++; |
break; |
case DW_LNE_set_discriminator: |
discriminator = |
read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
break; |
case DW_LNE_HP_source_file_correlation: |
1825,12 → 1991,12 |
case DW_LNS_advance_pc: |
if (lh.maximum_ops_per_insn == 1) |
address += (lh.minimum_instruction_length |
* read_unsigned_leb128 (abfd, line_ptr, |
&bytes_read)); |
* safe_read_leb128 (abfd, line_ptr, &bytes_read, |
FALSE, line_end)); |
else |
{ |
bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr, |
&bytes_read); |
bfd_vma adjust = safe_read_leb128 (abfd, line_ptr, &bytes_read, |
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; |
1838,7 → 2004,7 |
line_ptr += bytes_read; |
break; |
case DW_LNS_advance_line: |
line += read_signed_leb128 (abfd, line_ptr, &bytes_read); |
line += safe_read_leb128 (abfd, line_ptr, &bytes_read, TRUE, line_end); |
line_ptr += bytes_read; |
break; |
case DW_LNS_set_file: |
1847,7 → 2013,7 |
|
/* The file and directory tables are 0 |
based, the references are 1 based. */ |
file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
file = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
if (filename) |
free (filename); |
1855,7 → 2021,7 |
break; |
} |
case DW_LNS_set_column: |
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
column = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
break; |
case DW_LNS_negate_stmt: |
1877,7 → 2043,7 |
} |
break; |
case DW_LNS_fixed_advance_pc: |
address += read_2_bytes (abfd, line_ptr); |
address += read_2_bytes (abfd, line_ptr, line_end); |
op_index = 0; |
line_ptr += 2; |
break; |
1885,7 → 2051,7 |
/* Unknown standard opcode, ignore it. */ |
for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++) |
{ |
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); |
(void) safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); |
line_ptr += bytes_read; |
} |
break; |
1909,11 → 2075,13 |
return NULL; |
} |
|
/* If ADDR is within TABLE set the output parameters and return TRUE, |
otherwise return FALSE. The output parameters, FILENAME_PTR and |
LINENUMBER_PTR, are pointers to the objects to be filled in. */ |
/* If ADDR is within TABLE set the output parameters and return the |
range of addresses covered by the entry used to fill them out. |
Otherwise set * FILENAME_PTR to NULL and return 0. |
The parameters FILENAME_PTR, LINENUMBER_PTR and DISCRIMINATOR_PTR |
are pointers to the objects to be filled in. */ |
|
static bfd_boolean |
static bfd_vma |
lookup_address_in_line_info_table (struct line_info_table *table, |
bfd_vma addr, |
const char **filename_ptr, |
1955,12 → 2123,12 |
*linenumber_ptr = each_line->line; |
if (discriminator_ptr) |
*discriminator_ptr = each_line->discriminator; |
return TRUE; |
return seq->last_line->address - seq->low_pc; |
} |
} |
|
*filename_ptr = NULL; |
return FALSE; |
return 0; |
} |
|
/* Read in the .debug_ranges section for future reference. */ |
1976,19 → 2144,19 |
|
/* Function table functions. */ |
|
/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE. |
Note that we need to find the function that has the smallest |
range that contains ADDR, to handle inlined functions without |
depending upon them being ordered in TABLE by increasing range. */ |
/* If ADDR is within UNIT's function tables, set FUNCTION_PTR, and return |
TRUE. Note that we need to find the function that has the smallest range |
that contains ADDR, to handle inlined functions without depending upon |
them being ordered in TABLE by increasing range. */ |
|
static bfd_boolean |
lookup_address_in_function_table (struct comp_unit *unit, |
bfd_vma addr, |
struct funcinfo **function_ptr, |
const char **functionname_ptr) |
struct funcinfo **function_ptr) |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
bfd_vma best_fit_len = 0; |
struct arange *arange; |
|
for (each_func = unit->function_table; |
2002,24 → 2170,22 |
if (addr >= arange->low && addr < arange->high) |
{ |
if (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low)) |
|| arange->high - arange->low < best_fit_len) |
{ |
best_fit = each_func; |
best_fit_len = arange->high - arange->low; |
} |
} |
} |
} |
|
if (best_fit) |
{ |
*functionname_ptr = best_fit->name; |
*function_ptr = best_fit; |
return TRUE; |
} |
else |
{ |
return FALSE; |
} |
} |
|
/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR |
and LINENUMBER_PTR, and return TRUE. */ |
2033,6 → 2199,7 |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
bfd_vma best_fit_len = 0; |
struct arange *arange; |
const char *name = bfd_asymbol_name (sym); |
asection *sec = bfd_get_section (sym); |
2051,11 → 2218,13 |
&& each_func->name |
&& strcmp (name, each_func->name) == 0 |
&& (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low))) |
|| arange->high - arange->low < best_fit_len)) |
{ |
best_fit = each_func; |
best_fit_len = arange->high - arange->low; |
} |
} |
} |
|
if (best_fit) |
{ |
2106,10 → 2275,12 |
|
static char * |
find_abstract_instance_name (struct comp_unit *unit, |
struct attribute *attr_ptr) |
struct attribute *attr_ptr, |
bfd_boolean *is_linkage) |
{ |
bfd *abfd = unit->abfd; |
bfd_byte *info_ptr; |
bfd_byte *info_ptr_end; |
unsigned int abbrev_number, bytes_read, i; |
struct abbrev_info *abbrev; |
bfd_uint64_t die_ref = attr_ptr->u.val; |
2126,7 → 2297,30 |
abort (); |
|
info_ptr = unit->sec_info_ptr + die_ref; |
info_ptr_end = unit->end_ptr; |
|
/* Now find the CU containing this pointer. */ |
if (info_ptr >= unit->info_ptr_unit && info_ptr < unit->end_ptr) |
; |
else |
{ |
/* Check other CUs to see if they contain the abbrev. */ |
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) |
break; |
|
if (u == NULL) |
for (u = unit->next_unit; u != NULL; u = u->next_unit) |
if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr) |
break; |
|
if (u) |
unit = u; |
/* else FIXME: What do we do now ? */ |
} |
} |
else if (attr_ptr->form == DW_FORM_GNU_ref_alt) |
{ |
info_ptr = read_alt_indirect_ref (unit, die_ref); |
2135,13 → 2329,20 |
(*_bfd_error_handler) |
(_("Dwarf Error: Unable to read alt ref %u."), die_ref); |
bfd_set_error (bfd_error_bad_value); |
return name; |
return NULL; |
} |
info_ptr_end = unit->stash->alt_dwarf_info_buffer + unit->stash->alt_dwarf_info_size; |
|
/* FIXME: Do we need to locate the correct CU, in a similar |
fashion to the code in the DW_FORM_ref_addr case above ? */ |
} |
else |
{ |
info_ptr = unit->info_ptr_unit + die_ref; |
info_ptr_end = unit->end_ptr; |
} |
|
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); |
info_ptr += bytes_read; |
|
if (abbrev_number) |
2158,7 → 2359,7 |
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, |
info_ptr); |
info_ptr, info_ptr_end); |
if (info_ptr == NULL) |
break; |
switch (attr.name) |
2166,15 → 2367,25 |
case DW_AT_name: |
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name |
over DW_AT_name. */ |
if (name == NULL) |
if (name == NULL && is_str_attr (attr.form)) |
{ |
name = attr.u.str; |
if (non_mangled (unit->lang)) |
*is_linkage = TRUE; |
} |
break; |
case DW_AT_specification: |
name = find_abstract_instance_name (unit, &attr); |
name = find_abstract_instance_name (unit, &attr, is_linkage); |
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)) |
{ |
name = attr.u.str; |
*is_linkage = TRUE; |
} |
break; |
default: |
break; |
2190,6 → 2401,7 |
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) |
2197,7 → 2409,11 |
if (! read_debug_ranges (unit)) |
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; |
|
for (;;) |
{ |
2204,9 → 2420,13 |
bfd_vma low_pc; |
bfd_vma high_pc; |
|
low_pc = read_address (unit, ranges_ptr); |
/* PR 17512: file: 62cada7d. */ |
if (ranges_ptr + 2 * unit->addr_size > ranges_end) |
return FALSE; |
|
low_pc = read_address (unit, ranges_ptr, ranges_end); |
ranges_ptr += unit->addr_size; |
high_pc = read_address (unit, ranges_ptr); |
high_pc = read_address (unit, ranges_ptr, ranges_end); |
ranges_ptr += unit->addr_size; |
|
if (low_pc == 0 && high_pc == 0) |
2233,6 → 2453,7 |
{ |
bfd *abfd = unit->abfd; |
bfd_byte *info_ptr = unit->first_child_die_ptr; |
bfd_byte *info_ptr_end = unit->stash->info_ptr_end; |
int nesting_level = 1; |
struct funcinfo **nested_funcs; |
int nested_funcs_size; |
2257,7 → 2478,11 |
bfd_vma high_pc = 0; |
bfd_boolean high_pc_relative = FALSE; |
|
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
/* PR 17512: file: 9f405d9d. */ |
if (info_ptr >= info_ptr_end) |
goto fail; |
|
abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end); |
info_ptr += bytes_read; |
|
if (! abbrev_number) |
2321,7 → 2546,7 |
|
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, info_ptr_end); |
if (info_ptr == NULL) |
goto fail; |
|
2340,19 → 2565,30 |
|
case DW_AT_abstract_origin: |
case DW_AT_specification: |
func->name = find_abstract_instance_name (unit, &attr); |
func->name = find_abstract_instance_name (unit, &attr, |
&func->is_linkage); |
break; |
|
case DW_AT_name: |
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name |
over DW_AT_name. */ |
if (func->name == NULL) |
if (func->name == NULL && is_str_attr (attr.form)) |
{ |
func->name = attr.u.str; |
if (non_mangled (unit->lang)) |
func->is_linkage = TRUE; |
} |
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)) |
{ |
func->name = attr.u.str; |
func->is_linkage = TRUE; |
} |
break; |
|
case DW_AT_low_pc: |
2508,15 → 2744,15 |
bfd *abfd = stash->bfd_ptr; |
bfd_boolean high_pc_relative = FALSE; |
|
version = read_2_bytes (abfd, info_ptr); |
version = read_2_bytes (abfd, info_ptr, end_ptr); |
info_ptr += 2; |
BFD_ASSERT (offset_size == 4 || offset_size == 8); |
if (offset_size == 4) |
abbrev_offset = read_4_bytes (abfd, info_ptr); |
abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr); |
else |
abbrev_offset = read_8_bytes (abfd, info_ptr); |
abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr); |
info_ptr += offset_size; |
addr_size = read_1_byte (abfd, info_ptr); |
addr_size = read_1_byte (abfd, info_ptr, end_ptr); |
info_ptr += 1; |
|
if (version != 2 && version != 3 && version != 4) |
2553,7 → 2789,7 |
if (! abbrevs) |
return 0; |
|
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); |
abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, end_ptr); |
info_ptr += bytes_read; |
if (! abbrev_number) |
{ |
2588,7 → 2824,7 |
|
for (i = 0; i < abbrev->num_attrs; ++i) |
{ |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); |
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr); |
if (info_ptr == NULL) |
return NULL; |
|
2627,6 → 2863,15 |
case DW_AT_comp_dir: |
{ |
char *comp_dir = attr.u.str; |
|
/* PR 17512: file: 1fe726be. */ |
if (! is_str_attr (attr.form)) |
{ |
(*_bfd_error_handler) |
(_("Dwarf Error: DW_AT_comp_dir attribute encountered with a non-string form.")); |
comp_dir = NULL; |
} |
|
if (comp_dir) |
{ |
/* Irix 6.2 native cc prepends <machine>.: to the compilation |
2640,6 → 2885,10 |
break; |
} |
|
case DW_AT_language: |
unit->lang = attr.u.val; |
break; |
|
default: |
break; |
} |
2684,24 → 2933,22 |
|
/* If UNIT contains ADDR, set the output parameters to the values for |
the line containing ADDR. The output parameters, FILENAME_PTR, |
FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects |
FUNCTION_PTR, and LINENUMBER_PTR, are pointers to the objects |
to be filled in. |
|
Return TRUE if UNIT contains ADDR, and no errors were encountered; |
FALSE otherwise. */ |
Returns the range of addresses covered by the entry that was used |
to fill in *LINENUMBER_PTR or 0 if it was not filled in. */ |
|
static bfd_boolean |
static bfd_vma |
comp_unit_find_nearest_line (struct comp_unit *unit, |
bfd_vma addr, |
const char **filename_ptr, |
const char **functionname_ptr, |
struct funcinfo **function_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
struct dwarf2_debug *stash) |
{ |
bfd_boolean line_p; |
bfd_boolean func_p; |
struct funcinfo *function; |
|
if (unit->error) |
return FALSE; |
2730,16 → 2977,15 |
} |
} |
|
function = NULL; |
func_p = lookup_address_in_function_table (unit, addr, |
&function, functionname_ptr); |
if (func_p && (function->tag == DW_TAG_inlined_subroutine)) |
stash->inliner_chain = function; |
line_p = lookup_address_in_line_info_table (unit->line_table, addr, |
*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; |
|
return lookup_address_in_line_info_table (unit->line_table, addr, |
filename_ptr, |
linenumber_ptr, |
discriminator_ptr); |
return line_p || func_p; |
} |
|
/* Check to see if line info is already decoded in a comp_unit. |
2962,12 → 3208,36 |
return NULL; |
} |
|
/* Transfer VMAs from object file to separate debug file. */ |
|
static void |
set_debug_vma (bfd *orig_bfd, bfd *debug_bfd) |
{ |
asection *s, *d; |
|
for (s = orig_bfd->sections, d = debug_bfd->sections; |
s != NULL && d != NULL; |
s = s->next, d = d->next) |
{ |
if ((d->flags & SEC_DEBUGGING) != 0) |
break; |
/* ??? Assumes 1-1 correspondence between sections in the |
two files. */ |
if (strcmp (s->name, d->name) == 0) |
{ |
d->output_section = s->output_section; |
d->output_offset = s->output_offset; |
d->vma = s->vma; |
} |
} |
} |
|
/* Unset vmas for adjusted sections in STASH. */ |
|
static void |
unset_sections (struct dwarf2_debug *stash) |
{ |
unsigned int i; |
int i; |
struct adjusted_section *p; |
|
i = stash->adjusted_section_count; |
2976,14 → 3246,23 |
p->section->vma = 0; |
} |
|
/* Set unique VMAs for loadable and DWARF sections in ABFD and save |
VMAs in STASH for unset_sections. */ |
/* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a |
relocatable object file. VMAs are normally all zero in relocatable |
object files, so if we want to distinguish locations in sections by |
address we need to set VMAs so the sections do not overlap. We |
also set VMA on .debug_info so that when we have multiple |
.debug_info sections (or the linkonce variant) they also do not |
overlap. The multiple .debug_info sections make up a single |
logical section. ??? We should probably do the same for other |
debug sections. */ |
|
static bfd_boolean |
place_sections (bfd *abfd, struct dwarf2_debug *stash) |
place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) |
{ |
bfd *abfd; |
struct adjusted_section *p; |
unsigned int i; |
int i; |
const char *debug_info_name; |
|
if (stash->adjusted_section_count != 0) |
{ |
2991,78 → 3270,79 |
p = stash->adjusted_sections; |
for (; i > 0; i--, p++) |
p->section->vma = p->adj_vma; |
return TRUE; |
} |
else |
|
debug_info_name = stash->debug_sections[debug_info].uncompressed_name; |
i = 0; |
abfd = orig_bfd; |
while (1) |
{ |
asection *sect; |
bfd_vma last_vma = 0, last_dwarf = 0; |
bfd_size_type amt; |
const char *debug_info_name; |
|
debug_info_name = stash->debug_sections[debug_info].uncompressed_name; |
i = 0; |
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
{ |
bfd_size_type sz; |
int is_debug_info; |
|
if (sect->vma != 0) |
if ((sect->output_section != NULL |
&& sect->output_section != sect |
&& (sect->flags & SEC_DEBUGGING) == 0) |
|| sect->vma != 0) |
continue; |
|
/* We need to adjust the VMAs of any .debug_info sections. |
Skip compressed ones, since no relocations could target |
them - they should not appear in object files anyway. */ |
if (strcmp (sect->name, debug_info_name) == 0) |
is_debug_info = 1; |
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) |
is_debug_info = 1; |
else |
is_debug_info = 0; |
is_debug_info = (strcmp (sect->name, debug_info_name) == 0 |
|| CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); |
|
if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) |
if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) |
&& !is_debug_info) |
continue; |
|
sz = sect->rawsize ? sect->rawsize : sect->size; |
if (sz == 0) |
continue; |
|
i++; |
} |
if (abfd == stash->bfd_ptr) |
break; |
abfd = stash->bfd_ptr; |
} |
|
amt = i * sizeof (struct adjusted_section); |
p = (struct adjusted_section *) bfd_alloc (abfd, amt); |
if (! p) |
if (i <= 1) |
stash->adjusted_section_count = -1; |
else |
{ |
bfd_vma last_vma = 0, last_dwarf = 0; |
bfd_size_type amt = i * sizeof (struct adjusted_section); |
|
p = (struct adjusted_section *) bfd_malloc (amt); |
if (p == NULL) |
return FALSE; |
|
stash->adjusted_sections = p; |
stash->adjusted_section_count = i; |
|
abfd = orig_bfd; |
while (1) |
{ |
asection *sect; |
|
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
{ |
bfd_size_type sz; |
int is_debug_info; |
|
if (sect->vma != 0) |
if ((sect->output_section != NULL |
&& sect->output_section != sect |
&& (sect->flags & SEC_DEBUGGING) == 0) |
|| sect->vma != 0) |
continue; |
|
/* We need to adjust the VMAs of any .debug_info sections. |
Skip compressed ones, since no relocations could target |
them - they should not appear in object files anyway. */ |
if (strcmp (sect->name, debug_info_name) == 0) |
is_debug_info = 1; |
else if (CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)) |
is_debug_info = 1; |
else |
is_debug_info = 0; |
is_debug_info = (strcmp (sect->name, debug_info_name) == 0 |
|| CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); |
|
if (!is_debug_info && (sect->flags & SEC_LOAD) == 0) |
if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) |
&& !is_debug_info) |
continue; |
|
sz = sect->rawsize ? sect->rawsize : sect->size; |
if (sz == 0) |
continue; |
|
p->section = sect; |
if (is_debug_info) |
{ |
BFD_ASSERT (sect->alignment_power == 0); |
3069,25 → 3349,30 |
sect->vma = last_dwarf; |
last_dwarf += sz; |
} |
else if (last_vma != 0) |
else |
{ |
/* Align the new address to the current section |
alignment. */ |
last_vma = ((last_vma |
+ ~((bfd_vma) -1 << sect->alignment_power)) |
& ((bfd_vma) -1 << sect->alignment_power)); |
+ ~(-((bfd_vma) 1 << sect->alignment_power))) |
& (-((bfd_vma) 1 << sect->alignment_power))); |
sect->vma = last_vma; |
last_vma += sect->vma + sz; |
last_vma += sz; |
} |
else |
last_vma += sect->vma + sz; |
|
p->section = sect; |
p->adj_vma = sect->vma; |
|
p++; |
} |
if (abfd == stash->bfd_ptr) |
break; |
abfd = stash->bfd_ptr; |
} |
} |
|
if (orig_bfd != stash->bfd_ptr) |
set_debug_vma (orig_bfd, stash->bfd_ptr); |
|
return TRUE; |
} |
|
3106,6 → 3391,7 |
{ |
struct funcinfo* each_func; |
struct funcinfo* best_fit = NULL; |
bfd_vma best_fit_len = 0; |
struct info_list_node *node; |
struct arange *arange; |
const char *name = bfd_asymbol_name (sym); |
3124,11 → 3410,13 |
&& addr >= arange->low |
&& addr < arange->high |
&& (!best_fit |
|| (arange->high - arange->low |
< best_fit->arange.high - best_fit->arange.low))) |
|| arange->high - arange->low < best_fit_len)) |
{ |
best_fit = each_func; |
best_fit_len = arange->high - arange->low; |
} |
} |
} |
|
if (best_fit) |
{ |
3316,6 → 3604,56 |
filename_ptr, linenumber_ptr); |
} |
|
/* Save current section VMAs. */ |
|
static bfd_boolean |
save_section_vma (const bfd *abfd, struct dwarf2_debug *stash) |
{ |
asection *s; |
unsigned int i; |
|
if (abfd->section_count == 0) |
return TRUE; |
stash->sec_vma = bfd_malloc (sizeof (*stash->sec_vma) * abfd->section_count); |
if (stash->sec_vma == NULL) |
return FALSE; |
for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) |
{ |
if (s->output_section != NULL) |
stash->sec_vma[i] = s->output_section->vma + s->output_offset; |
else |
stash->sec_vma[i] = s->vma; |
} |
return TRUE; |
} |
|
/* Compare current section VMAs against those at the time the stash |
was created. If find_nearest_line is used in linker warnings or |
errors early in the link process, the debug info stash will be |
invalid for later calls. This is because we relocate debug info |
sections, so the stashed section contents depend on symbol values, |
which in turn depend on section VMAs. */ |
|
static bfd_boolean |
section_vma_same (const bfd *abfd, const struct dwarf2_debug *stash) |
{ |
asection *s; |
unsigned int i; |
|
for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) |
{ |
bfd_vma vma; |
|
if (s->output_section != NULL) |
vma = s->output_section->vma + s->output_offset; |
else |
vma = s->vma; |
if (vma != stash->sec_vma[i]) |
return FALSE; |
} |
return TRUE; |
} |
|
/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified. |
If DEBUG_BFD is not specified, we read debug information from ABFD |
or its gnu_debuglink. The results will be stored in PINFO. |
3325,7 → 3663,8 |
_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, |
const struct dwarf_debug_section *debug_sections, |
asymbol **symbols, |
void **pinfo) |
void **pinfo, |
bfd_boolean do_place) |
{ |
bfd_size_type amt = sizeof (struct dwarf2_debug); |
bfd_size_type total_size; |
3333,13 → 3672,22 |
struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; |
|
if (stash != NULL) |
{ |
if (section_vma_same (abfd, stash)) |
return TRUE; |
|
_bfd_dwarf2_cleanup_debug_info (abfd, pinfo); |
memset (stash, 0, amt); |
} |
else |
{ |
stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); |
if (! stash) |
return FALSE; |
} |
stash->debug_sections = debug_sections; |
stash->syms = symbols; |
if (!save_section_vma (abfd, stash)) |
return FALSE; |
|
*pinfo = stash; |
|
3361,7 → 3709,8 |
if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL |
|| ! bfd_check_format (debug_bfd, bfd_object) |
|| (msec = find_debug_info (debug_bfd, |
debug_sections, NULL)) == NULL) |
debug_sections, NULL)) == NULL |
|| !bfd_generic_link_read_symbols (debug_bfd)) |
{ |
if (debug_bfd) |
bfd_close (debug_bfd); |
3369,10 → 3718,17 |
free (debug_filename); |
return FALSE; |
} |
|
symbols = bfd_get_outsymbols (debug_bfd); |
stash->syms = symbols; |
stash->close_on_cleanup = TRUE; |
} |
stash->bfd_ptr = debug_bfd; |
|
if (do_place |
&& !place_sections (abfd, stash)) |
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 |
there's more than one, try case two: none of the sections is |
3432,6 → 3788,57 |
return TRUE; |
} |
|
/* Scan the debug information in PINFO looking for a DW_TAG_subprogram |
abbrev with a DW_AT_low_pc attached to it. Then lookup that same |
symbol in SYMBOLS and return the difference between the low_pc and |
the symbol's address. Returns 0 if no suitable symbol could be found. */ |
|
bfd_signed_vma |
_bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo) |
{ |
struct dwarf2_debug *stash; |
struct comp_unit * unit; |
|
stash = (struct dwarf2_debug *) *pinfo; |
|
if (stash == NULL) |
return 0; |
|
for (unit = stash->all_comp_units; unit; unit = unit->next_unit) |
{ |
struct funcinfo * func; |
|
if (unit->function_table == NULL) |
{ |
if (unit->line_table == NULL) |
unit->line_table = decode_line_info (unit, stash); |
if (unit->line_table != NULL) |
scan_unit_for_symbols (unit); |
} |
|
for (func = unit->function_table; func != NULL; func = func->prev_func) |
if (func->name && func->arange.low) |
{ |
asymbol ** psym; |
|
/* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */ |
|
for (psym = symbols; * psym != NULL; psym++) |
{ |
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)); |
} |
} |
} |
|
return 0; |
} |
|
/* Find the source code location of SYMBOL. If SYMBOL is NULL |
then find the nearest source code location corresponding to |
the address SECTION + OFFSET. |
3444,17 → 3851,17 |
field and in the abbreviation offset, or zero to indicate that the |
default value should be used. */ |
|
static bfd_boolean |
find_line (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
bfd_boolean |
_bfd_dwarf2_find_nearest_line (bfd *abfd, |
asymbol **symbols, |
asymbol *symbol, |
asection *section, |
bfd_vma offset, |
asymbol *symbol, |
asymbol **symbols, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
const struct dwarf_debug_section *debug_sections, |
unsigned int addr_size, |
void **pinfo) |
{ |
3470,7 → 3877,8 |
/* What address are we looking for? */ |
bfd_vma addr; |
struct comp_unit* each; |
bfd_vma found = FALSE; |
struct funcinfo *function = NULL; |
bfd_boolean found = FALSE; |
bfd_boolean do_line; |
|
*filename_ptr = NULL; |
3480,35 → 3888,25 |
if (discriminator_ptr) |
*discriminator_ptr = 0; |
|
if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, |
debug_sections, symbols, pinfo)) |
if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, debug_sections, |
symbols, pinfo, |
(abfd->flags & (EXEC_P | DYNAMIC)) == 0)) |
return FALSE; |
|
stash = (struct dwarf2_debug *) *pinfo; |
|
/* In a relocatable file, 2 functions may have the same address. |
We change the section vma so that they won't overlap. */ |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) |
{ |
if (! place_sections (abfd, stash)) |
return FALSE; |
} |
|
do_line = (section == NULL |
&& offset == 0 |
&& functionname_ptr == NULL |
&& symbol != NULL); |
do_line = symbol != NULL; |
if (do_line) |
{ |
BFD_ASSERT (section == NULL && offset == 0 && functionname_ptr == NULL); |
section = bfd_get_section (symbol); |
addr = symbol->value; |
section = bfd_get_section (symbol); |
} |
else if (section != NULL |
&& functionname_ptr != NULL |
&& symbol == NULL) |
else |
{ |
BFD_ASSERT (section != NULL && functionname_ptr != NULL); |
addr = offset; |
else |
abort (); |
} |
|
if (section->output_section) |
addr += section->output_section->vma + section->output_offset; |
3560,17 → 3958,55 |
} |
else |
{ |
bfd_vma min_range = (bfd_vma) -1; |
const char * local_filename = NULL; |
struct funcinfo *local_function = NULL; |
unsigned int local_linenumber = 0; |
unsigned int local_discriminator = 0; |
|
for (each = stash->all_comp_units; each; each = each->next_unit) |
{ |
bfd_vma range = (bfd_vma) -1; |
|
found = ((each->arange.high == 0 |
|| comp_unit_contains_address (each, addr)) |
&& comp_unit_find_nearest_line (each, addr, |
filename_ptr, |
functionname_ptr, |
linenumber_ptr, |
discriminator_ptr, |
stash)); |
&& (range = comp_unit_find_nearest_line (each, addr, |
& local_filename, |
& local_function, |
& local_linenumber, |
& local_discriminator, |
stash)) != 0); |
if (found) |
{ |
/* PRs 15935 15994: Bogus debug information may have provided us |
with an erroneous match. We attempt to counter this by |
selecting the match that has the smallest address range |
associated with it. (We are assuming that corrupt debug info |
will tend to result in extra large address ranges rather than |
extra small ranges). |
|
This does mean that we scan through all of the CUs associated |
with the bfd each time this function is called. But this does |
have the benefit of producing consistent results every time the |
function is called. */ |
if (range <= min_range) |
{ |
if (filename_ptr && local_filename) |
* filename_ptr = local_filename; |
if (local_function) |
function = local_function; |
if (discriminator_ptr && local_discriminator) |
* discriminator_ptr = local_discriminator; |
if (local_linenumber) |
* linenumber_ptr = local_linenumber; |
min_range = range; |
} |
} |
} |
|
if (* linenumber_ptr) |
{ |
found = TRUE; |
goto done; |
} |
} |
3589,13 → 4025,13 |
unsigned int offset_size = addr_size; |
bfd_byte *info_ptr_unit = stash->info_ptr; |
|
length = read_4_bytes (stash->bfd_ptr, 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); |
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, |
3604,7 → 4040,7 |
else if (length == 0) |
{ |
offset_size = 8; |
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4); |
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 |
3626,6 → 4062,8 |
|
if (length > 0) |
{ |
bfd_byte * new_ptr; |
|
each = parse_comp_unit (stash, length, info_ptr_unit, |
offset_size); |
if (!each) |
3632,8 → 4070,18 |
/* The dwarf information is damaged, don't trust it any |
more. */ |
break; |
stash->info_ptr += length; |
|
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 |
3660,10 → 4108,10 |
|| comp_unit_contains_address (each, addr)) |
&& comp_unit_find_nearest_line (each, addr, |
filename_ptr, |
functionname_ptr, |
&function, |
linenumber_ptr, |
discriminator_ptr, |
stash)); |
stash) != 0); |
|
if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) |
== stash->sec->size) |
3679,6 → 4127,28 |
} |
|
done: |
if (function) |
{ |
if (!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; |
if (fun != NULL |
&& fun->value + sec_vma == function->arange.low) |
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; |
} |
*functionname_ptr = function->name; |
} |
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) |
unset_sections (stash); |
|
3685,46 → 4155,7 |
return found; |
} |
|
/* The DWARF2 version of find_nearest_line. |
Return TRUE if the line is found without error. */ |
|
bfd_boolean |
_bfd_dwarf2_find_nearest_line (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
unsigned int addr_size, |
void **pinfo) |
{ |
return find_line (abfd, debug_sections, section, offset, NULL, symbols, |
filename_ptr, functionname_ptr, linenumber_ptr, |
discriminator_ptr, addr_size, pinfo); |
} |
|
/* The DWARF2 version of find_line. |
Return TRUE if the line is found without error. */ |
|
bfd_boolean |
_bfd_dwarf2_find_line (bfd *abfd, |
asymbol **symbols, |
asymbol *symbol, |
const char **filename_ptr, |
unsigned int *linenumber_ptr, |
unsigned int *discriminator_ptr, |
unsigned int addr_size, |
void **pinfo) |
{ |
return find_line (abfd, dwarf_debug_sections, NULL, 0, symbol, symbols, |
filename_ptr, NULL, linenumber_ptr, discriminator_ptr, |
addr_size, pinfo); |
} |
|
bfd_boolean |
_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED, |
const char **filename_ptr, |
const char **functionname_ptr, |
3828,6 → 4259,116 |
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); |
} |
|
/* Find the function to a particular section and offset, |
for error reporting. */ |
|
asymbol * |
_bfd_elf_find_function (bfd *abfd, |
asymbol **symbols, |
asection *section, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr) |
{ |
struct elf_find_function_cache |
{ |
asection *last_section; |
asymbol *func; |
const char *filename; |
bfd_size_type func_size; |
} *cache; |
|
if (symbols == NULL) |
return NULL; |
|
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) |
return NULL; |
|
cache = elf_tdata (abfd)->elf_find_function_cache; |
if (cache == NULL) |
{ |
cache = bfd_zalloc (abfd, sizeof (*cache)); |
elf_tdata (abfd)->elf_find_function_cache = cache; |
if (cache == NULL) |
return NULL; |
} |
if (cache->last_section != section |
|| cache->func == NULL |
|| offset < cache->func->value |
|| offset >= cache->func->value + cache->func_size) |
{ |
asymbol *file; |
bfd_vma low_func; |
asymbol **p; |
/* ??? Given multiple file symbols, it is impossible to reliably |
choose the right file name for global symbols. File symbols are |
local symbols, and thus all file symbols must sort before any |
global symbols. The ELF spec may be interpreted to say that a |
file symbol must sort before other local symbols, but currently |
ld -r doesn't do this. So, for ld -r output, it is possible to |
make a better choice of file name for local symbols by ignoring |
file symbols appearing after a given local symbol. */ |
enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; |
const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
|
file = NULL; |
low_func = 0; |
state = nothing_seen; |
cache->filename = NULL; |
cache->func = NULL; |
cache->func_size = 0; |
cache->last_section = section; |
|
for (p = symbols; *p != NULL; p++) |
{ |
asymbol *sym = *p; |
bfd_vma code_off; |
bfd_size_type size; |
|
if ((sym->flags & BSF_FILE) != 0) |
{ |
file = sym; |
if (state == symbol_seen) |
state = file_after_symbol_seen; |
continue; |
} |
|
size = bed->maybe_function_sym (sym, section, &code_off); |
if (size != 0 |
&& code_off <= offset |
&& (code_off > low_func |
|| (code_off == low_func |
&& size > cache->func_size))) |
{ |
cache->func = sym; |
cache->func_size = size; |
cache->filename = NULL; |
low_func = code_off; |
if (file != NULL |
&& ((sym->flags & BSF_LOCAL) != 0 |
|| state != file_after_symbol_seen)) |
cache->filename = bfd_asymbol_name (file); |
} |
if (state == nothing_seen) |
state = symbol_seen; |
} |
} |
|
if (cache->func == NULL) |
return NULL; |
|
if (filename_ptr) |
*filename_ptr = cache->filename; |
if (functionname_ptr) |
*functionname_ptr = bfd_asymbol_name (cache->func); |
|
return cache->func; |
} |