dwarf2.c:bfd_find_nearest_line et al

Alan Modra amodra@gmail.com
Wed May 16 14:00:00 GMT 2012


A couple of fixes, some optimisation, and formatting.
The fixes:
- find_line allows a comp unit to be searched for matching lines if
comp_unit_contains_address is true *or* the comp unit has no address
range info, but only on first parse of the comp unit.  We can't revist
a comp unit without address range info.  I think this bug goes all the
way back to rev 1.6 of dwarf2.c.
- parse_comp_unit set unit_base_address regardless of the type of DIE.
It ought to always be DW_TAG_compile_unit, so this is only a minor
bug.
The optimisations:
- When loading debug info, make use of hashed section by name lookup
when we can, rather than interation over all sections.
- Use bfd_alloc rather than bfd_zalloc in cases where all of the
memory allocated is soon written.
- Don't clutter arange list with empty ranges.  These are the (1,1)
ranges generated when --gc-sections drops sections.

	* dwarf2.c: Formatting.
	(arange_add): Pass in unit rather than bfd.  Update callers.
	Ignore empty ranges.  Don't ask for cleared memory.
	(parse_comp_unit): Only set unit->base_address if processing
	DW_TAG_compile_unit.
	(find_debug_info): Optimise section lookup.
	(place_sections): Use bfd_alloc for stash->adjusted_sections.
	(find_line): Match previously parsed comp unit addresses as we
	do for newly parsed comp units.

