diff options
| author | Paul Pluzhnikov <ppluzhnikov@google.com> | 2009-08-06 23:19:47 +0000 | 
|---|---|---|
| committer | Paul Pluzhnikov <ppluzhnikov@google.com> | 2009-08-06 23:19:47 +0000 | 
| commit | b01c84103b9aeb50d2c34d2e562579b79a0c604c (patch) | |
| tree | b04e0e7cec9d9a5c11545f22617602e6e9d497d7 /gdb/dwarf2-frame.c | |
| parent | d837706a7c1ce2dea0c2c18d3f7977bc54e31eb6 (diff) | |
| download | binutils-b01c84103b9aeb50d2c34d2e562579b79a0c604c.zip binutils-b01c84103b9aeb50d2c34d2e562579b79a0c604c.tar.gz binutils-b01c84103b9aeb50d2c34d2e562579b79a0c604c.tar.bz2 | |
2009-08-06  Paul Pluzhnikov  <ppluzhnikov@google.com>
	* dwarf2-frame.c (struct dwarf2_cie): Remove 'next'.
	(struct dwarf2_cie_table): New.
	(struct dwarf2_fde): Remove 'next'.
	(struct dwarf2_fde_table): New.
	(struct comp_unit): Remove 'cie'.
	(bsearch_cie_cmp, bsearch_fde_cmp): New function.
	(find_cie, dwarf2_frame_find_fde): Use bsearch.
	(add_cie, add_fde): Use array instead of linked list.
	(decode_frame_entry, decode_frame_entry_1): New parameters.
	(qsort_fde_cmp): New function.
	(dwarf2_build_frame_info): Adjust.
