OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [bfd/] [elf-strtab.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* ELF strtab with GC and suffix merging support.
/* ELF strtab with GC and suffix merging support.
   Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2008
   Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2008
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Written by Jakub Jelinek <jakub@redhat.com>.
   Written by Jakub Jelinek <jakub@redhat.com>.
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "libbfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf-bfd.h"
#include "hashtab.h"
#include "hashtab.h"
#include "libiberty.h"
#include "libiberty.h"
 
 
/* An entry in the strtab hash table.  */
/* An entry in the strtab hash table.  */
 
 
struct elf_strtab_hash_entry
struct elf_strtab_hash_entry
{
{
  struct bfd_hash_entry root;
  struct bfd_hash_entry root;
  /* Length of this entry.  This includes the zero terminator.  */
  /* Length of this entry.  This includes the zero terminator.  */
  int len;
  int len;
  unsigned int refcount;
  unsigned int refcount;
  union {
  union {
    /* Index within the merged section.  */
    /* Index within the merged section.  */
    bfd_size_type index;
    bfd_size_type index;
    /* Entry this is a suffix of (if len < 0).  */
    /* Entry this is a suffix of (if len < 0).  */
    struct elf_strtab_hash_entry *suffix;
    struct elf_strtab_hash_entry *suffix;
  } u;
  } u;
};
};
 
 
/* The strtab hash table.  */
/* The strtab hash table.  */
 
 
struct elf_strtab_hash
struct elf_strtab_hash
{
{
  struct bfd_hash_table table;
  struct bfd_hash_table table;
  /* Next available index.  */
  /* Next available index.  */
  bfd_size_type size;
  bfd_size_type size;
  /* Number of array entries alloced.  */
  /* Number of array entries alloced.  */
  bfd_size_type alloced;
  bfd_size_type alloced;
  /* Final strtab size.  */
  /* Final strtab size.  */
  bfd_size_type sec_size;
  bfd_size_type sec_size;
  /* Array of pointers to strtab entries.  */
  /* Array of pointers to strtab entries.  */
  struct elf_strtab_hash_entry **array;
  struct elf_strtab_hash_entry **array;
};
};
 
 
/* Routine to create an entry in a section merge hashtab.  */
/* Routine to create an entry in a section merge hashtab.  */
 
 
static struct bfd_hash_entry *
static struct bfd_hash_entry *
elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
                         struct bfd_hash_table *table,
                         struct bfd_hash_table *table,
                         const char *string)
                         const char *string)
{
{
  /* Allocate the structure if it has not already been allocated by a
  /* Allocate the structure if it has not already been allocated by a
     subclass.  */
     subclass.  */
  if (entry == NULL)
  if (entry == NULL)
    entry = (struct bfd_hash_entry *)
    entry = (struct bfd_hash_entry *)
        bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
        bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
  if (entry == NULL)
  if (entry == NULL)
    return NULL;
    return NULL;
 
 
  /* Call the allocation method of the superclass.  */
  /* Call the allocation method of the superclass.  */
  entry = bfd_hash_newfunc (entry, table, string);
  entry = bfd_hash_newfunc (entry, table, string);
 
 
  if (entry)
  if (entry)
    {
    {
      /* Initialize the local fields.  */
      /* Initialize the local fields.  */
      struct elf_strtab_hash_entry *ret;
      struct elf_strtab_hash_entry *ret;
 
 
      ret = (struct elf_strtab_hash_entry *) entry;
      ret = (struct elf_strtab_hash_entry *) entry;
      ret->u.index = -1;
      ret->u.index = -1;
      ret->refcount = 0;
      ret->refcount = 0;
      ret->len = 0;
      ret->len = 0;
    }
    }
 
 
  return entry;
  return entry;
}
}
 
 
/* Create a new hash table.  */
/* Create a new hash table.  */
 
 
struct elf_strtab_hash *
struct elf_strtab_hash *
_bfd_elf_strtab_init (void)
_bfd_elf_strtab_init (void)
{
{
  struct elf_strtab_hash *table;
  struct elf_strtab_hash *table;
  bfd_size_type amt = sizeof (struct elf_strtab_hash);
  bfd_size_type amt = sizeof (struct elf_strtab_hash);
 
 
  table = (struct elf_strtab_hash *) bfd_malloc (amt);
  table = (struct elf_strtab_hash *) bfd_malloc (amt);
  if (table == NULL)
  if (table == NULL)
    return NULL;
    return NULL;
 
 
  if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
  if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
                            sizeof (struct elf_strtab_hash_entry)))
                            sizeof (struct elf_strtab_hash_entry)))
    {
    {
      free (table);
      free (table);
      return NULL;
      return NULL;
    }
    }
 
 
  table->sec_size = 0;
  table->sec_size = 0;
  table->size = 1;
  table->size = 1;
  table->alloced = 64;
  table->alloced = 64;
  amt = sizeof (struct elf_strtab_hasn_entry *);
  amt = sizeof (struct elf_strtab_hasn_entry *);
  table->array = (struct elf_strtab_hash_entry **)
  table->array = (struct elf_strtab_hash_entry **)
      bfd_malloc (table->alloced * amt);
      bfd_malloc (table->alloced * amt);
  if (table->array == NULL)
  if (table->array == NULL)
    {
    {
      free (table);
      free (table);
      return NULL;
      return NULL;
    }
    }
 
 
  table->array[0] = NULL;
  table->array[0] = NULL;
 
 
  return table;
  return table;
}
}
 
 
/* Free a strtab.  */
/* Free a strtab.  */
 
 
void
void
_bfd_elf_strtab_free (struct elf_strtab_hash *tab)
_bfd_elf_strtab_free (struct elf_strtab_hash *tab)
{
{
  bfd_hash_table_free (&tab->table);
  bfd_hash_table_free (&tab->table);
  free (tab->array);
  free (tab->array);
  free (tab);
  free (tab);
}
}
 
 
/* Get the index of an entity in a hash table, adding it if it is not
/* Get the index of an entity in a hash table, adding it if it is not
   already present.  */
   already present.  */
 
 