Index: bfd/dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.147
diff -u -p -r1.147 dwarf2.c
--- bfd/dwarf2.c	3 May 2012 12:49:22 -0000	1.147
+++ bfd/dwarf2.c	16 May 2012 11:45:45 -0000
@@ -405,8 +405,8 @@ create_info_hash_table (bfd *abfd)
 {
   struct info_hash_table *hash_table;
 
-  hash_table = (struct info_hash_table *)
-      bfd_alloc (abfd, sizeof (struct info_hash_table));
+  hash_table = ((struct info_hash_table *)
+		bfd_alloc (abfd, sizeof (struct info_hash_table)));
   if (!hash_table)
     return hash_table;
 
@@ -503,7 +503,7 @@ read_section (bfd *           abfd,
       if (syms)
 	{
 	  *section_buffer
-	      = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+	    = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
 	  if (! *section_buffer)
 	    return FALSE;
 	}
@@ -522,7 +522,8 @@ 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)."),
+      (*_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;
@@ -1014,20 +1015,27 @@ struct line_info_table
 /* Remember some information about each function.  If the function is
    inlined (DW_TAG_inlined_subroutine) it may have two additional
    attributes, DW_AT_call_file and DW_AT_call_line, which specify the
-   source code location where this function was inlined. */
+   source code location where this function was inlined.  */
 
 struct funcinfo
 {
-  struct funcinfo *prev_func;		/* Pointer to previous function in list of all functions */
-  struct funcinfo *caller_func;		/* Pointer to function one scope higher */
-  char *caller_file;			/* Source location file name where caller_func inlines this func */
-  int caller_line;			/* Source location line number where caller_func inlines this func */
-  char *file;				/* Source location file name */
-  int line;				/* Source location line number */
+  /* Pointer to previous function in list of all functions.  */
+  struct funcinfo *prev_func;
+  /* Pointer to function one scope higher.  */
+  struct funcinfo *caller_func;
+  /* Source location file name where caller_func inlines this func.  */
+  char *caller_file;
+  /* Source location line number where caller_func inlines this func.  */
+  int caller_line;
+  /* Source location file name.  */
+  char *file;
+  /* Source location line number.  */
+  int line;
   int tag;
   char *name;
   struct arange arange;
-  asection *sec;			/* Where the symbol is defined */
+  /* Where the symbol is defined.  */
+  asection *sec;
 };
 
 struct varinfo
@@ -1248,12 +1256,16 @@ concat_filename (struct line_info_table 
 }
 
 static bfd_boolean
-arange_add (bfd *abfd, struct arange *first_arange,
+arange_add (const struct comp_unit *unit, struct arange *first_arange,
 	    bfd_vma low_pc, bfd_vma high_pc)
 {
   struct arange *arange;
 
-  /* If the first arange is empty, use it. */
+  /* Ignore empty ranges.  */
+  if (low_pc == high_pc)
+    return TRUE;
+
+  /* If the first arange is empty, use it.  */
   if (first_arange->high == 0)
     {
       first_arange->low = low_pc;
@@ -1281,7 +1293,7 @@ arange_add (bfd *abfd, struct arange *fi
 
   /* Need to allocate a new arange and insert it into the arange list.
      Order isn't significant, so just insert after the first arange. */
-  arange = (struct arange *) bfd_zalloc (abfd, sizeof (*arange));
+  arange = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange));
   if (arange == NULL)
     return FALSE;
   arange->low = low_pc;
@@ -1582,15 +1594,15 @@ decode_line_info (struct comp_unit *unit
 	      /* Special operand.  */
 	      adj_opcode = op_code - lh.opcode_base;
 	      if (lh.maximum_ops_per_insn == 1)
-		address += (adj_opcode / lh.line_range)
-			   * lh.minimum_instruction_length;
+		address += (adj_opcode / lh.line_range
+			    * lh.minimum_instruction_length);
 	      else
 		{
-		  address += ((op_index + (adj_opcode / lh.line_range))
-			      / lh.maximum_ops_per_insn)
-			     * lh.minimum_instruction_length;
-		  op_index = (op_index + (adj_opcode / lh.line_range))
-			     % lh.maximum_ops_per_insn;
+		  address += ((op_index + adj_opcode / lh.line_range)
+			      / lh.maximum_ops_per_insn
+			      * lh.minimum_instruction_length);
+		  op_index = ((op_index + adj_opcode / lh.line_range)
+			      % lh.maximum_ops_per_insn);
 		}
 	      line += lh.line_base + (adj_opcode % lh.line_range);
 	      /* Append row to matrix using current values.  */
@@ -1605,7 +1617,7 @@ decode_line_info (struct comp_unit *unit
 	  else switch (op_code)
 	    {
 	    case DW_LNS_extended_op:
-              exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	      exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
 	      line_ptr += bytes_read;
 	      extended_op = read_1_byte (abfd, line_ptr);
 	      line_ptr += 1;
@@ -1621,7 +1633,7 @@ decode_line_info (struct comp_unit *unit
 		    low_pc = address;
 		  if (address > high_pc)
 		    high_pc = address;
-		  if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+		  if (!arange_add (unit, &unit->arange, low_pc, high_pc))
 		    goto line_fail;
 		  break;
 		case DW_LNE_set_address:
@@ -1659,11 +1671,12 @@ decode_line_info (struct comp_unit *unit
 		  (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
 		  line_ptr += bytes_read;
 		  break;
-                case DW_LNE_HP_source_file_correlation:
-                  line_ptr += exop_len - 1;
-                  break;
+		case DW_LNE_HP_source_file_correlation:
+		  line_ptr += exop_len - 1;
+		  break;
 		default:
-		  (*_bfd_error_handler) (_("Dwarf Error: mangled line number section."));
+		  (*_bfd_error_handler)
+		    (_("Dwarf Error: mangled line number section."));
 		  bfd_set_error (bfd_error_bad_value);
 		line_fail:
 		  if (filename != NULL)
@@ -1682,15 +1695,15 @@ decode_line_info (struct comp_unit *unit
 	      break;
 	    case DW_LNS_advance_pc:
 	      if (lh.maximum_ops_per_insn == 1)
-		address += lh.minimum_instruction_length
-			   * read_unsigned_leb128 (abfd, line_ptr,
-						   &bytes_read);
+		address += (lh.minimum_instruction_length
+			    * read_unsigned_leb128 (abfd, line_ptr,
+						    &bytes_read));
 	      else
 		{
 		  bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr,
 							 &bytes_read);
-		  address = ((op_index + adjust) / lh.maximum_ops_per_insn)
-			    * lh.minimum_instruction_length;
+		  address = ((op_index + adjust) / lh.maximum_ops_per_insn
+			     * lh.minimum_instruction_length);
 		  op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
 		}
 	      line_ptr += bytes_read;
@@ -1723,13 +1736,14 @@ decode_line_info (struct comp_unit *unit
 	      break;
 	    case DW_LNS_const_add_pc:
 	      if (lh.maximum_ops_per_insn == 1)
-		address += lh.minimum_instruction_length
-			   * ((255 - lh.opcode_base) / lh.line_range);
+		address += (lh.minimum_instruction_length
+			    * ((255 - lh.opcode_base) / lh.line_range));
 	      else
 		{
 		  bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range);
-		  address += lh.minimum_instruction_length
-			     * ((op_index + adjust) / lh.maximum_ops_per_insn);
+		  address += (lh.minimum_instruction_length
+			      * ((op_index + adjust)
+				 / lh.maximum_ops_per_insn));
 		  op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
 		}
 	      break;
@@ -1855,8 +1869,9 @@ lookup_address_in_function_table (struct
 	{
 	  if (addr >= arange->low && addr < arange->high)
 	    {
-	      if (!best_fit ||
-		  ((arange->high - arange->low) < (best_fit->arange.high - best_fit->arange.low)))
+	      if (!best_fit
+		  || (arange->high - arange->low
+		      < best_fit->arange.high - best_fit->arange.low))
 		best_fit = each_func;
 	    }
 	}
@@ -1904,8 +1919,8 @@ lookup_symbol_in_function_table (struct 
 	      && each_func->name
 	      && strcmp (name, each_func->name) == 0
 	      && (!best_fit
-		  || ((arange->high - arange->low)
-		      < (best_fit->arange.high - best_fit->arange.low))))
+		  || (arange->high - arange->low
+		      < best_fit->arange.high - best_fit->arange.low)))
 	    best_fit = each_func;
 	}
     }
@@ -1990,8 +2005,8 @@ find_abstract_instance_name (struct comp
       abbrev = lookup_abbrev (abbrev_number, unit->abbrevs);
       if (! abbrev)
 	{
-	  (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
-				 abbrev_number);
+	  (*_bfd_error_handler)
+	    (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number);
 	  bfd_set_error (bfd_error_bad_value);
 	}
       else
@@ -2056,7 +2071,7 @@ read_rangelist (struct comp_unit *unit, 
 	base_address = high_pc;
       else
 	{
-	  if (!arange_add (unit->abfd, arange,
+	  if (!arange_add (unit, arange,
 			   base_address + low_pc, base_address + high_pc))
 	    return FALSE;
 	}
@@ -2082,7 +2097,7 @@ scan_unit_for_symbols (struct comp_unit 
      can use to set the caller_func field.  */
   nested_funcs_size = 32;
   nested_funcs = (struct funcinfo **)
-      bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
+    bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
   if (nested_funcs == NULL)
     return FALSE;
   nested_funcs[nesting_level] = 0;
@@ -2286,7 +2301,7 @@ scan_unit_for_symbols (struct comp_unit 
 
       if (func && high_pc != 0)
 	{
-	  if (!arange_add (unit->abfd, &func->arange, low_pc, high_pc))
+	  if (!arange_add (unit, &func->arange, low_pc, high_pc))
 	    goto fail;
 	}
 
@@ -2300,8 +2315,8 @@ scan_unit_for_symbols (struct comp_unit 
 
 	      nested_funcs_size *= 2;
 	      tmp = (struct funcinfo **)
-                 bfd_realloc (nested_funcs,
-                              (nested_funcs_size * sizeof (struct funcinfo *)));
+		bfd_realloc (nested_funcs,
+			     nested_funcs_size * sizeof (struct funcinfo *));
 	      if (tmp == NULL)
 		goto fail;
 	      nested_funcs = tmp;
@@ -2362,23 +2377,29 @@ parse_comp_unit (struct dwarf2_debug *st
 
   if (version != 2 && version != 3 && version != 4)
     {
-      (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2, 3 and 4 information."), version);
+      (*_bfd_error_handler)
+	(_("Dwarf Error: found dwarf version '%u', this reader"
+	   " only handles version 2, 3 and 4 information."), version);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
   if (addr_size > sizeof (bfd_vma))
     {
-      (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."),
-			 addr_size,
-			 (unsigned int) sizeof (bfd_vma));
+      (*_bfd_error_handler)
+	(_("Dwarf Error: found address size '%u', this reader"
+	   " can not handle sizes greater than '%u'."),
+	 addr_size,
+	 (unsigned int) sizeof (bfd_vma));
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
 
   if (addr_size != 2 && addr_size != 4 && addr_size != 8)
     {
-      (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size);
+      (*_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);
       return 0;
     }
@@ -2386,14 +2407,14 @@ parse_comp_unit (struct dwarf2_debug *st
   /* Read the abbrevs for this compilation unit into a table.  */
   abbrevs = read_abbrevs (abfd, abbrev_offset, stash);
   if (! abbrevs)
-      return 0;
+    return 0;
 
   abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
   info_ptr += bytes_read;
   if (! abbrev_number)
     {
       (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."),
-			 abbrev_number);
+			     abbrev_number);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
@@ -2402,7 +2423,7 @@ parse_comp_unit (struct dwarf2_debug *st
   if (! abbrev)
     {
       (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
-			 abbrev_number);
+			     abbrev_number);
       bfd_set_error (bfd_error_bad_value);
       return 0;
     }
@@ -2445,7 +2466,8 @@ parse_comp_unit (struct dwarf2_debug *st
 	  /* 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. */
-	  unit->base_address = low_pc;
+	  if (abbrev->tag == DW_TAG_compile_unit)
+	    unit->base_address = low_pc;
 	  break;
 
 	case DW_AT_high_pc:
@@ -2482,7 +2504,7 @@ parse_comp_unit (struct dwarf2_debug *st
     high_pc += low_pc;
   if (high_pc != 0)
     {
-      if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+      if (!arange_add (unit, &unit->arange, low_pc, high_pc))
 	return NULL;
     }
 
@@ -2752,25 +2774,43 @@ static asection *
 find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
                  asection *after_sec)
 {
-  asection * msec;
+  asection *msec;
+  const char *look;
+
+  if (after_sec == NULL)
+    {
+      look = debug_sections[debug_info].uncompressed_name;
+      msec = bfd_get_section_by_name (abfd, look);
+      if (msec != NULL)
+	return msec;
 
-  msec = after_sec != NULL ? after_sec->next : abfd->sections;
+      look = debug_sections[debug_info].compressed_name;
+      if (look != NULL)
+	{
+	  msec = bfd_get_section_by_name (abfd, look);
+	  if (msec != NULL)
+	    return msec;
+	}
 
-  while (msec)
+      for (msec = abfd->sections; msec != NULL; msec = msec->next)
+	if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
+	  return msec;
+
+      return NULL;
+    }
+
+  for (msec = after_sec->next; msec != NULL; msec = msec->next)
     {
-      if (strcmp (msec->name,
-                  debug_sections[debug_info].uncompressed_name) == 0)
+      look = debug_sections[debug_info].uncompressed_name;
+      if (strcmp (msec->name, look) == 0)
 	return msec;
 
-      if (debug_sections[debug_info].compressed_name != NULL
-          && strcmp (msec->name,
-                     debug_sections[debug_info].compressed_name) == 0)
+      look = debug_sections[debug_info].compressed_name;
+      if (look != NULL && strcmp (msec->name, look) == 0)
 	return msec;
 
       if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO))
 	return msec;
-
-      msec = msec->next;
     }
 
   return NULL;
@@ -2844,7 +2884,7 @@ place_sections (bfd *abfd, struct dwarf2
 	}
 
       amt = i * sizeof (struct adjusted_section);
-      p = (struct adjusted_section *) bfd_zalloc (abfd, amt);
+      p = (struct adjusted_section *) bfd_alloc (abfd, amt);
       if (! p)
 	return FALSE;
 
@@ -2938,8 +2978,8 @@ info_hash_lookup_funcinfo (struct info_h
 	      && addr >= arange->low
 	      && addr < arange->high
 	      && (!best_fit
-		  || ((arange->high - arange->low)
-		      < (best_fit->arange.high - best_fit->arange.low))))
+		  || (arange->high - arange->low
+		      < best_fit->arange.high - best_fit->arange.low)))
 	    best_fit = each_func;
 	}
     }
@@ -3359,6 +3399,7 @@ find_line (bfd *abfd,
 	  /* Check the previously read comp. units first.  */
 	  for (each = stash->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,
@@ -3372,7 +3413,8 @@ find_line (bfd *abfd,
     {
       for (each = stash->all_comp_units; each; each = each->next_unit)
 	{
-	  found = (comp_unit_contains_address (each, addr)
+	  found = ((each->arange.high == 0
+		    || comp_unit_contains_address (each, addr))
 		   && comp_unit_find_nearest_line (each, addr,
 						   filename_ptr,
 						   functionname_ptr,
@@ -3485,7 +3527,7 @@ find_line (bfd *abfd,
 	}
     }
 
-done:
+ done:
   if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
     unset_sections (stash);
 

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list