Diffstat (limited to 'gdb/dwarf2-frame.c')
| -rw-r--r-- | gdb/dwarf2-frame.c | 227 | 
1 files changed, 171 insertions, 56 deletions
| diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index c620067..6617659 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -85,8 +85,12 @@ struct dwarf2_cie    /* The version recorded in the CIE.  */    unsigned char version; +}; -  struct dwarf2_cie *next; +struct dwarf2_cie_table +{ +  int num_entries; +  struct dwarf2_cie **entries;  };  /* Frame Description Entry (FDE).  */ @@ -109,8 +113,12 @@ struct dwarf2_fde    /* True if this FDE is read from a .eh_frame instead of a .debug_frame       section.  */    unsigned char eh_frame_p; +}; -  struct dwarf2_fde *next; +struct dwarf2_fde_table +{ +  int num_entries; +  struct dwarf2_fde **entries;  };  /* A minimal decoding of DWARF2 compilation units.  We only decode @@ -123,9 +131,6 @@ struct comp_unit    struct objfile *objfile; -  /* Linked list of CIEs for this object.  */ -  struct dwarf2_cie *cie; -    /* Pointer to the .debug_frame section loaded into memory.  */    gdb_byte *dwarf_frame_buffer; @@ -1464,31 +1469,56 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,  } -/* GCC uses a single CIE for all FDEs in a .debug_frame section. -   That's why we use a simple linked list here.  */ - -static struct dwarf2_cie * -find_cie (struct comp_unit *unit, ULONGEST cie_pointer) +static int +bsearch_cie_cmp (const void *key, const void *element)  { -  struct dwarf2_cie *cie = unit->cie; +  ULONGEST cie_pointer = *(ULONGEST *) key; +  struct dwarf2_cie *cie = *(struct dwarf2_cie **) element; -  while (cie) -    { -      if (cie->cie_pointer == cie_pointer) -	return cie; +  if (cie_pointer == cie->cie_pointer) +    return 0; -      cie = cie->next; -    } +  return (cie_pointer < cie->cie_pointer) ? -1 : 1; +} + +/* Find CIE with the given CIE_POINTER in CIE_TABLE.  */ +static struct dwarf2_cie * +find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer) +{ +  struct dwarf2_cie **p_cie; +  p_cie = bsearch (&cie_pointer, cie_table->entries, cie_table->num_entries, +                   sizeof (cie_table->entries[0]), bsearch_cie_cmp); +  if (p_cie != NULL) +    return *p_cie;    return NULL;  } +/* Add a pointer to new CIE to the CIE_TABLE, allocating space for it.  */  static void -add_cie (struct comp_unit *unit, struct dwarf2_cie *cie) +add_cie (struct dwarf2_cie_table *cie_table, struct dwarf2_cie *cie)  { -  cie->next = unit->cie; -  unit->cie = cie; -  cie->unit = unit; +  const int n = cie_table->num_entries; + +  gdb_assert (n < 1 +              || cie_table->entries[n - 1]->cie_pointer < cie->cie_pointer); + +  cie_table->entries = +      xrealloc (cie_table->entries, (n + 1) * sizeof (cie_table->entries[0])); +  cie_table->entries[n] = cie; +  cie_table->num_entries = n + 1; +} + +static int +bsearch_fde_cmp (const void *key, const void *element) +{ +  CORE_ADDR seek_pc = *(CORE_ADDR *) key; +  struct dwarf2_fde *fde = *(struct dwarf2_fde **) element; +  if (seek_pc < fde->initial_location) +    return -1; +  if (seek_pc < fde->initial_location + fde->address_range) +    return 0; +  return 1;  }  /* Find the FDE for *PC.  Return a pointer to the FDE, and store the @@ -1501,37 +1531,47 @@ dwarf2_frame_find_fde (CORE_ADDR *pc)    ALL_OBJFILES (objfile)      { -      struct dwarf2_fde *fde; +      struct dwarf2_fde_table *fde_table; +      struct dwarf2_fde **p_fde;        CORE_ADDR offset; +      CORE_ADDR seek_pc; -      fde = objfile_data (objfile, dwarf2_frame_objfile_data); -      if (fde == NULL) +      fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); +      if (fde_table == NULL)  	continue;        gdb_assert (objfile->section_offsets);        offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); -      while (fde) -	{ -	  if (*pc >= fde->initial_location + offset -	      && *pc < fde->initial_location + offset + fde->address_range) -	    { -	      *pc = fde->initial_location + offset; -	      return fde; -	    } - -	  fde = fde->next; -	} +      gdb_assert (fde_table->num_entries > 0); +      if (*pc < offset + fde_table->entries[0]->initial_location) +        continue; + +      seek_pc = *pc - offset; +      p_fde = bsearch (&seek_pc, fde_table->entries, fde_table->num_entries, +                       sizeof (fde_table->entries[0]), bsearch_fde_cmp); +      if (p_fde != NULL) +        { +          *pc = (*p_fde)->initial_location + offset; +          return *p_fde; +        }      } -    return NULL;  } +/* Add a pointer to new FDE to the FDE_TABLE, allocating space for it.  */  static void -add_fde (struct comp_unit *unit, struct dwarf2_fde *fde) +add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde)  { -  fde->next = objfile_data (unit->objfile, dwarf2_frame_objfile_data); -  set_objfile_data (unit->objfile, dwarf2_frame_objfile_data, fde); +  if (fde->address_range == 0) +    /* Discard useless FDEs.  */ +    return; + +  fde_table->num_entries += 1; +  fde_table->entries = +      xrealloc (fde_table->entries, +                fde_table->num_entries * sizeof (fde_table->entries[0])); +  fde_table->entries[fde_table->num_entries - 1] = fde;  }  #ifdef CC_HAS_LONG_LONG @@ -1541,12 +1581,16 @@ add_fde (struct comp_unit *unit, struct dwarf2_fde *fde)  #endif  static gdb_byte *decode_frame_entry (struct comp_unit *unit, gdb_byte *start, -				     int eh_frame_p); +				     int eh_frame_p, +                                     struct dwarf2_cie_table *cie_table, +                                     struct dwarf2_fde_table *fde_table);  /* Decode the next CIE or FDE.  Return NULL if invalid input, otherwise     the next byte to be processed.  */  static gdb_byte * -decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) +decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, +                      struct dwarf2_cie_table *cie_table, +                      struct dwarf2_fde_table *fde_table)  {    struct gdbarch *gdbarch = get_objfile_arch (unit->objfile);    gdb_byte *buf, *end; @@ -1601,7 +1645,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)        cie_pointer = start - unit->dwarf_frame_buffer;        /* Check whether we've already read it.  */ -      if (find_cie (unit, cie_pointer)) +      if (find_cie (cie_table, cie_pointer))  	return end;        cie = (struct dwarf2_cie *) @@ -1738,8 +1782,9 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)        cie->initial_instructions = buf;        cie->end = end; +      cie->unit = unit; -      add_cie (unit, cie); +      add_cie (cie_table, cie);      }    else      { @@ -1763,12 +1808,12 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)        fde = (struct dwarf2_fde *)  	obstack_alloc (&unit->objfile->objfile_obstack,  		       sizeof (struct dwarf2_fde)); -      fde->cie = find_cie (unit, cie_pointer); +      fde->cie = find_cie (cie_table, cie_pointer);        if (fde->cie == NULL)  	{  	  decode_frame_entry (unit, unit->dwarf_frame_buffer + cie_pointer, -			      eh_frame_p); -	  fde->cie = find_cie (unit, cie_pointer); +			      eh_frame_p, cie_table, fde_table); +	  fde->cie = find_cie (cie_table, cie_pointer);  	}        gdb_assert (fde->cie != NULL); @@ -1802,7 +1847,7 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)        fde->eh_frame_p = eh_frame_p; -      add_fde (unit, fde); +      add_fde (fde_table, fde);      }    return end; @@ -1810,7 +1855,9 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)  /* Read a CIE or FDE in BUF and decode it.  */  static gdb_byte * -decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p) +decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p, +                    struct dwarf2_cie_table *cie_table, +                    struct dwarf2_fde_table *fde_table)  {    enum { NONE, ALIGN4, ALIGN8, FAIL } workaround = NONE;    gdb_byte *ret; @@ -1819,7 +1866,8 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)    while (1)      { -      ret = decode_frame_entry_1 (unit, start, eh_frame_p); +      ret = decode_frame_entry_1 (unit, start, eh_frame_p, +                                  cie_table, fde_table);        if (ret != NULL)  	break; @@ -1905,11 +1953,31 @@ decode_frame_entry (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)  extern void dwarf2_get_section_info (struct objfile *, const char *, asection **,                                       gdb_byte **, bfd_size_type *); +static int +qsort_fde_cmp (const void *a, const void *b) +{ +  struct dwarf2_fde *aa = *(struct dwarf2_fde **)a; +  struct dwarf2_fde *bb = *(struct dwarf2_fde **)b; +  if (aa->initial_location == bb->initial_location) +    /* Put eh_frame entries after debug_frame ones.  */ +    return aa->eh_frame_p - bb->eh_frame_p; + +  return (aa->initial_location < bb->initial_location) ? -1 : 1; +} +  void  dwarf2_build_frame_info (struct objfile *objfile)  {    struct comp_unit *unit;    gdb_byte *frame_ptr; +  struct dwarf2_cie_table cie_table; +  struct dwarf2_fde_table fde_table; + +  cie_table.num_entries = 0; +  cie_table.entries = NULL; + +  fde_table.num_entries = 0; +  fde_table.entries = NULL;    /* Build a minimal decoding of the DWARF2 compilation unit.  */    unit = (struct comp_unit *) obstack_alloc (&objfile->objfile_obstack, @@ -1919,8 +1987,6 @@ dwarf2_build_frame_info (struct objfile *objfile)    unit->dbase = 0;    unit->tbase = 0; -  /* First add the information from the .eh_frame section.  That way, -     the FDEs from that section are searched last.  */    dwarf2_get_section_info (objfile, ".eh_frame",                             &unit->dwarf_frame_section,                             &unit->dwarf_frame_buffer, @@ -1929,7 +1995,6 @@ dwarf2_build_frame_info (struct objfile *objfile)      {        asection *got, *txt; -      unit->cie = NULL;        /* FIXME: kettenis/20030602: This is the DW_EH_PE_datarel base  	 that is used for the i386/amd64 target, which currently is  	 the only target in GCC that supports/uses the @@ -1946,7 +2011,16 @@ dwarf2_build_frame_info (struct objfile *objfile)        frame_ptr = unit->dwarf_frame_buffer;        while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size) -	frame_ptr = decode_frame_entry (unit, frame_ptr, 1); +	frame_ptr = decode_frame_entry (unit, frame_ptr, 1, +                                        &cie_table, &fde_table); + +      if (cie_table.num_entries != 0) +        { +          /* Reinit cie_table: debug_frame has different CIEs.  */ +          xfree (cie_table.entries); +          cie_table.num_entries = 0; +          cie_table.entries = NULL; +        }      }    dwarf2_get_section_info (objfile, ".debug_frame", @@ -1955,11 +2029,52 @@ dwarf2_build_frame_info (struct objfile *objfile)                             &unit->dwarf_frame_size);    if (unit->dwarf_frame_size)      { -      unit->cie = NULL; -        frame_ptr = unit->dwarf_frame_buffer;        while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size) -	frame_ptr = decode_frame_entry (unit, frame_ptr, 0); +	frame_ptr = decode_frame_entry (unit, frame_ptr, 0, +                                        &cie_table, &fde_table); +    } + +  /* Discard the cie_table, it is no longer needed.  */ +  if (cie_table.num_entries != 0) +    { +      xfree (cie_table.entries); +      cie_table.entries = NULL;   /* Paranoia.  */ +      cie_table.num_entries = 0;  /* Paranoia.  */ +    } + +  if (fde_table.num_entries != 0) +    { +      struct dwarf2_fde_table *fde_table2; +      int i, j; + +      /* Prepare FDE table for lookups.  */ +      qsort (fde_table.entries, fde_table.num_entries, +             sizeof (fde_table.entries[0]), qsort_fde_cmp); + +      /* Copy fde_table to obstack: it is needed at runtime.  */ +      fde_table2 = (struct dwarf2_fde_table *) +          obstack_alloc (&objfile->objfile_obstack, sizeof (*fde_table2)); + +      /* Since we'll be doing bsearch, squeeze out identical (except for +         eh_frame_p) fde entries so bsearch result is predictable.  */ +      for (i = 0, j = 0; j < fde_table.num_entries; ++i) +        { +          const int k = j; + +          obstack_grow (&objfile->objfile_obstack, &fde_table.entries[j], +                        sizeof (fde_table.entries[0])); +          while (++j < fde_table.num_entries +                 && (fde_table.entries[k]->initial_location == +                     fde_table.entries[j]->initial_location)) +            /* Skip.  */; +        } +      fde_table2->entries = obstack_finish (&objfile->objfile_obstack); +      fde_table2->num_entries = i; +      set_objfile_data (objfile, dwarf2_frame_objfile_data, fde_table2); + +      /* Discard the original fde_table.  */ +      xfree (fde_table.entries);      }  } | 
