X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=bfd%2Fdwarf2.c;h=8c9bd7a3026dc7c583fbb8bc7079505b24759b86;hb=e0b74a85b879354d2aa1a6b5026d5de58c78ec45;hp=4761878851362abd6d843fa6122f2d4136ac2593;hpb=b44cfc5de139d7e2410e91846df0f0164d663d0b;p=thirdparty%2Fbinutils-gdb.git diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 47618788513..8c9bd7a3026 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -1,5 +1,5 @@ /* DWARF 2 support. - Copyright (C) 1994-2022 Free Software Foundation, Inc. + Copyright (C) 1994-2023 Free Software Foundation, Inc. Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions (gavin@cygnus.com). @@ -32,10 +32,12 @@ #include "sysdep.h" #include "bfd.h" #include "libiberty.h" +#include "demangle.h" #include "libbfd.h" #include "elf-bfd.h" #include "dwarf2.h" #include "hashtab.h" +#include "splay-tree.h" /* The data in the .debug_line statement prologue looks like this. */ @@ -80,6 +82,7 @@ struct adjusted_section { asection *section; bfd_vma adj_vma; + bfd_vma orig_vma; }; /* A trie to map quickly from address range to compilation unit. @@ -152,6 +155,45 @@ static struct trie_node *alloc_trie_leaf (bfd *abfd) return &leaf->head; } +struct addr_range +{ + bfd_byte *start; + bfd_byte *end; +}; + +/* Return true if address range do intersect. */ + +static bool +addr_range_intersects (struct addr_range *r1, struct addr_range *r2) +{ + return (r1->start <= r2->start && r2->start < r1->end) + || (r1->start <= (r2->end - 1) && (r2->end - 1) < r1->end); +} + +/* Compare function for splay tree of addr_ranges. */ + +static int +splay_tree_compare_addr_range (splay_tree_key xa, splay_tree_key xb) +{ + struct addr_range *r1 = (struct addr_range *) xa; + struct addr_range *r2 = (struct addr_range *) xb; + + if (addr_range_intersects (r1, r2) || addr_range_intersects (r2, r1)) + return 0; + else if (r1->end <= r2->start) + return -1; + else + return 1; +} + +/* Splay tree release function for keys (addr_range). */ + +static void +splay_tree_free_addr_range (splay_tree_key key) +{ + free ((struct addr_range *)key); +} + struct dwarf2_debug_file { /* The actual bfd from which debug info was loaded. Might be @@ -235,6 +277,9 @@ struct dwarf2_debug_file /* Root of a trie to map addresses to compilation units. */ struct trie_node *trie_root; + + /* Splay tree to map info_ptr address to compilation units. */ + splay_tree comp_unit_tree; }; struct dwarf2_debug @@ -646,7 +691,6 @@ read_section (bfd *abfd, { bfd_size_type amt; asection *msec; - ufile_ptr filesize; msec = bfd_get_section_by_name (abfd, section_name); if (msec == NULL) @@ -662,20 +706,22 @@ read_section (bfd *abfd, return false; } - amt = bfd_get_section_limit_octets (abfd, msec); - filesize = bfd_get_file_size (abfd); - /* PR 28834: A compressed debug section could well decompress to a size - larger than the file, so we choose an arbitrary modifier of 10x in - the test below. If this ever turns out to be insufficient, it can - be changed by a future update. */ - if (amt >= filesize * 10) + if ((msec->flags & SEC_HAS_CONTENTS) == 0) + { + _bfd_error_handler (_("DWARF error: section %s has no contents"), + section_name); + bfd_set_error (bfd_error_no_contents); + return false; + } + + if (_bfd_section_size_insane (abfd, msec)) { /* PR 26946 */ - _bfd_error_handler (_("DWARF error: section %s is larger than 10x its filesize! (0x%lx vs 0x%lx)"), - section_name, (long) amt, (long) filesize); - bfd_set_error (bfd_error_bad_value); + _bfd_error_handler (_("DWARF error: section %s is too big"), + section_name); return false; } + amt = bfd_get_section_limit_octets (abfd, msec); *section_size = amt; /* Paranoia - alloc one extra so that we can make sure a string section is NUL terminated. */ @@ -1369,20 +1415,20 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit) &file->dwarf_addr_buffer, &file->dwarf_addr_size)) return 0; - if (_bfd_mul_overflow (idx, unit->offset_size, &offset)) + if (_bfd_mul_overflow (idx, unit->addr_size, &offset)) return 0; offset += unit->dwarf_addr_offset; if (offset < unit->dwarf_addr_offset || offset > file->dwarf_addr_size - || file->dwarf_addr_size - offset < unit->offset_size) + || file->dwarf_addr_size - offset < unit->addr_size) return 0; info_ptr = file->dwarf_addr_buffer + offset; - if (unit->offset_size == 4) + if (unit->addr_size == 4) return bfd_get_32 (unit->abfd, info_ptr); - else if (unit->offset_size == 8) + else if (unit->addr_size == 8) return bfd_get_64 (unit->abfd, info_ptr); else return 0; @@ -1668,31 +1714,52 @@ read_attribute (struct attribute * attr, return info_ptr; } -/* Return whether DW_AT_name will return the same as DW_AT_linkage_name - for a function. */ +/* Return mangling style given LANG. */ -static bool -non_mangled (int lang) +static int +mangle_style (int lang) { switch (lang) { + case DW_LANG_Ada83: + case DW_LANG_Ada95: + return DMGL_GNAT; + + case DW_LANG_C_plus_plus: + case DW_LANG_C_plus_plus_03: + case DW_LANG_C_plus_plus_11: + case DW_LANG_C_plus_plus_14: + return DMGL_GNU_V3; + + case DW_LANG_Java: + return DMGL_JAVA; + + case DW_LANG_D: + return DMGL_DLANG; + + case DW_LANG_Rust: + case DW_LANG_Rust_old: + return DMGL_RUST; + default: - return false; + return DMGL_AUTO; 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_C99: case DW_LANG_UPC: case DW_LANG_C11: case DW_LANG_Mips_Assembler: - return true; + case DW_LANG_Upc: + case DW_LANG_HP_Basic91: + case DW_LANG_HP_IMacro: + case DW_LANG_HP_Assembler: + return 0; } } @@ -1736,6 +1803,7 @@ struct line_info_table unsigned int num_files; unsigned int num_dirs; unsigned int num_sequences; + bool use_dir_and_file_0; char * comp_dir; char ** dirs; struct fileinfo* files; @@ -1766,8 +1834,6 @@ struct funcinfo bool is_linkage; const char *name; struct arange arange; - /* Where the symbol is defined. */ - asection *sec; /* The offset of the funcinfo from the start of the unit. */ uint64_t unit_offset; }; @@ -1801,11 +1867,9 @@ struct varinfo /* The type of this variable. */ int tag; /* The name of the variable, if it has one. */ - char *name; + const char *name; /* The address of the variable. */ bfd_vma addr; - /* Where the symbol is defined. */ - asection *sec; /* Is this a stack variable? */ bool stack; }; @@ -1956,16 +2020,30 @@ concat_filename (struct line_info_table *table, unsigned int file) { char *filename; - if (table == NULL || file - 1 >= table->num_files) + /* Pre DWARF-5 entry 0 in the directory and filename tables was not used. + So in order to save space in the tables used here the info for, eg + directory 1 is stored in slot 0 of the directory table, directory 2 + in slot 1 and so on. + + Starting with DWARF-5 the 0'th entry is used so there is a one to one + mapping between DWARF slots and internal table entries. */ + if (! table->use_dir_and_file_0) + { + /* Pre DWARF-5, FILE == 0 means unknown. */ + if (file == 0) + return strdup (""); + -- file; + } + + if (table == NULL || file >= table->num_files) { - /* FILE == 0 means unknown. */ - if (file) - _bfd_error_handler - (_("DWARF error: mangled line number section (bad file number)")); + _bfd_error_handler + (_("DWARF error: mangled line number section (bad file number)")); return strdup (""); } - filename = table->files[file - 1].name; + filename = table->files[file].name; + if (filename == NULL) return strdup (""); @@ -1975,13 +2053,16 @@ concat_filename (struct line_info_table *table, unsigned int file) char *subdir_name = NULL; char *name; size_t len; + unsigned int dir = table->files[file].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 (!table->use_dir_and_file_0) + --dir; + /* Wrapping from 0 to -1u above gives the intended result with + the test below of leaving subdir_name NULL for pre-DWARF5 dir + of 0. */ + /* PR 17512: file: 0317e960, file: 7f3d2e4b. */ + if (dir < table->num_dirs) + subdir_name = table->dirs[dir]; if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) dir_name = table->comp_dir; @@ -2022,10 +2103,12 @@ concat_filename (struct line_info_table *table, unsigned int file) /* Check whether [low1, high1) can be combined with [low2, high2), i.e., they touch or overlap. */ -static bool ranges_overlap (bfd_vma low1, - bfd_vma high1, - bfd_vma low2, - bfd_vma high2) + +static bool +ranges_overlap (bfd_vma low1, + bfd_vma high1, + bfd_vma low2, + bfd_vma high2) { if (low1 == low2 || high1 == high2) return true; @@ -2052,15 +2135,16 @@ static bool ranges_overlap (bfd_vma low1, /* Insert an address range in the trie mapping addresses to compilation units. Will return the new trie node (usually the same as is being sent in, but in case of a leaf-to-interior conversion, or expansion of a leaf, it may be - different), or NULL on failure. - */ -static struct trie_node *insert_arange_in_trie(bfd *abfd, - struct trie_node *trie, - bfd_vma trie_pc, - unsigned int trie_pc_bits, - struct comp_unit *unit, - bfd_vma low_pc, - bfd_vma high_pc) + different), or NULL on failure. */ + +static struct trie_node * +insert_arange_in_trie (bfd *abfd, + struct trie_node *trie, + bfd_vma trie_pc, + unsigned int trie_pc_bits, + struct comp_unit *unit, + bfd_vma low_pc, + bfd_vma high_pc) { bfd_vma clamped_low_pc, clamped_high_pc; int ch, from_ch, to_ch; @@ -2198,7 +2282,6 @@ static struct trie_node *insert_arange_in_trie(bfd *abfd, return trie; } - static bool arange_add (struct comp_unit *unit, struct arange *first_arange, struct trie_node **trie_root, bfd_vma low_pc, bfd_vma high_pc) @@ -2584,10 +2667,8 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, } } - /* Skip the first "zero entry", which is the compilation dir/file. */ - if (datai != 0) - if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) - return false; + if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) + return false; } *bufp = buf; @@ -2764,6 +2845,7 @@ decode_line_info (struct comp_unit *unit) if (!read_formatted_entries (unit, &line_ptr, line_end, table, line_info_add_file_name)) goto fail; + table->use_dir_and_file_0 = true; } else { @@ -2786,6 +2868,7 @@ decode_line_info (struct comp_unit *unit) if (!line_info_add_file_name (table, cur_file, dir, xtime, size)) goto fail; } + table->use_dir_and_file_0 = false; } /* Read the statement sequences until there's nothing left. */ @@ -2794,7 +2877,7 @@ decode_line_info (struct comp_unit *unit) /* State machine registers. */ bfd_vma address = 0; unsigned char op_index = 0; - char * filename = table->num_files ? concat_filename (table, 1) : NULL; + char * filename = NULL; unsigned int line = 1; unsigned int column = 0; unsigned int discriminator = 0; @@ -2809,6 +2892,14 @@ decode_line_info (struct comp_unit *unit) bfd_vma low_pc = (bfd_vma) -1; bfd_vma high_pc = 0; + if (table->num_files) + { + if (table->use_dir_and_file_0) + filename = concat_filename (table, 0); + else + filename = concat_filename (table, 1); + } + /* Decode the table. */ while (!end_sequence && line_ptr < line_end) { @@ -3197,7 +3288,7 @@ lookup_address_in_function_table (struct comp_unit *unit, struct lookup_funcinfo* lookup_funcinfo = NULL; struct funcinfo* funcinfo = NULL; struct funcinfo* best_fit = NULL; - bfd_vma best_fit_len = 0; + bfd_vma best_fit_len = (bfd_vma) -1; bfd_size_type low, high, mid, first; struct arange *arange; @@ -3243,8 +3334,7 @@ lookup_address_in_function_table (struct comp_unit *unit, if (addr < arange->low || addr >= arange->high) continue; - if (!best_fit - || arange->high - arange->low < best_fit_len + if (arange->high - arange->low < best_fit_len /* The following comparison is designed to return the same match as the previous algorithm for routines which have the same best fit length. */ @@ -3276,44 +3366,33 @@ lookup_symbol_in_function_table (struct comp_unit *unit, const char **filename_ptr, unsigned int *linenumber_ptr) { - struct funcinfo* each_func; + struct funcinfo* each; struct funcinfo* best_fit = NULL; - bfd_vma best_fit_len = 0; + bfd_vma best_fit_len = (bfd_vma) -1; struct arange *arange; const char *name = bfd_asymbol_name (sym); - asection *sec = bfd_asymbol_section (sym); - for (each_func = unit->function_table; - each_func; - each_func = each_func->prev_func) - { - for (arange = &each_func->arange; - arange; - arange = arange->next) + for (each = unit->function_table; each; each = each->prev_func) + for (arange = &each->arange; arange; arange = arange->next) + if (addr >= arange->low + && addr < arange->high + && arange->high - arange->low < best_fit_len + && each->file + && each->name + && strstr (name, each->name) != NULL) { - if ((!each_func->sec || each_func->sec == sec) - && addr >= arange->low - && addr < arange->high - && each_func->name - && strcmp (name, each_func->name) == 0 - && (!best_fit - || arange->high - arange->low < best_fit_len)) - { - best_fit = each_func; - best_fit_len = arange->high - arange->low; - } + best_fit = each; + best_fit_len = arange->high - arange->low; } - } if (best_fit) { - best_fit->sec = sec; *filename_ptr = best_fit->file; *linenumber_ptr = best_fit->line; return true; } - else - return false; + + return false; } /* Variable table functions. */ @@ -3328,22 +3407,19 @@ lookup_symbol_in_variable_table (struct comp_unit *unit, const char **filename_ptr, unsigned int *linenumber_ptr) { - const char *name = bfd_asymbol_name (sym); - asection *sec = bfd_asymbol_section (sym); struct varinfo* each; + const char *name = bfd_asymbol_name (sym); for (each = unit->variable_table; each; each = each->prev_var) - if (! each->stack + if (each->addr == addr + && !each->stack && each->file != NULL && each->name != NULL - && each->addr == addr - && (!each->sec || each->sec == sec) - && strcmp (name, each->name) == 0) + && strstr (name, each->name) != NULL) break; if (each) { - each->sec = sec; *filename_ptr = each->file; *linenumber_ptr = each->line; return true; @@ -3372,7 +3448,6 @@ find_abstract_instance (struct comp_unit *unit, struct abbrev_info *abbrev; uint64_t die_ref = attr_ptr->u.val; struct attribute attr; - const char *name = NULL; if (recur_count == 100) { @@ -3447,16 +3522,12 @@ find_abstract_instance (struct comp_unit *unit, 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; + struct comp_unit *u = NULL; + struct addr_range range = { info_ptr, info_ptr }; + splay_tree_node v = splay_tree_lookup (unit->file->comp_unit_tree, + (splay_tree_key)&range); + if (v != NULL) + u = (struct comp_unit *)v->value; if (attr_ptr->form == DW_FORM_ref_addr) while (u == NULL) @@ -3537,17 +3608,17 @@ find_abstract_instance (struct comp_unit *unit, case DW_AT_name: /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name over DW_AT_name. */ - if (name == NULL && is_str_form (&attr)) + if (*pname == NULL && is_str_form (&attr)) { - name = attr.u.str; - if (non_mangled (unit->lang)) + *pname = attr.u.str; + if (mangle_style (unit->lang) == 0) *is_linkage = true; } break; case DW_AT_specification: if (is_int_form (&attr) && !find_abstract_instance (unit, &attr, recur_count + 1, - &name, is_linkage, + pname, is_linkage, filename_ptr, linenumber_ptr)) return false; break; @@ -3557,7 +3628,7 @@ find_abstract_instance (struct comp_unit *unit, non-string forms into these attributes. */ if (is_str_form (&attr)) { - name = attr.u.str; + *pname = attr.u.str; *is_linkage = true; } break; @@ -3565,8 +3636,11 @@ find_abstract_instance (struct comp_unit *unit, if (!comp_unit_maybe_decode_line_info (unit)) return false; if (is_int_form (&attr)) - *filename_ptr = concat_filename (unit->line_table, - attr.u.val); + { + free (*filename_ptr); + *filename_ptr = concat_filename (unit->line_table, + attr.u.val); + } break; case DW_AT_decl_line: if (is_int_form (&attr)) @@ -3578,7 +3652,6 @@ find_abstract_instance (struct comp_unit *unit, } } } - *pname = name; return true; } @@ -4036,7 +4109,7 @@ scan_unit_for_symbols (struct comp_unit *unit) if (func->name == NULL && is_str_form (&attr)) { func->name = attr.u.str; - if (non_mangled (unit->lang)) + if (mangle_style (unit->lang) == 0) func->is_linkage = true; } break; @@ -4074,8 +4147,11 @@ scan_unit_for_symbols (struct comp_unit *unit) case DW_AT_decl_file: if (is_int_form (&attr)) - func->file = concat_filename (unit->line_table, - attr.u.val); + { + free (func->file); + func->file = concat_filename (unit->line_table, + attr.u.val); + } break; case DW_AT_decl_line: @@ -4094,11 +4170,12 @@ scan_unit_for_symbols (struct comp_unit *unit) case DW_AT_specification: if (is_int_form (&attr) && attr.u.val) { - struct varinfo * spec_var; - - spec_var = lookup_var_by_offset (attr.u.val, - unit->variable_table); - if (spec_var == NULL) + bool is_linkage; + if (!find_abstract_instance (unit, &attr, 0, + &var->name, + &is_linkage, + &var->file, + &var->line)) { _bfd_error_handler (_("DWARF error: could not find " "variable specification " @@ -4106,15 +4183,6 @@ scan_unit_for_symbols (struct comp_unit *unit) (unsigned long) attr.u.val); break; } - - if (var->name == NULL) - var->name = spec_var->name; - if (var->file == NULL && spec_var->file != NULL) - var->file = strdup (spec_var->file); - if (var->line == 0) - var->line = spec_var->line; - if (var->sec == NULL) - var->sec = spec_var->sec; } break; @@ -4125,8 +4193,11 @@ scan_unit_for_symbols (struct comp_unit *unit) case DW_AT_decl_file: if (is_int_form (&attr)) - var->file = concat_filename (unit->line_table, - attr.u.val); + { + free (var->file); + var->file = concat_filename (unit->line_table, + attr.u.val); + } break; case DW_AT_decl_line: @@ -4347,13 +4418,23 @@ parse_comp_unit (struct dwarf2_debug *stash, if (version < 5) addr_size = read_1_byte (abfd, &info_ptr, end_ptr); - if (unit_type == DW_UT_type) + switch (unit_type) { + case DW_UT_type: /* Skip type signature. */ info_ptr += 8; /* Skip type offset. */ info_ptr += offset_size; + break; + + case DW_UT_skeleton: + /* Skip DWO_id field. */ + info_ptr += 8; + break; + + default: + break; } if (addr_size > sizeof (bfd_vma)) @@ -4562,21 +4643,20 @@ parse_comp_unit (struct dwarf2_debug *stash, really contains the given address. */ static bool -comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr) +comp_unit_may_contain_address (struct comp_unit *unit, bfd_vma addr) { struct arange *arange; if (unit->error) return false; - arange = &unit->arange; - do - { - if (addr >= arange->low && addr < arange->high) - return true; - arange = arange->next; - } - while (arange); + if (unit->arange.high == 0 /* No ranges have been computed yet. */ + || unit->line_table == NULL) /* The line info table has not been loaded. */ + return true; + + for (arange = &unit->arange; arange != NULL; arange = arange->next) + if (addr >= arange->low && addr < arange->high) + return true; return false; } @@ -4764,16 +4844,19 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, { look = debug_sections[debug_info].uncompressed_name; msec = bfd_get_section_by_name (abfd, look); - if (msec != NULL) + /* Testing SEC_HAS_CONTENTS is an anti-fuzzer measure. Of + course debug sections always have contents. */ + if (msec != NULL && (msec->flags & SEC_HAS_CONTENTS) != 0) return msec; look = debug_sections[debug_info].compressed_name; msec = bfd_get_section_by_name (abfd, look); - if (msec != NULL) + if (msec != NULL && (msec->flags & SEC_HAS_CONTENTS) != 0) return msec; for (msec = abfd->sections; msec != NULL; msec = msec->next) - if (startswith (msec->name, GNU_LINKONCE_INFO)) + if ((msec->flags & SEC_HAS_CONTENTS) != 0 + && startswith (msec->name, GNU_LINKONCE_INFO)) return msec; return NULL; @@ -4781,6 +4864,9 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, for (msec = after_sec->next; msec != NULL; msec = msec->next) { + if ((msec->flags & SEC_HAS_CONTENTS) == 0) + continue; + look = debug_sections[debug_info].uncompressed_name; if (strcmp (msec->name, look) == 0) return msec; @@ -4866,7 +4952,7 @@ unset_sections (struct dwarf2_debug *stash) i = stash->adjusted_section_count; p = stash->adjusted_sections; for (; i > 0; i--, p++) - p->section->vma = 0; + p->section->vma = p->orig_vma; } /* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a @@ -4907,10 +4993,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) { int is_debug_info; - if ((sect->output_section != NULL - && sect->output_section != sect - && (sect->flags & SEC_DEBUGGING) == 0) - || sect->vma != 0) + if (sect->output_section != NULL + && sect->output_section != sect + && (sect->flags & SEC_DEBUGGING) == 0) continue; is_debug_info = (strcmp (sect->name, debug_info_name) == 0 @@ -4951,10 +5036,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) bfd_size_type sz; int is_debug_info; - if ((sect->output_section != NULL - && sect->output_section != sect - && (sect->flags & SEC_DEBUGGING) == 0) - || sect->vma != 0) + if (sect->output_section != NULL + && sect->output_section != sect + && (sect->flags & SEC_DEBUGGING) == 0) continue; is_debug_info = (strcmp (sect->name, debug_info_name) == 0 @@ -4966,24 +5050,17 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) sz = sect->rawsize ? sect->rawsize : sect->size; - if (is_debug_info) - { - BFD_ASSERT (sect->alignment_power == 0); - sect->vma = last_dwarf; - last_dwarf += sz; - } - 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))); - sect->vma = last_vma; - last_vma += sz; - } - p->section = sect; + p->orig_vma = sect->vma; + + bfd_vma *v = is_debug_info ? &last_dwarf : &last_vma; + /* Align the new address to the current section + alignment. */ + bfd_vma mask = -(bfd_vma) 1 << sect->alignment_power; + *v = (*v + ~mask) & mask; + sect->vma = *v; + *v += sz; + p->adj_vma = sect->vma; p++; } @@ -5014,11 +5091,10 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, { struct funcinfo* each_func; struct funcinfo* best_fit = NULL; - bfd_vma best_fit_len = 0; + bfd_vma best_fit_len = (bfd_vma) -1; struct info_list_node *node; struct arange *arange; const char *name = bfd_asymbol_name (sym); - asection *sec = bfd_asymbol_section (sym); for (node = lookup_info_hash_table (hash_table, name); node; @@ -5029,11 +5105,9 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, arange; arange = arange->next) { - if ((!each_func->sec || each_func->sec == sec) - && addr >= arange->low + if (addr >= arange->low && addr < arange->high - && (!best_fit - || arange->high - arange->low < best_fit_len)) + && arange->high - arange->low < best_fit_len) { best_fit = each_func; best_fit_len = arange->high - arange->low; @@ -5043,7 +5117,6 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table, if (best_fit) { - best_fit->sec = sec; *filename_ptr = best_fit->file; *linenumber_ptr = best_fit->line; return true; @@ -5065,20 +5138,17 @@ info_hash_lookup_varinfo (struct info_hash_table *hash_table, const char **filename_ptr, unsigned int *linenumber_ptr) { - const char *name = bfd_asymbol_name (sym); - asection *sec = bfd_asymbol_section (sym); struct varinfo* each; struct info_list_node *node; + const char *name = bfd_asymbol_name (sym); for (node = lookup_info_hash_table (hash_table, name); node; node = node->next) { each = (struct varinfo *) node->info; - if (each->addr == addr - && (!each->sec || each->sec == sec)) + if (each->addr == addr) { - each->sec = sec; *filename_ptr = each->file; *linenumber_ptr = each->line; return true; @@ -5300,7 +5370,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, void **pinfo, bool do_place) { - size_t amt = sizeof (struct dwarf2_debug); bfd_size_type total_size; asection *msec; struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; @@ -5312,7 +5381,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, { /* Check that we did previously find some debug information before attempting to make use of it. */ - if (stash->f.bfd_ptr != NULL) + if (stash->f.dwarf_info_size != 0) { if (do_place && !place_sections (abfd, stash)) return false; @@ -5322,13 +5391,14 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, return false; } _bfd_dwarf2_cleanup_debug_info (abfd, pinfo); - memset (stash, 0, amt); + memset (stash, 0, sizeof (*stash)); } else { - stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); + stash = (struct dwarf2_debug *) bfd_zalloc (abfd, sizeof (*stash)); if (! stash) return false; + *pinfo = stash; } stash->orig_bfd = abfd; stash->debug_sections = debug_sections; @@ -5354,8 +5424,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, if (!stash->alt.trie_root) return false; - *pinfo = stash; - if (debug_bfd == NULL) debug_bfd = abfd; @@ -5404,14 +5472,11 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, /* 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 - compressed. In that case, read them all in and produce one - large stash. We do this in two passes - in the first pass we + there's more than one, try case two: read them all in and produce + one large stash. We do this in two passes - in the first pass we just accumulate the section sizes, and in the second pass we read in the section's contents. (The allows us to avoid - reallocing the data as we add sections to the stash.) If - some or all sections are compressed, then do things the slow - way, with a bunch of reallocs. */ + reallocing the data as we add sections to the stash.) */ if (! find_debug_info (debug_bfd, debug_sections, msec)) { @@ -5420,7 +5485,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, if (! read_section (debug_bfd, &stash->debug_sections[debug_info], symbols, 0, &stash->f.dwarf_info_buffer, &total_size)) - return false; + goto restore_vma; } else { @@ -5429,19 +5494,20 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, msec; msec = find_debug_info (debug_bfd, debug_sections, msec)) { + if (_bfd_section_size_insane (debug_bfd, msec)) + goto restore_vma; /* Catch PR25070 testcase overflowing size calculation here. */ - if (total_size + msec->size < total_size - || total_size + msec->size < msec->size) + if (total_size + msec->size < total_size) { bfd_set_error (bfd_error_no_memory); - return false; + goto restore_vma; } total_size += msec->size; } stash->f.dwarf_info_buffer = (bfd_byte *) bfd_malloc (total_size); if (stash->f.dwarf_info_buffer == NULL) - return false; + goto restore_vma; total_size = 0; for (msec = find_debug_info (debug_bfd, debug_sections, NULL); @@ -5457,7 +5523,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, if (!(bfd_simple_get_relocated_section_contents (debug_bfd, msec, stash->f.dwarf_info_buffer + total_size, symbols))) - return false; + goto restore_vma; total_size += size; } @@ -5466,6 +5532,10 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, stash->f.info_ptr = stash->f.dwarf_info_buffer; stash->f.dwarf_info_size = total_size; return true; + + restore_vma: + unset_sections (stash); + return false; } /* Parse the next DWARF2 compilation unit at FILE->INFO_PTR. */ @@ -5517,6 +5587,22 @@ stash_comp_unit (struct dwarf2_debug *stash, struct dwarf2_debug_file *file) info_ptr_unit, offset_size); if (each) { + if (file->comp_unit_tree == NULL) + file->comp_unit_tree + = splay_tree_new (splay_tree_compare_addr_range, + splay_tree_free_addr_range, NULL); + + struct addr_range *r + = (struct addr_range *)bfd_malloc (sizeof (struct addr_range)); + r->start = each->info_ptr_unit; + r->end = each->end_ptr; + splay_tree_node v = splay_tree_lookup (file->comp_unit_tree, + (splay_tree_key)r); + if (v != NULL || r->end <= r->start) + abort (); + splay_tree_insert (file->comp_unit_tree, (splay_tree_key)r, + (splay_tree_value)each); + if (file->all_comp_units) file->all_comp_units->prev_unit = each; else @@ -5622,18 +5708,7 @@ _bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo) return result; } -/* Find the source code location of SYMBOL. If SYMBOL is NULL - then find the nearest source code location corresponding to - the address SECTION + OFFSET. - Returns 1 if the line is found without error and fills in - FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was - NULL the FUNCTIONNAME_PTR is also filled in. - Returns 2 if partial information from _bfd_elf_find_function is - returned (function and maybe file) by looking at symbols. DWARF2 - info is present but not regarding the requested code location. - Returns 0 otherwise. - SYMBOLS contains the symbol table for ABFD. - DEBUG_SECTIONS contains the name of the dwarf debug sections. */ +/* See _bfd_dwarf2_find_nearest_line_with_alt. */ int _bfd_dwarf2_find_nearest_line (bfd *abfd, @@ -5647,6 +5722,43 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, unsigned int *discriminator_ptr, const struct dwarf_debug_section *debug_sections, void **pinfo) +{ + return _bfd_dwarf2_find_nearest_line_with_alt + (abfd, NULL, symbols, symbol, section, offset, filename_ptr, + functionname_ptr, linenumber_ptr, discriminator_ptr, debug_sections, + pinfo); +} + +/* Find the source code location of SYMBOL. If SYMBOL is NULL + then find the nearest source code location corresponding to + the address SECTION + OFFSET. + Returns 1 if the line is found without error and fills in + FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was + NULL the FUNCTIONNAME_PTR is also filled in. + Returns 2 if partial information from _bfd_elf_find_function is + returned (function and maybe file) by looking at symbols. DWARF2 + info is present but not regarding the requested code location. + Returns 0 otherwise. + SYMBOLS contains the symbol table for ABFD. + DEBUG_SECTIONS contains the name of the dwarf debug sections. + If ALT_FILENAME is given, attempt to open the file and use it + as the .gnu_debugaltlink file. Otherwise this file will be + searched for when needed. */ + +int +_bfd_dwarf2_find_nearest_line_with_alt + (bfd *abfd, + const char *alt_filename, + asymbol **symbols, + asymbol *symbol, + asection *section, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *linenumber_ptr, + unsigned int *discriminator_ptr, + const struct dwarf_debug_section *debug_sections, + void **pinfo) { /* Read each compilation unit from the section .debug_info, and check to see if it contains the address we are searching for. If yes, @@ -5678,6 +5790,23 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, stash = (struct dwarf2_debug *) *pinfo; + if (stash->alt.bfd_ptr == NULL && alt_filename != NULL) + { + bfd *alt_bfd = bfd_openr (alt_filename, NULL); + + if (alt_bfd == NULL) + /* bfd_openr will have set the bfd_error. */ + return false; + if (!bfd_check_format (alt_bfd, bfd_object)) + { + bfd_set_error (bfd_error_wrong_format); + bfd_close (alt_bfd); + return false; + } + + stash->alt.bfd_ptr = alt_bfd; + } + do_line = symbol != NULL; if (do_line) { @@ -5751,25 +5880,22 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, if (stash->info_hash_status == STASH_INFO_HASH_ON) { - found = stash_find_line_fast (stash, symbol, addr, filename_ptr, - linenumber_ptr); + found = stash_find_line_fast (stash, symbol, addr, + filename_ptr, linenumber_ptr); if (found) goto done; } - else - { - /* Check the previously read comp. units first. */ - for (each = stash->f.all_comp_units; each; each = each->next_unit) - if ((symbol->flags & BSF_FUNCTION) == 0 - || each->arange.high == 0 - || comp_unit_contains_address (each, addr)) - { - found = comp_unit_find_line (each, symbol, addr, filename_ptr, - linenumber_ptr); - if (found) - goto done; - } - } + + /* Check the previously read comp. units first. */ + for (each = stash->f.all_comp_units; each; each = each->next_unit) + if ((symbol->flags & BSF_FUNCTION) == 0 + || comp_unit_may_contain_address (each, addr)) + { + found = comp_unit_find_line (each, symbol, addr, filename_ptr, + linenumber_ptr); + if (found) + goto done; + } } else { @@ -5845,13 +5971,11 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, address. */ if (do_line) found = (((symbol->flags & BSF_FUNCTION) == 0 - || each->arange.high == 0 - || comp_unit_contains_address (each, addr)) + || comp_unit_may_contain_address (each, addr)) && comp_unit_find_line (each, symbol, addr, filename_ptr, linenumber_ptr)); else - found = ((each->arange.high == 0 - || comp_unit_contains_address (each, addr)) + found = (comp_unit_may_contain_address (each, addr) && comp_unit_find_nearest_line (each, addr, filename_ptr, &function, @@ -5902,8 +6026,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd, } } - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) - unset_sections (stash); + unset_sections (stash); return found; } @@ -5990,6 +6113,8 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) free (file->line_table->dirs); } htab_delete (file->abbrev_offsets); + if (file->comp_unit_tree != NULL) + splay_tree_delete (file->comp_unit_tree); free (file->dwarf_line_str_buffer); free (file->dwarf_str_buffer);