bfd_size_type
bfd_size_type
_bfd_elf_strtab_add (struct elf_strtab_hash *tab,
_bfd_elf_strtab_add (struct elf_strtab_hash *tab,
                     const char *str,
                     const char *str,
                     bfd_boolean copy)
                     bfd_boolean copy)
{
{
  register struct elf_strtab_hash_entry *entry;
  register struct elf_strtab_hash_entry *entry;
 
 
  /* We handle this specially, since we don't want to do refcounting
  /* We handle this specially, since we don't want to do refcounting
     on it.  */
     on it.  */
  if (*str == '\0')
  if (*str == '\0')
    return 0;
    return 0;
 
 
  BFD_ASSERT (tab->sec_size == 0);
  BFD_ASSERT (tab->sec_size == 0);
  entry = (struct elf_strtab_hash_entry *)
  entry = (struct elf_strtab_hash_entry *)
          bfd_hash_lookup (&tab->table, str, TRUE, copy);
          bfd_hash_lookup (&tab->table, str, TRUE, copy);
 
 
  if (entry == NULL)
  if (entry == NULL)
    return (bfd_size_type) -1;
    return (bfd_size_type) -1;
 
 
  entry->refcount++;
  entry->refcount++;
  if (entry->len == 0)
  if (entry->len == 0)
    {
    {
      entry->len = strlen (str) + 1;
      entry->len = strlen (str) + 1;
      /* 2G strings lose.  */
      /* 2G strings lose.  */
      BFD_ASSERT (entry->len > 0);
      BFD_ASSERT (entry->len > 0);
      if (tab->size == tab->alloced)
      if (tab->size == tab->alloced)
        {
        {
          bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
          bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
          tab->alloced *= 2;
          tab->alloced *= 2;
          tab->array = (struct elf_strtab_hash_entry **)
          tab->array = (struct elf_strtab_hash_entry **)
              bfd_realloc_or_free (tab->array, tab->alloced * amt);
              bfd_realloc_or_free (tab->array, tab->alloced * amt);
          if (tab->array == NULL)
          if (tab->array == NULL)
            return (bfd_size_type) -1;
            return (bfd_size_type) -1;
        }
        }
 
 
      entry->u.index = tab->size++;
      entry->u.index = tab->size++;
      tab->array[entry->u.index] = entry;
      tab->array[entry->u.index] = entry;
    }
    }
  return entry->u.index;
  return entry->u.index;
}
}
 
 
void
void
_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
{
{
  if (idx == 0 || idx == (bfd_size_type) -1)
  if (idx == 0 || idx == (bfd_size_type) -1)
    return;
    return;
  BFD_ASSERT (tab->sec_size == 0);
  BFD_ASSERT (tab->sec_size == 0);
  BFD_ASSERT (idx < tab->size);
  BFD_ASSERT (idx < tab->size);
  ++tab->array[idx]->refcount;
  ++tab->array[idx]->refcount;
}
}
 
 
void
void
_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
{
{
  if (idx == 0 || idx == (bfd_size_type) -1)
  if (idx == 0 || idx == (bfd_size_type) -1)
    return;
    return;
  BFD_ASSERT (tab->sec_size == 0);
  BFD_ASSERT (tab->sec_size == 0);
  BFD_ASSERT (idx < tab->size);
  BFD_ASSERT (idx < tab->size);
  BFD_ASSERT (tab->array[idx]->refcount > 0);
  BFD_ASSERT (tab->array[idx]->refcount > 0);
  --tab->array[idx]->refcount;
  --tab->array[idx]->refcount;
}
}
 
 
void
void
_bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
_bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
{
{
  bfd_size_type idx;
  bfd_size_type idx;
 
 
  for (idx = 1; idx < tab->size; ++idx)
  for (idx = 1; idx < tab->size; ++idx)
    tab->array[idx]->refcount = 0;
    tab->array[idx]->refcount = 0;
}
}
 
 
bfd_size_type
bfd_size_type
_bfd_elf_strtab_size (struct elf_strtab_hash *tab)
_bfd_elf_strtab_size (struct elf_strtab_hash *tab)
{
{
  return tab->sec_size ? tab->sec_size : tab->size;
  return tab->sec_size ? tab->sec_size : tab->size;
}
}
 
 
bfd_size_type
bfd_size_type
_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
{
{
  struct elf_strtab_hash_entry *entry;
  struct elf_strtab_hash_entry *entry;
 
 
  if (idx == 0)
  if (idx == 0)
    return 0;
    return 0;
  BFD_ASSERT (idx < tab->size);
  BFD_ASSERT (idx < tab->size);
  BFD_ASSERT (tab->sec_size);
  BFD_ASSERT (tab->sec_size);
  entry = tab->array[idx];
  entry = tab->array[idx];
  BFD_ASSERT (entry->refcount > 0);
  BFD_ASSERT (entry->refcount > 0);
  entry->refcount--;
  entry->refcount--;
  return tab->array[idx]->u.index;
  return tab->array[idx]->u.index;
}
}
 
 
bfd_boolean
bfd_boolean
_bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
_bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
{
{
  bfd_size_type off = 1, i;
  bfd_size_type off = 1, i;
 
 
  if (bfd_bwrite ("", 1, abfd) != 1)
  if (bfd_bwrite ("", 1, abfd) != 1)
    return FALSE;
    return FALSE;
 
 
  for (i = 1; i < tab->size; ++i)
  for (i = 1; i < tab->size; ++i)
    {
    {
      register const char *str;
      register const char *str;
      register unsigned int len;
      register unsigned int len;
 
 
      BFD_ASSERT (tab->array[i]->refcount == 0);
      BFD_ASSERT (tab->array[i]->refcount == 0);
      len = tab->array[i]->len;
      len = tab->array[i]->len;
      if ((int) len < 0)
      if ((int) len < 0)
        continue;
        continue;
 
 
      str = tab->array[i]->root.string;
      str = tab->array[i]->root.string;
      if (bfd_bwrite (str, len, abfd) != len)
      if (bfd_bwrite (str, len, abfd) != len)
        return FALSE;
        return FALSE;
 
 
      off += len;
      off += len;
    }
    }
 
 
  BFD_ASSERT (off == tab->sec_size);
  BFD_ASSERT (off == tab->sec_size);
  return TRUE;
  return TRUE;
}
}
 
 
/* Compare two elf_strtab_hash_entry structures.  Called via qsort.  */
/* Compare two elf_strtab_hash_entry structures.  Called via qsort.  */
 
 
static int
static int
strrevcmp (const void *a, const void *b)
strrevcmp (const void *a, const void *b)
{
{
  struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
  struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
  struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
  struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
  unsigned int lenA = A->len;
  unsigned int lenA = A->len;
  unsigned int lenB = B->len;
  unsigned int lenB = B->len;
  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
  int l = lenA < lenB ? lenA : lenB;
  int l = lenA < lenB ? lenA : lenB;
 
 
  while (l)
  while (l)
    {
    {
      if (*s != *t)
      if (*s != *t)
        return (int) *s - (int) *t;
        return (int) *s - (int) *t;
      s--;
      s--;
      t--;
      t--;
      l--;
      l--;
    }
    }
  return lenA - lenB;
  return lenA - lenB;
}
}
 
 
static inline int
static inline int
is_suffix (const struct elf_strtab_hash_entry *A,
is_suffix (const struct elf_strtab_hash_entry *A,
           const struct elf_strtab_hash_entry *B)
           const struct elf_strtab_hash_entry *B)
{
{
  if (A->len <= B->len)
  if (A->len <= B->len)
    /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
    /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
       not to be equal by the hash table.  */
       not to be equal by the hash table.  */
    return 0;
    return 0;
 
 
  return memcmp (A->root.string + (A->len - B->len),
  return memcmp (A->root.string + (A->len - B->len),
                 B->root.string, B->len - 1) == 0;
                 B->root.string, B->len - 1) == 0;
}
}
 
 
/* This function assigns final string table offsets for used strings,
/* This function assigns final string table offsets for used strings,
   merging strings matching suffixes of longer strings if possible.  */
   merging strings matching suffixes of longer strings if possible.  */
 
 
