diff options
Diffstat (limited to 'bfd/dwarf2.c')
-rw-r--r-- | bfd/dwarf2.c | 197 |
1 files changed, 97 insertions, 100 deletions
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index be9983edbf0..404f35df62b 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -557,10 +557,14 @@ read_section (bfd * abfd, amt = bfd_get_section_limit_octets (abfd, msec); filesize = bfd_get_file_size (abfd); - if (amt >= filesize) + /* 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 its filesize! (0x%lx vs 0x%lx)"), + _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; @@ -1437,6 +1441,7 @@ non_mangled (int lang) case DW_LANG_PLI: case DW_LANG_UPC: case DW_LANG_C11: + case DW_LANG_Mips_Assembler: return true; } } @@ -2539,13 +2544,12 @@ decode_line_info (struct comp_unit *unit) return NULL; } -/* 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. +/* If ADDR is within TABLE set the output parameters and return TRUE, + otherwise set *FILENAME_PTR to NULL and return FALSE. The parameters FILENAME_PTR, LINENUMBER_PTR and DISCRIMINATOR_PTR are pointers to the objects to be filled in. */ -static bfd_vma +static bool lookup_address_in_line_info_table (struct line_info_table *table, bfd_vma addr, const char **filename_ptr, @@ -2604,12 +2608,12 @@ lookup_address_in_line_info_table (struct line_info_table *table, *linenumber_ptr = info->line; if (discriminator_ptr) *discriminator_ptr = info->discriminator; - return seq->last_line->address - seq->low_pc; + return true; } fail: *filename_ptr = NULL; - return 0; + return false; } /* Read in the .debug_ranges section for future reference. */ @@ -3289,6 +3293,36 @@ lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table) /* DWARF2 Compilation unit functions. */ +static struct funcinfo * +reverse_funcinfo_list (struct funcinfo *head) +{ + struct funcinfo *rhead; + struct funcinfo *temp; + + for (rhead = NULL; head; head = temp) + { + temp = head->prev_func; + head->prev_func = rhead; + rhead = head; + } + return rhead; +} + +static struct varinfo * +reverse_varinfo_list (struct varinfo *head) +{ + struct varinfo *rhead; + struct varinfo *temp; + + for (rhead = NULL; head; head = temp) + { + temp = head->prev_var; + head->prev_var = rhead; + rhead = head; + } + return rhead; +} + /* Scan over each die in a comp. unit looking for functions to add to the function table and variables to the variable table. */ @@ -3304,7 +3338,9 @@ scan_unit_for_symbols (struct comp_unit *unit) struct funcinfo *func; } *nested_funcs; int nested_funcs_size; - + struct funcinfo *last_func; + struct varinfo *last_var; + /* Maintain a stack of in-scope functions and inlined functions, which we can use to set the caller_func field. */ nested_funcs_size = 32; @@ -3438,10 +3474,16 @@ scan_unit_for_symbols (struct comp_unit *unit) } } + unit->function_table = reverse_funcinfo_list (unit->function_table); + unit->variable_table = reverse_varinfo_list (unit->variable_table); + /* This is the second pass over the abbrevs. */ info_ptr = unit->first_child_die_ptr; nesting_level = 0; + last_func = NULL; + last_var = NULL; + while (nesting_level >= 0) { unsigned int abbrev_number, i; @@ -3477,16 +3519,32 @@ scan_unit_for_symbols (struct comp_unit *unit) || abbrev->tag == DW_TAG_entry_point || abbrev->tag == DW_TAG_inlined_subroutine) { - func = lookup_func_by_offset (current_offset, unit->function_table); + if (last_func + && last_func->prev_func + && last_func->prev_func->unit_offset == current_offset) + func = last_func->prev_func; + else + func = lookup_func_by_offset (current_offset, unit->function_table); + if (func == NULL) goto fail; + + last_func = func; } else if (abbrev->tag == DW_TAG_variable || abbrev->tag == DW_TAG_member) { - var = lookup_var_by_offset (current_offset, unit->variable_table); + if (last_var + && last_var->prev_var + && last_var->prev_var->unit_offset == current_offset) + var = last_var->prev_var; + else + var = lookup_var_by_offset (current_offset, unit->variable_table); + if (var == NULL) goto fail; + + last_var = var; } for (i = 0; i < abbrev->num_attrs; ++i) @@ -3680,6 +3738,9 @@ scan_unit_for_symbols (struct comp_unit *unit) } } + unit->function_table = reverse_funcinfo_list (unit->function_table); + unit->variable_table = reverse_varinfo_list (unit->variable_table); + free (nested_funcs); return true; @@ -3947,14 +4008,11 @@ comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr) } /* If UNIT contains ADDR, set the output parameters to the values for - the line containing ADDR. The output parameters, FILENAME_PTR, - FUNCTION_PTR, and LINENUMBER_PTR, are pointers to the objects - to be filled in. - - 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. */ + the line containing ADDR and return TRUE. Otherwise return FALSE. + The output parameters, FILENAME_PTR, FUNCTION_PTR, and + LINENUMBER_PTR, are pointers to the objects to be filled in. */ -static bfd_vma +static bool comp_unit_find_nearest_line (struct comp_unit *unit, bfd_vma addr, const char **filename_ptr, @@ -3962,7 +4020,7 @@ comp_unit_find_nearest_line (struct comp_unit *unit, unsigned int *linenumber_ptr, unsigned int *discriminator_ptr) { - bool func_p; + bool line_p, func_p; if (!comp_unit_maybe_decode_line_info (unit)) return false; @@ -3972,10 +4030,11 @@ comp_unit_find_nearest_line (struct comp_unit *unit, if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine) unit->stash->inliner_chain = *function_ptr; - return lookup_address_in_line_info_table (unit->line_table, addr, - filename_ptr, - linenumber_ptr, - discriminator_ptr); + line_p = 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. @@ -4043,36 +4102,6 @@ comp_unit_find_line (struct comp_unit *unit, linenumber_ptr); } -static struct funcinfo * -reverse_funcinfo_list (struct funcinfo *head) -{ - struct funcinfo *rhead; - struct funcinfo *temp; - - for (rhead = NULL; head; head = temp) - { - temp = head->prev_func; - head->prev_func = rhead; - rhead = head; - } - return rhead; -} - -static struct varinfo * -reverse_varinfo_list (struct varinfo *head) -{ - struct varinfo *rhead; - struct varinfo *temp; - - for (rhead = NULL; head; head = temp) - { - temp = head->prev_var; - head->prev_var = rhead; - rhead = head; - } - return rhead; -} - /* Extract all interesting funcinfos and varinfos of a compilation unit into hash tables for faster lookup. Returns TRUE if no errors were enountered; FALSE otherwise. */ @@ -5156,54 +5185,17 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, } 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->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))) != 0); + && comp_unit_find_nearest_line (each, addr, + filename_ptr, + &function, + linenumber_ptr, + discriminator_ptr)); 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; + goto done; } } @@ -5228,7 +5220,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, filename_ptr, &function, linenumber_ptr, - discriminator_ptr) != 0); + discriminator_ptr)); if (found) break; @@ -5236,7 +5228,11 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, done: if (functionname_ptr && function && function->is_linkage) - *functionname_ptr = function->name; + { + *functionname_ptr = function->name; + if (!found) + found = 2; + } else if (functionname_ptr && (!*functionname_ptr || (function && !function->is_linkage))) @@ -5260,8 +5256,9 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, 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) + if (fun == NULL) + *functionname_ptr = function->name; + else if (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. */ |