diff -rup binutils.orig/bfd/dwarf2.c binutils-2.25.1/bfd/dwarf2.c --- binutils.orig/bfd/dwarf2.c 2017-01-16 14:48:05.110778762 +0000 +++ binutils-2.25.1/bfd/dwarf2.c 2017-01-16 14:51:04.915885225 +0000 @@ -144,16 +144,16 @@ struct dwarf2_debug /* Length of the loaded .debug_str section. */ bfd_size_type dwarf_str_size; - /* Pointer to the .debug_ranges section loaded into memory. */ + /* Pointer to the .debug_ranges section loaded into memory. */ bfd_byte *dwarf_ranges_buffer; - /* Length of the loaded .debug_ranges section. */ + /* Length of the loaded .debug_ranges section. */ bfd_size_type dwarf_ranges_size; /* If the most recent call to bfd_find_nearest_line was given an address in an inlined function, preserve a pointer into the calling chain for subsequent calls to bfd_find_inliner_info to - use. */ + use. */ struct funcinfo *inliner_chain; /* Section VMAs at the time the stash was built. */ @@ -212,9 +212,12 @@ struct comp_unit /* Keep the bfd convenient (for memory allocation). */ bfd *abfd; - /* The lowest and highest addresses contained in this compilation - unit as specified in the compilation unit header. */ + /* Linked list of the low and high address ranges contained in this + compilation unit as specified in the compilation unit header. */ struct arange arange; + /* A single arange containing the lowest and highest + addresses covered by the compilation unit. */ + struct arange minmax; /* The DW_AT_name attribute (for error messages). */ char *name; @@ -256,6 +259,12 @@ struct comp_unit /* A list of the functions found in this comp. unit. */ struct funcinfo *function_table; + /* A table of function information references searchable by address. */ + struct lookup_funcinfo *lookup_funcinfo_table; + + /* Number of functions in the function_table and sorted_function_table. */ + bfd_size_type number_of_functions; + /* A list of the variables found in this comp. unit. */ struct varinfo *variable_table; @@ -390,7 +399,7 @@ struct info_hash_table struct bfd_hash_table base; }; -/* Function to create a new entry in info hash table. */ +/* Function to create a new entry in info hash table. */ static struct bfd_hash_entry * info_hash_table_newfunc (struct bfd_hash_entry *entry, @@ -476,7 +485,7 @@ insert_info_hash_table (struct info_hash } /* Look up an info entry list from an info hash table. Return NULL - if there is none. */ + if there is none. */ static struct info_list_node * lookup_info_hash_table (struct info_hash_table *hash_table, const char *key) @@ -517,8 +526,8 @@ read_section (bfd * abfd, } if (! msec) { - (*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."), - sec->uncompressed_name); + _bfd_error_handler (_("Dwarf Error: Can't find %s section."), + sec->uncompressed_name); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -546,9 +555,10 @@ read_section (bfd * abfd, that the client wants. Validate it here to avoid trouble later. */ if (offset != 0 && offset >= *section_size) { - (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu)" - " greater than or equal to %s size (%lu)."), - (long) offset, section_name, *section_size); + /* xgettext: c-format */ + _bfd_error_handler (_("Dwarf Error: Offset (%lu)" + " greater than or equal to %s size (%lu)."), + (long) offset, section_name, *section_size); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1157,8 +1167,8 @@ read_attribute_value (struct attribute * 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."), - form); + _bfd_error_handler (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), + form); bfd_set_error (bfd_error_bad_value); return NULL; } @@ -1213,22 +1223,22 @@ non_mangled (int lang) struct line_info { - struct line_info* prev_line; - bfd_vma address; - char *filename; - unsigned int line; - unsigned int column; - unsigned int discriminator; - unsigned char op_index; - unsigned char end_sequence; /* End of (sequential) code sequence. */ + struct line_info * prev_line; + bfd_vma address; + char * filename; + unsigned int line; + unsigned int column; + unsigned int discriminator; + unsigned char op_index; + unsigned char end_sequence; /* End of (sequential) code sequence. */ }; struct fileinfo { - char *name; - unsigned int dir; - unsigned int time; - unsigned int size; + char * name; + unsigned int dir; + unsigned int time; + unsigned int size; }; struct line_sequence @@ -1236,11 +1246,13 @@ struct line_sequence bfd_vma low_pc; struct line_sequence* prev_sequence; struct line_info* last_line; /* Largest VMA. */ + struct line_info** line_info_lookup; + bfd_size_type num_lines; }; struct line_info_table { - bfd* abfd; + bfd * abfd; unsigned int num_files; unsigned int num_dirs; unsigned int num_sequences; @@ -1259,23 +1271,37 @@ struct line_info_table struct funcinfo { /* Pointer to previous function in list of all functions. */ - struct funcinfo *prev_func; + struct funcinfo * prev_func; /* Pointer to function one scope higher. */ - struct funcinfo *caller_func; + struct funcinfo * caller_func; /* Source location file name where caller_func inlines this func. */ - char *caller_file; + char * caller_file; /* Source location file name. */ - char *file; + char * file; /* Source location line number where caller_func inlines this func. */ - int caller_line; + int caller_line; /* Source location line number. */ - int line; - int tag; - bfd_boolean is_linkage; - const char *name; - struct arange arange; + int line; + int tag; + bfd_boolean is_linkage; + const char * name; + struct arange arange; /* Where the symbol is defined. */ - asection *sec; + asection * sec; +}; + +struct lookup_funcinfo +{ + /* Function information corresponding to this lookup table entry. */ + struct funcinfo * funcinfo; + + /* The lowest address for this specific function. */ + bfd_vma low_addr; + + /* The highest address of this function before the lookup table is sorted. + The highest address of all prior functions after the lookup table is + sorted, which is used for binary search. */ + bfd_vma high_addr; }; struct varinfo @@ -1446,7 +1472,7 @@ concat_filename (struct line_info_table { /* FILE == 0 means unknown. */ if (file) - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: mangled line number section (bad file number).")); return strdup (""); } @@ -1502,7 +1528,7 @@ concat_filename (struct line_info_table } static bfd_boolean -arange_add (const struct comp_unit *unit, struct arange *first_arange, +arange_add (struct comp_unit *unit, struct arange *first_arange, bfd_vma low_pc, bfd_vma high_pc) { struct arange *arange; @@ -1514,11 +1540,16 @@ arange_add (const struct comp_unit *unit /* If the first arange is empty, use it. */ if (first_arange->high == 0) { - first_arange->low = low_pc; - first_arange->high = high_pc; + unit->minmax.low = first_arange->low = low_pc; + unit->minmax.high = first_arange->high = high_pc; return TRUE; } + if (unit->minmax.low > low_pc) + unit->minmax.low = low_pc; + if (unit->minmax.high < high_pc) + unit->minmax.high = high_pc; + /* Next see if we can cheaply extend an existing range. */ arange = first_arange; do @@ -1538,7 +1569,7 @@ arange_add (const struct comp_unit *unit while (arange); /* Need to allocate a new arange and insert it into the arange list. - Order isn't significant, so just insert after the first arange. */ + Order isn't significant, so just insert after the first arange. */ arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange)); if (arange == NULL) return FALSE; @@ -1578,17 +1609,62 @@ compare_sequences (const void* a, const return 0; } +/* Construct the line information table for quick lookup. */ + +static bfd_boolean +build_line_info_table (struct line_info_table * table, + struct line_sequence * seq) +{ + bfd_size_type amt; + struct line_info** line_info_lookup; + struct line_info* each_line; + unsigned int num_lines; + unsigned int line_index; + + if (seq->line_info_lookup != NULL) + return TRUE; + + /* Count the number of line information entries. We could do this while + scanning the debug information, but some entries may be added via + lcl_head without having a sequence handy to increment the number of + lines. */ + num_lines = 0; + for (each_line = seq->last_line; each_line; each_line = each_line->prev_line) + num_lines++; + + if (num_lines == 0) + return TRUE; + + /* Allocate space for the line information lookup table. */ + amt = sizeof (struct line_info*) * num_lines; + line_info_lookup = (struct line_info**) bfd_alloc (table->abfd, amt); + if (line_info_lookup == NULL) + return FALSE; + + /* Create the line information lookup table. */ + line_index = num_lines; + for (each_line = seq->last_line; each_line; each_line = each_line->prev_line) + line_info_lookup[--line_index] = each_line; + + BFD_ASSERT (line_index == 0); + + seq->num_lines = num_lines; + seq->line_info_lookup = line_info_lookup; + + return TRUE; +} + /* Sort the line sequences for quick lookup. */ static bfd_boolean sort_line_sequences (struct line_info_table* table) { - bfd_size_type amt; - struct line_sequence* sequences; - struct line_sequence* seq; - unsigned int n = 0; - unsigned int num_sequences = table->num_sequences; - bfd_vma last_high_pc; + bfd_size_type amt; + struct line_sequence* sequences; + struct line_sequence* seq; + unsigned int n = 0; + unsigned int num_sequences = table->num_sequences; + bfd_vma last_high_pc; if (num_sequences == 0) return TRUE; @@ -1609,6 +1685,8 @@ sort_line_sequences (struct line_info_ta sequences[n].low_pc = seq->low_pc; sequences[n].prev_sequence = NULL; sequences[n].last_line = seq->last_line; + sequences[n].line_info_lookup = NULL; + sequences[n].num_lines = 0; seq = seq->prev_sequence; free (last_seq); } @@ -1687,7 +1765,7 @@ decode_line_info (struct comp_unit *unit if (stash->dwarf_line_size < 16) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Line info section is too small (%ld)"), (long) stash->dwarf_line_size); bfd_set_error (bfd_error_bad_value); @@ -1716,7 +1794,8 @@ decode_line_info (struct comp_unit *unit if (lh.total_length > stash->dwarf_line_size) { - (*_bfd_error_handler) + _bfd_error_handler + /* xgettext: c-format */ (_("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); @@ -1728,7 +1807,7 @@ decode_line_info (struct comp_unit *unit lh.version = read_2_bytes (abfd, line_ptr, line_end); if (lh.version < 2 || lh.version > 4) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Unhandled .debug_line version %d."), lh.version); bfd_set_error (bfd_error_bad_value); return NULL; @@ -1737,7 +1816,7 @@ decode_line_info (struct comp_unit *unit if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Ran out of room reading prologue")); bfd_set_error (bfd_error_bad_value); return NULL; @@ -1762,7 +1841,7 @@ decode_line_info (struct comp_unit *unit if (lh.maximum_ops_per_insn == 0) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Invalid maximum operations per instruction.")); bfd_set_error (bfd_error_bad_value); return NULL; @@ -1782,7 +1861,7 @@ decode_line_info (struct comp_unit *unit if (line_ptr + (lh.opcode_base - 1) >= line_end) { - (*_bfd_error_handler) (_("Dwarf Error: Ran out of room reading opcodes")); + _bfd_error_handler (_("Dwarf Error: Ran out of room reading opcodes")); bfd_set_error (bfd_error_bad_value); return NULL; } @@ -1969,7 +2048,7 @@ decode_line_info (struct comp_unit *unit line_ptr += exop_len - 1; break; default: - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: mangled line number section.")); bfd_set_error (bfd_error_bad_value); line_fail: @@ -2089,7 +2168,7 @@ lookup_address_in_line_info_table (struc unsigned int *discriminator_ptr) { struct line_sequence *seq = NULL; - struct line_info *each_line; + struct line_info *info; int low, high, mid; /* Binary search the array of sequences. */ @@ -2107,26 +2186,43 @@ lookup_address_in_line_info_table (struc break; } - if (seq && addr >= seq->low_pc && addr < seq->last_line->address) + /* Check for a valid sequence. */ + if (!seq || addr < seq->low_pc || addr >= seq->last_line->address) + goto fail; + + if (!build_line_info_table (table, seq)) + goto fail; + + /* Binary search the array of line information. */ + low = 0; + high = seq->num_lines; + info = NULL; + while (low < high) { - /* Note: seq->last_line should be a descendingly sorted list. */ - for (each_line = seq->last_line; - each_line; - each_line = each_line->prev_line) - if (addr >= each_line->address) - break; + mid = (low + high) / 2; + info = seq->line_info_lookup[mid]; + if (addr < info->address) + high = mid; + else if (addr >= seq->line_info_lookup[mid + 1]->address) + low = mid + 1; + else + break; + } - if (each_line - && !(each_line->end_sequence || each_line == seq->last_line)) - { - *filename_ptr = each_line->filename; - *linenumber_ptr = each_line->line; - if (discriminator_ptr) - *discriminator_ptr = each_line->discriminator; - return seq->last_line->address - seq->low_pc; - } + /* Check for a valid line information entry. */ + if (info + && addr >= info->address + && addr < seq->line_info_lookup[mid + 1]->address + && !(info->end_sequence || info == seq->last_line)) + { + *filename_ptr = info->filename; + *linenumber_ptr = info->line; + if (discriminator_ptr) + *discriminator_ptr = info->discriminator; + return seq->last_line->address - seq->low_pc; } +fail: *filename_ptr = NULL; return 0; } @@ -2134,16 +2230,102 @@ lookup_address_in_line_info_table (struc /* Read in the .debug_ranges section for future reference. */ static bfd_boolean -read_debug_ranges (struct comp_unit *unit) +read_debug_ranges (struct comp_unit * unit) { - struct dwarf2_debug *stash = unit->stash; + struct dwarf2_debug * stash = unit->stash; + return read_section (unit->abfd, &stash->debug_sections[debug_ranges], stash->syms, 0, - &stash->dwarf_ranges_buffer, &stash->dwarf_ranges_size); + &stash->dwarf_ranges_buffer, + &stash->dwarf_ranges_size); } /* Function table functions. */ +static int +compare_lookup_funcinfos (const void * a, const void * b) +{ + const struct lookup_funcinfo * lookup1 = a; + const struct lookup_funcinfo * lookup2 = b; + + if (lookup1->low_addr < lookup2->low_addr) + return -1; + if (lookup1->low_addr > lookup2->low_addr) + return 1; + if (lookup1->high_addr < lookup2->high_addr) + return -1; + if (lookup1->high_addr > lookup2->high_addr) + return 1; + + return 0; +} + +static bfd_boolean +build_lookup_funcinfo_table (struct comp_unit * unit) +{ + struct lookup_funcinfo *lookup_funcinfo_table = unit->lookup_funcinfo_table; + unsigned int number_of_functions = unit->number_of_functions; + struct funcinfo *each; + struct lookup_funcinfo *entry; + size_t func_index; + struct arange *range; + bfd_vma low_addr, high_addr; + + if (lookup_funcinfo_table || number_of_functions == 0) + return TRUE; + + /* Create the function info lookup table. */ + lookup_funcinfo_table = (struct lookup_funcinfo *) + bfd_malloc (number_of_functions * sizeof (struct lookup_funcinfo)); + if (lookup_funcinfo_table == NULL) + return FALSE; + + /* Populate the function info lookup table. */ + func_index = number_of_functions; + for (each = unit->function_table; each; each = each->prev_func) + { + entry = &lookup_funcinfo_table[--func_index]; + entry->funcinfo = each; + + /* Calculate the lowest and highest address for this function entry. */ + low_addr = entry->funcinfo->arange.low; + high_addr = entry->funcinfo->arange.high; + + for (range = entry->funcinfo->arange.next; range; range = range->next) + { + if (range->low < low_addr) + low_addr = range->low; + if (range->high > high_addr) + high_addr = range->high; + } + + entry->low_addr = low_addr; + entry->high_addr = high_addr; + } + + BFD_ASSERT (func_index == 0); + + /* Sort the function by address. */ + qsort (lookup_funcinfo_table, + number_of_functions, + sizeof (struct lookup_funcinfo), + compare_lookup_funcinfos); + + /* Calculate the high watermark for each function in the lookup table. */ + high_addr = lookup_funcinfo_table[0].high_addr; + for (func_index = 1; func_index < number_of_functions; func_index++) + { + entry = &lookup_funcinfo_table[func_index]; + if (entry->high_addr > high_addr) + high_addr = entry->high_addr; + else + entry->high_addr = high_addr; + } + + unit->lookup_funcinfo_table = lookup_funcinfo_table; + return TRUE; +} + /* 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 @@ -2154,37 +2336,77 @@ lookup_address_in_function_table (struct bfd_vma addr, struct funcinfo **function_ptr) { - struct funcinfo* each_func; + unsigned int number_of_functions = unit->number_of_functions; + struct lookup_funcinfo* lookup_funcinfo = NULL; + struct funcinfo* funcinfo = NULL; struct funcinfo* best_fit = NULL; bfd_vma best_fit_len = 0; + bfd_size_type low, high, mid, first; struct arange *arange; - for (each_func = unit->function_table; - each_func; - each_func = each_func->prev_func) + if (number_of_functions == 0) + return FALSE; + + if (!build_lookup_funcinfo_table (unit)) + return FALSE; + + if (unit->lookup_funcinfo_table[number_of_functions - 1].high_addr < addr) + return FALSE; + + /* Find the first function in the lookup table which may contain the + specified address. */ + low = 0; + high = number_of_functions; + first = high; + while (low < high) { - for (arange = &each_func->arange; - arange; - arange = arange->next) + mid = (low + high) / 2; + lookup_funcinfo = &unit->lookup_funcinfo_table[mid]; + if (addr < lookup_funcinfo->low_addr) + high = mid; + else if (addr >= lookup_funcinfo->high_addr) + low = mid + 1; + else + high = first = mid; + } + + /* Find the 'best' match for the address. The prior algorithm defined the + best match as the function with the smallest address range containing + the specified address. This definition should probably be changed to the + innermost inline routine containing the address, but right now we want + to get the same results we did before. */ + while (first < number_of_functions) + { + if (addr < unit->lookup_funcinfo_table[first].low_addr) + break; + funcinfo = unit->lookup_funcinfo_table[first].funcinfo; + + for (arange = &funcinfo->arange; arange; arange = arange->next) { - if (addr >= arange->low && addr < arange->high) + if (addr < arange->low || addr >= arange->high) + continue; + + if (!best_fit + || 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. */ + || (arange->high - arange->low == best_fit_len + && funcinfo > best_fit)) { - if (!best_fit - || arange->high - arange->low < best_fit_len) - { - best_fit = each_func; - best_fit_len = arange->high - arange->low; - } + best_fit = funcinfo; + best_fit_len = arange->high - arange->low; } } - } - if (best_fit) - { - *function_ptr = best_fit; - return TRUE; + first++; } - return FALSE; + + if (!best_fit) + return FALSE; + + *function_ptr = best_fit; + return TRUE; } /* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR @@ -2269,8 +2491,8 @@ lookup_symbol_in_variable_table (struct *linenumber_ptr = each->line; return TRUE; } - else - return FALSE; + + return FALSE; } static char * @@ -2326,7 +2548,7 @@ find_abstract_instance_name (struct comp info_ptr = read_alt_indirect_ref (unit, die_ref); if (info_ptr == NULL) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Unable to read alt ref %u."), die_ref); bfd_set_error (bfd_error_bad_value); return NULL; @@ -2350,7 +2572,7 @@ find_abstract_instance_name (struct comp abbrev = lookup_abbrev (abbrev_number, unit->abbrevs); if (! abbrev) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); bfd_set_error (bfd_error_bad_value); } @@ -2494,7 +2716,7 @@ scan_unit_for_symbols (struct comp_unit abbrev = lookup_abbrev (abbrev_number,unit->abbrevs); if (! abbrev) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); bfd_set_error (bfd_error_bad_value); @@ -2513,6 +2735,7 @@ scan_unit_for_symbols (struct comp_unit func->tag = abbrev->tag; func->prev_func = unit->function_table; unit->function_table = func; + unit->number_of_functions++; BFD_ASSERT (!unit->cached); if (func->tag == DW_TAG_inlined_subroutine) @@ -2766,7 +2989,8 @@ parse_comp_unit (struct dwarf2_debug *st if (addr_size > sizeof (bfd_vma)) { - (*_bfd_error_handler) + _bfd_error_handler + /* xgettext: c-format */ (_("Dwarf Error: found address size '%u', this reader" " can not handle sizes greater than '%u'."), addr_size, @@ -2777,7 +3001,7 @@ parse_comp_unit (struct dwarf2_debug *st if (addr_size != 2 && addr_size != 4 && addr_size != 8) { - (*_bfd_error_handler) + _bfd_error_handler ("Dwarf Error: found address size '%u', this reader" " can only handle address sizes '2', '4' and '8'.", addr_size); bfd_set_error (bfd_error_bad_value); @@ -2845,7 +3069,7 @@ parse_comp_unit (struct dwarf2_debug *st low_pc = attr.u.val; /* If the compilation unit DIE has a DW_AT_low_pc attribute, this is the base address to use when reading location - lists or range lists. */ + lists or range lists. */ if (abbrev->tag == DW_TAG_compile_unit) unit->base_address = low_pc; break; @@ -2867,7 +3091,7 @@ parse_comp_unit (struct dwarf2_debug *st /* PR 17512: file: 1fe726be. */ if (! is_str_attr (attr.form)) { - (*_bfd_error_handler) + _bfd_error_handler (_("Dwarf Error: DW_AT_comp_dir attribute encountered with a non-string form.")); comp_dir = NULL; } @@ -2919,6 +3143,11 @@ comp_unit_contains_address (struct comp_ if (unit->error) return FALSE; + if (unit->minmax.high < addr || unit->minmax.low > addr) + return FALSE; + + /* We know that the address *might* be contained within this comp + unit, but we cannot be sure until we check the specific ranges. */ arange = &unit->arange; do { @@ -3116,7 +3345,7 @@ comp_unit_hash_info (struct dwarf2_debug each_func && okay; each_func = each_func->prev_func) { - /* Skip nameless functions. */ + /* Skip nameless functions. */ if (each_func->name) /* There is no need to copy name string into hash table as name string is either in the dwarf string buffer or @@ -3498,7 +3727,7 @@ stash_maybe_update_info_hash_tables (str return TRUE; } -/* Check consistency of info hash tables. This is for debugging only. */ +/* Check consistency of info hash tables. This is for debugging only. */ static void ATTRIBUTE_UNUSED stash_verify_info_hash_table (struct dwarf2_debug *stash) @@ -3930,7 +4159,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd stash_maybe_enable_info_hash_tables (abfd, stash); /* Keep info hash table up to date if they are available. Note that we - may disable the hash tables if there is any error duing update. */ + may disable the hash tables if there is any error duing update. */ if (stash->info_hash_status == STASH_INFO_HASH_ON) stash_maybe_update_info_hash_tables (stash); @@ -4222,6 +4451,12 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abf function_table = function_table->prev_func; } + if (each->lookup_funcinfo_table) + { + free (each->lookup_funcinfo_table); + each->lookup_funcinfo_table = NULL; + } + while (variable_table) { if (variable_table->file) diff -rup binutils.orig/binutils/objdump.c binutils-2.25.1/binutils/objdump.c --- binutils.orig/binutils/objdump.c 2017-01-16 14:48:06.214761408 +0000 +++ binutils-2.25.1/binutils/objdump.c 2017-01-16 14:50:19.313618730 +0000 @@ -3439,7 +3439,7 @@ display_any_bfd (bfd *file, int level) } static void -display_file (char *filename, char *target) +display_file (char *filename, char *target, bfd_boolean last_file) { bfd *file; @@ -3458,7 +3458,14 @@ display_file (char *filename, char *targ display_any_bfd (file, 0); - bfd_close (file); + /* This is an optimization to improve the speed of objdump, especially when + dumping a file with lots of associated debug informatiom. Closing such + a file can take a non-trivial amount of time as there are lots of lists + to walk and buffers to free. This is only really necessary however if + we are about to load another file. Otherwise, if we are about to exit, + then we can save (a lot of) time by not bothering to do any tidying up. */ + if (! last_file) + bfd_close (file); } int @@ -3736,10 +3743,13 @@ main (int argc, char **argv) else { if (optind == argc) - display_file ("a.out", target); + display_file ("a.out", target, TRUE); else for (; optind < argc;) - display_file (argv[optind++], target); + { + display_file (argv[optind], target, optind == argc - 1); + optind++; + } } free_only_list ();