void
void
_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
{
{
  struct elf_strtab_hash_entry **array, **a, *e;
  struct elf_strtab_hash_entry **array, **a, *e;
  bfd_size_type size, amt;
  bfd_size_type size, amt;
 
 
  /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
  /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
     a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
     a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
     Besides, indexing with a long long wouldn't give anything but extra
     Besides, indexing with a long long wouldn't give anything but extra
     cycles.  */
     cycles.  */
  size_t i;
  size_t i;
 
 
  /* Sort the strings by suffix and length.  */
  /* Sort the strings by suffix and length.  */
  amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
  amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
  array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
  array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
  if (array == NULL)
  if (array == NULL)
    goto alloc_failure;
    goto alloc_failure;
 
 
  for (i = 1, a = array; i < tab->size; ++i)
  for (i = 1, a = array; i < tab->size; ++i)
    {
    {
      e = tab->array[i];
      e = tab->array[i];
      if (e->refcount)
      if (e->refcount)
        {
        {
          *a++ = e;
          *a++ = e;
          /* Adjust the length to not include the zero terminator.  */
          /* Adjust the length to not include the zero terminator.  */
          e->len -= 1;
          e->len -= 1;
        }
        }
      else
      else
        e->len = 0;
        e->len = 0;
    }
    }
 
 
  size = a - array;
  size = a - array;
  if (size != 0)
  if (size != 0)
    {
    {
      qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
      qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
 
 
      /* Loop over the sorted array and merge suffixes.  Start from the
      /* Loop over the sorted array and merge suffixes.  Start from the
         end because we want eg.
         end because we want eg.
 
 
         s1 -> "d"
         s1 -> "d"
         s2 -> "bcd"
         s2 -> "bcd"
         s3 -> "abcd"
         s3 -> "abcd"
 
 
         to end up as
         to end up as
 
 
         s3 -> "abcd"
         s3 -> "abcd"
         s2 _____^
         s2 _____^
         s1 _______^
         s1 _______^
 
 
         ie. we don't want s1 pointing into the old s2.  */
         ie. we don't want s1 pointing into the old s2.  */
      e = *--a;
      e = *--a;
      e->len += 1;
      e->len += 1;
      while (--a >= array)
      while (--a >= array)
        {
        {
          struct elf_strtab_hash_entry *cmp = *a;
          struct elf_strtab_hash_entry *cmp = *a;
 
 
          cmp->len += 1;
          cmp->len += 1;
          if (is_suffix (e, cmp))
          if (is_suffix (e, cmp))
            {
            {
              cmp->u.suffix = e;
              cmp->u.suffix = e;
              cmp->len = -cmp->len;
              cmp->len = -cmp->len;
            }
            }
          else
          else
            e = cmp;
            e = cmp;
        }
        }
    }
    }
 
 
alloc_failure:
alloc_failure:
  if (array)
  if (array)
    free (array);
    free (array);
 
 
  /* Assign positions to the strings we want to keep.  */
  /* Assign positions to the strings we want to keep.  */
  size = 1;
  size = 1;
  for (i = 1; i < tab->size; ++i)
  for (i = 1; i < tab->size; ++i)
    {
    {
      e = tab->array[i];
      e = tab->array[i];
      if (e->refcount && e->len > 0)
      if (e->refcount && e->len > 0)
        {
        {
          e->u.index = size;
          e->u.index = size;
          size += e->len;
          size += e->len;
        }
        }
    }
    }
 
 
  tab->sec_size = size;
  tab->sec_size = size;
 
 
  /* Adjust the rest.  */
  /* Adjust the rest.  */
  for (i = 1; i < tab->size; ++i)
  for (i = 1; i < tab->size; ++i)
    {
    {
      e = tab->array[i];
      e = tab->array[i];
      if (e->refcount && e->len < 0)
      if (e->refcount && e->len < 0)
        e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
        e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.