Blame SOURCES/binutils-2.25.1-objdump-speedup.patch

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