Debug package patch.
authorjbj <devnull@localhost>
Fri, 18 Oct 2002 16:01:59 +0000 (16:01 +0000)
committerjbj <devnull@localhost>
Fri, 18 Oct 2002 16:01:59 +0000 (16:01 +0000)
CVS patchset: 5788
CVS date: 2002/10/18 16:01:59

macros.in
rpm.spec.in
scripts/find-debuginfo.sh
tools/Makefile.am
tools/debugedit.c [new file with mode: 0644]
tools/dwarf2.h [new file with mode: 0644]
tools/hashtab.c [new file with mode: 0644]
tools/hashtab.h [new file with mode: 0644]
tools/utils.c

index 230fcaf..ae0a592 100644 (file)
--- a/macros.in
+++ b/macros.in
@@ -1,7 +1,7 @@
 #/*! \page config_macros Default configuration: @RPMCONFIGDIR@/macros
 # \verbatim
 #
-# $Id: macros.in,v 1.123 2002/08/31 22:39:34 jbj Exp $
+# $Id: macros.in,v 1.124 2002/10/18 16:01:59 jbj Exp $
 #
 # This is a global RPM configuration file. All changes made here will
 # be lost when the rpm package is upgraded. Any per-system configuration
 %package debug \
 Summary: Debug information for package %{name} \
 Group: Development/Debug \
-Requires: %{name} = %{version} \
 %description debug \
 This package provides debug information for package %{name}. \
 Debug information is useful when developing applications that use this \
index 6925c20..78b6608 100644 (file)
@@ -380,6 +380,7 @@ exit 0
 %rpmattr       %{__prefix}/lib/rpm/check-prereqs
 %rpmattr       %{__prefix}/lib/rpm/config.site
 %rpmattr       %{__prefix}/lib/rpm/cross-build
+%rpmattr       %{__prefix}/lib/rpm/debugedit
 %rpmattr       %{__prefix}/lib/rpm/find-debuginfo.sh
 %rpmattr       %{__prefix}/lib/rpm/find-lang.sh
 %rpmattr       %{__prefix}/lib/rpm/find-prov.pl
index 39ae760..9600675 100644 (file)
@@ -3,6 +3,10 @@
 #for inclusion in an rpm spec file.
 
 LISTFILE=debugfiles.list
+SOURCEFILE=debugsources.list
+
+touch .debug_saved_mode
+echo -n > $SOURCEFILE
 
 # Strip ELF binaries
 for f in `find $RPM_BUILD_ROOT -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -exec file {} \; | \
@@ -11,7 +15,19 @@ for f in `find $RPM_BUILD_ROOT -type f \( -perm -0100 -or -perm -0010 -or -perm
        OUTPUTDIR=${RPM_BUILD_ROOT}/usr/lib/debug${BASEDIR}
        mkdir -p ${OUTPUTDIR}
        echo extracting debug info from $f
+       #save old mode
+       chmod --reference=$f .debug_saved_mode
+       #make sure we have write perms
+       chmod u+w $f
+       /usr/lib/rpm/debugedit -b $RPM_BUILD_DIR -d /usr/src/debug -l $SOURCEFILE $f
+       chmod --reference=.debug_saved_mode $f
        /usr/lib/rpm/striptofile -g -u -o $OUTPUTDIR $f || :
 done
 
+mkdir -p ${RPM_BUILD_ROOT}/usr/src/debug
+(DIR=`pwd`; cd $RPM_BUILD_DIR; LANG=C sort $DIR/$SOURCEFILE -z -u | cpio -pd0m ${RPM_BUILD_ROOT}/usr/src/debug)
+# stupid cpio creates new directories in mode 0700, fixup
+find ${RPM_BUILD_ROOT}/usr/src/debug -type d -print0 | xargs -0 chmod a+rx
+
 find ${RPM_BUILD_ROOT}/usr/lib/debug -type f | sed -n -e "s#^$RPM_BUILD_ROOT#/#p" > $LISTFILE
+find ${RPM_BUILD_ROOT}/usr/src/debug -mindepth 1 -maxdepth 1 | sed -n -e "s#^$RPM_BUILD_ROOT#/#p" >> $LISTFILE
index 0a272d5..75e15d3 100644 (file)
@@ -14,7 +14,7 @@ INCLUDES = -I. \
        @INCPATH@ \
        -I$(top_srcdir)/misc
 
-EXTRA_DIST =   rpminject.c rpmsort.c sections.h utils.h
+EXTRA_DIST =   rpminject.c rpmsort.c sections.h utils.h dwarf2.h hashtab.h
 
 EXTRA_PROGRAMS = rpminject rpmsort
 
@@ -31,12 +31,13 @@ noinst_PROGRAMS = \
        convertdb1 dump dumpdb rpmarchive rpmheader rpmlead rpmsignature
 
 pkgbindir = @RPMCONFIGDIR@
-pkgbin_PROGRAMS = javadeps rpmcache striptofile unstripfile
+pkgbin_PROGRAMS = debugedit javadeps rpmcache striptofile unstripfile
 
 bin_PROGRAMS = rpmgraph
 
 convertdb1_SOURCES =   convertdb1.c
 
+debugedit_SOURCES =    debugedit.c hashtab.c
 javadeps_SOURCES =     javadeps.c
 
 rpmcache_SOURCES =     rpmcache.c
diff --git a/tools/debugedit.c b/tools/debugedit.c
new file mode 100644 (file)
index 0000000..c4f9811
--- /dev/null
@@ -0,0 +1,1054 @@
+/* Copyright (C) 2001, 2002 Red Hat, Inc.
+   Written by Alexander Larsson <alexl@redhat.com>, 2002
+   Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+   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
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <popt.h>
+#include <elf.h>
+#include <libelf/libelf.h>
+#include <libelf/gelf.h>
+
+#include "dwarf2.h"
+#include "hashtab.h"
+
+char *base_dir = NULL;
+char *dest_dir = NULL;
+char *list_file = NULL;
+int list_file_fd = -1; 
+
+typedef unsigned int uint_32;
+typedef unsigned short uint_16;
+
+typedef struct
+{
+  Elf *elf;
+  GElf_Ehdr ehdr;
+  GElf_Phdr *phdr;
+  Elf_Scn **scn;
+  const char *filename;
+  int lastscn;
+  GElf_Shdr shdr[0];
+} DSO;
+
+#define read_uleb128(ptr) ({           \
+  unsigned int ret = 0;                        \
+  unsigned int c;                      \
+  int shift = 0;                       \
+  do                                   \
+    {                                  \
+      c = *ptr++;                      \
+      ret |= (c & 0x7f) << shift;      \
+      shift += 7;                      \
+    } while (c & 0x80);                        \
+                                       \
+  if (shift >= 35)                     \
+    ret = UINT_MAX;                    \
+  ret;                                 \
+})
+
+static uint_16 (*do_read_16) (unsigned char *ptr);
+static uint_32 (*do_read_32) (unsigned char *ptr);
+static void (*write_32) (unsigned char *ptr, GElf_Addr val);
+
+static int ptr_size;
+
+static inline uint_16
+buf_read_ule16 (unsigned char *data)
+{
+  return data[0] | (data[1] << 8);
+}
+
+static inline uint_16
+buf_read_ube16 (unsigned char *data)
+{
+  return data[1] | (data[0] << 8);
+}
+
+static inline uint_32
+buf_read_ule32 (unsigned char *data)
+{
+  return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+static inline uint_32
+buf_read_ube32 (unsigned char *data)
+{
+  return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
+}
+
+static const char *
+strptr (DSO *dso, int sec, off_t offset)
+{
+  Elf_Scn *scn;
+  Elf_Data *data;
+
+  scn = dso->scn[sec];
+  if (offset >= 0 && offset < dso->shdr[sec].sh_size)
+    {
+      data = NULL;
+      while ((data = elf_getdata (scn, data)) != NULL)
+       {
+         if (data->d_buf
+             && offset >= data->d_off
+             && offset < data->d_off + data->d_size)
+           return (const char *) data->d_buf + (offset - data->d_off);
+       }
+    }
+
+  return NULL;
+}
+
+
+#define read_1(ptr) *ptr++
+
+#define read_16(ptr) ({                        \
+  uint_16 ret = do_read_16 (ptr);      \
+  ptr += 2;                            \
+  ret;                                 \
+})
+
+#define read_32(ptr) ({                        \
+  uint_32 ret = do_read_32 (ptr);      \
+  ptr += 4;                            \
+  ret;                                 \
+})
+
+static void
+dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
+{
+  uint_32 v = (uint_32) val;
+
+  p[0] = v;
+  p[1] = v >> 8;
+  p[2] = v >> 16;
+  p[3] = v >> 24;
+}
+
+
+static void
+dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
+{
+  uint_32 v = (uint_32) val;
+
+  p[3] = v;
+  p[2] = v >> 8;
+  p[1] = v >> 16;
+  p[0] = v >> 24;
+}
+
+static struct
+  {
+    const char *name;
+    unsigned char *data;
+    Elf_Data *elf_data;
+    size_t size;
+    int sec;
+  } debug_sections[] =
+  {
+#define DEBUG_INFO     0
+#define DEBUG_ABBREV   1
+#define DEBUG_LINE     2
+#define DEBUG_ARANGES  3
+#define DEBUG_PUBNAMES 4
+#define DEBUG_MACINFO  5
+#define DEBUG_LOC      6
+#define DEBUG_STR      7
+#define DEBUG_FRAME    8
+#define DEBUG_RANGES   9
+    { ".debug_info", NULL, 0, 0 },
+    { ".debug_abbrev", NULL, 0, 0 },
+    { ".debug_line", NULL, 0, 0 },
+    { ".debug_aranges", NULL, 0, 0 },
+    { ".debug_pubnames", NULL, 0, 0 },
+    { ".debug_macinfo", NULL, 0, 0 },
+    { ".debug_loc", NULL, 0, 0 },
+    { ".debug_str", NULL, 0, 0 },
+    { ".debug_frame", NULL, 0, 0 },
+    { ".debug_ranges", NULL, 0, 0 },
+    { NULL, NULL, 0 }
+  };
+
+struct abbrev_attr
+  {
+    unsigned int attr;
+    unsigned int form;
+  };
+
+struct abbrev_tag
+  {
+    unsigned int entry;
+    unsigned int tag;
+    int nattr;
+    struct abbrev_attr attr[0];
+  };
+
+static hashval_t
+abbrev_hash (const void *p)
+{
+  struct abbrev_tag *t = (struct abbrev_tag *)p;
+
+  return t->entry;
+}
+
+static int
+abbrev_eq (const void *p, const void *q)
+{
+  struct abbrev_tag *t1 = (struct abbrev_tag *)p;
+  struct abbrev_tag *t2 = (struct abbrev_tag *)p;
+
+  return t1->entry == t2->entry;
+}
+
+static void
+abbrev_del (void *p)
+{
+  free (p);
+}
+
+static htab_t
+read_abbrev (DSO *dso, unsigned char *ptr)
+{
+  htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
+  unsigned int attr, form;
+  struct abbrev_tag *t;
+  int size;
+  void **slot;
+
+  if (h == NULL)
+    {
+no_memory:
+      error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
+      if (h)
+        htab_delete (h);
+      return NULL;
+    }
+
+  while ((attr = read_uleb128 (ptr)) != 0)
+    {
+      size = 10;
+      t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
+      if (t == NULL)
+        goto no_memory;
+      t->entry = attr;
+      t->nattr = 0;
+      slot = htab_find_slot (h, t, INSERT);
+      if (slot == NULL)
+        {
+         free (t);
+         goto no_memory;
+        }
+      if (*slot != NULL)
+       {
+         error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
+                t->entry);
+         free (t);
+         htab_delete (h);
+         return NULL;
+       }
+      t->tag = read_uleb128 (ptr);
+      ++ptr; /* skip children flag.  */
+      while ((attr = read_uleb128 (ptr)) != 0)
+        {
+         if (t->nattr == size)
+           {
+             size += 10;
+             t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
+             if (t == NULL)
+               goto no_memory;
+           }
+         form = read_uleb128 (ptr);
+         if (form == 2 || form > DW_FORM_indirect)
+           {
+             error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
+             htab_delete (h);
+             return NULL;
+           }
+
+         t->attr[t->nattr].attr = attr;
+         t->attr[t->nattr++].form = form;
+        }
+      if (read_uleb128 (ptr) != 0)
+        {
+         error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
+                dso->filename);
+         htab_delete (h);
+         return NULL;
+        }
+      *slot = t;
+    }
+
+  return h;
+}
+
+#define IS_DIR_SEPARATOR(c) ((c)=='/')
+
+static char *
+canonicalize_path (char *s, char *d)
+{
+  char *rv = d;
+  char *sroot, *droot;
+
+  if (d == 0)
+    rv = d = s;
+
+  if (IS_DIR_SEPARATOR (*s))
+    {
+      *d++ = *s++;
+      if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
+       {
+         /* Special case for "//foo" meaning a Posix namespace
+            escape.  */
+         *d++ = *s++;
+       }
+      while (IS_DIR_SEPARATOR (*s))
+       s++;
+    }
+  droot = d;
+  sroot = s;
+
+  while (*s)
+    {
+      /* At this point, we're always at the beginning of a path
+        segment.  */
+
+      if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
+       {
+         s ++;
+         if (*s)
+           s++;
+         else if (d > droot)
+           d--;
+       }
+
+      else if (s[0] == '.' && s[1] == '.'
+              && (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
+       {
+         char *pre = d-1; /* includes slash */
+         while (droot < pre && IS_DIR_SEPARATOR (*pre))
+           pre--;
+         if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
+           {
+             d = pre;
+             while (droot < d && ! IS_DIR_SEPARATOR (*d))
+               d--;
+             /* d now points to the slash */
+             if (droot < d)
+               d++;
+             s += 2;
+             if (*s)
+               s++;
+             else if (d > droot)
+               d--;
+           }
+         else
+           {
+             *d++ = *s++;
+             *d++ = *s++;
+             if (*s)
+               *d++ = *s++;
+           }
+       }
+
+      else
+       {
+         while (*s && ! IS_DIR_SEPARATOR (*s))
+           *d++ = *s++;
+       }
+
+      if (IS_DIR_SEPARATOR (*s))
+       {
+         *d++ = *s++;
+         while (IS_DIR_SEPARATOR (*s))
+           s++;
+       }
+    }
+  while (droot < d && IS_DIR_SEPARATOR (d[-1]))
+    --d;
+  if (d == rv)
+    *d++ = '.';
+  *d = 0;
+
+  return rv;
+}
+
+static int
+has_prefix (const char  *str,
+           const char  *prefix)
+{
+  int str_len;
+  int prefix_len;
+  
+  str_len = strlen (str);
+  prefix_len = strlen (prefix);
+
+  if (str_len < prefix_len)
+    return 0;
+  
+  return strncmp (str, prefix, prefix_len) == 0;
+}
+
+static int
+edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
+{
+  unsigned char *ptr = debug_sections[DEBUG_LINE].data;
+  unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
+  unsigned char *endcu, *endprol;
+  unsigned char opcode_base;
+  uint_32 value;
+  int s;
+
+  if (phase != 0)
+    return 0;
+  
+  s = 0;
+
+  ptr += off;
+  
+  endcu = ptr + 4;
+  endcu += read_32 (ptr);
+  if (endcu == ptr + 0xffffffff)
+    {
+      error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+      return 1;
+    }
+  
+  if (endcu > endsec)
+    {
+      error (0, 0, "%s: .debug_line CU does not fit into section",
+            dso->filename);
+      return 1;
+    }
+  
+  value = read_16 (ptr);
+  if (value != 2)
+    {
+      error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
+            value);
+      return 1;
+    }
+  
+  endprol = ptr + 4;
+  endprol += read_32 (ptr);
+  if (endprol > endcu)
+    {
+      error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
+            dso->filename);
+      return 1;
+    }
+  
+  opcode_base = ptr[4];
+  ptr = ptr + 4 + opcode_base;
+  
+  /* dir table: */
+  while (*ptr != 0)
+    {
+      ptr = strchr(ptr, 0) + 1;
+    }
+  ptr++;
+  
+  /* file table: */
+  while (*ptr != 0)
+    {
+      char *s;
+      if (*ptr == '/')
+       {
+         s = strdup (ptr);
+       }
+      else
+       {
+         s = malloc (strlen (comp_dir) + 1 + strlen (ptr) + 1);
+         strcpy (s, comp_dir);
+         strcat (s, "/");
+         strcat (s, ptr);
+         canonicalize_path (s, s);
+       }
+      if (base_dir == NULL ||
+         has_prefix (s, base_dir))
+       {
+         char *p;
+         size_t size;
+         ssize_t ret;
+         if (base_dir)
+           p = s + strlen (base_dir);
+         else
+           p = s;
+         
+         if (list_file_fd != -1)
+           {
+             size = strlen (p) + 1;
+             while (size > 0)
+               {
+                 ret = write (list_file_fd, p, size);
+                 if (ret == -1)
+                   break;
+                 size -= ret;
+                 p += ret;
+               }
+           }
+         
+       }
+      
+      free (s);
+      
+       
+      ptr = strchr(ptr, 0) + 1;
+      read_uleb128(ptr);
+      read_uleb128(ptr);
+      read_uleb128(ptr);
+    }
+  
+  return 0;
+}
+
+
+
+static unsigned char *
+edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
+{
+  int i;
+  uint_32 list_offs;
+  int found_list_offs;
+  unsigned char *comp_dir;
+  
+  comp_dir = NULL;
+  list_offs = 0;
+  found_list_offs = 0;
+  for (i = 0; i < t->nattr; ++i)
+    {
+      uint_32 form = t->attr[i].form;
+      uint_32 len = 0;
+      int base_len, dest_len;
+      
+
+      while (1)
+       {
+         if (t->attr[i].attr == DW_AT_stmt_list)
+           {
+             if (form == DW_FORM_data4)
+               {
+                 list_offs = do_read_32 (ptr);
+                 found_list_offs = 1;
+               }
+           }
+
+         if (debug_sections[DEBUG_STR].data &&
+             t->attr[i].attr == DW_AT_comp_dir &&
+             form == DW_FORM_strp)
+           {
+             char *dir;
+             
+             dir = debug_sections[DEBUG_STR].data + do_read_32 (ptr);
+             comp_dir = strdup (dir);
+
+             if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
+               {
+                 base_len = strlen (base_dir);
+                 dest_len = strlen (dest_dir);
+                 
+                 memcpy (dir, dest_dir, dest_len);
+                 if (dest_len < base_len)
+                   {
+                     memcpy (dir + dest_len, dir + base_len,
+                             strlen (dir + base_len) + 1);
+                   }
+                 elf_flagdata (debug_sections[DEBUG_STR].elf_data, ELF_C_SET,
+                              ELF_F_DIRTY);
+               }
+           }
+         
+         switch (form)
+           {
+           case DW_FORM_addr:
+             ptr += ptr_size;
+             break;
+           case DW_FORM_ref1:
+           case DW_FORM_flag:
+           case DW_FORM_data1:
+             ++ptr;
+             break;
+           case DW_FORM_ref2:
+           case DW_FORM_data2:
+             ptr += 2;
+             break;
+           case DW_FORM_ref4:
+           case DW_FORM_data4:
+             ptr += 4;
+             break;
+           case DW_FORM_ref8:
+           case DW_FORM_data8:
+             ptr += 8;
+             break;
+           case DW_FORM_sdata:
+           case DW_FORM_ref_udata:
+           case DW_FORM_udata:
+             read_uleb128 (ptr);
+             break;
+           case DW_FORM_ref_addr:
+           case DW_FORM_strp:
+             ptr += 4;
+             break;
+           case DW_FORM_string:
+             ptr = strchr (ptr, '\0') + 1;
+             break;
+           case DW_FORM_indirect:
+             form = read_uleb128 (ptr);
+             continue;
+           case DW_FORM_block1:
+             len = *ptr++;
+             break;
+           case DW_FORM_block2:
+             len = read_16 (ptr);
+             form = DW_FORM_block1;
+             break;
+           case DW_FORM_block4:
+             len = read_32 (ptr);
+             form = DW_FORM_block1;
+             break;
+           case DW_FORM_block:
+             len = read_uleb128 (ptr);
+             form = DW_FORM_block1;
+             assert (len < UINT_MAX);
+             break;
+           default:
+             error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
+                    form);
+             return NULL;
+           }
+
+         if (form == DW_FORM_block1)
+           ptr += len;
+         
+         break;
+       }
+    }
+  if (found_list_offs && comp_dir)
+    edit_dwarf2_line (dso, list_offs, comp_dir, phase);
+
+  return ptr;
+}
+
+static int
+edit_dwarf2 (DSO *dso, int n)
+{
+  Elf_Data *data;
+  Elf_Scn *scn;
+  int i, j;
+
+  for (i = 0; debug_sections[i].name; ++i)
+    {
+      debug_sections[i].data = NULL;
+      debug_sections[i].size = 0;
+      debug_sections[i].sec = 0;
+    }
+  ptr_size = 0;
+
+  for (i = 1; i < dso->ehdr.e_shnum; ++i)
+    if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
+       && dso->shdr[i].sh_size)
+      {
+        const char *name = strptr (dso, dso->ehdr.e_shstrndx,
+                                  dso->shdr[i].sh_name);
+
+       if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
+         {
+           for (j = 0; debug_sections[j].name; ++j)
+             if (strcmp (name, debug_sections[j].name) == 0)
+               {
+                 if (debug_sections[j].data)
+                   {
+                     error (0, 0, "%s: Found two copies of %s section",
+                            dso->filename, name);
+                     return 1;
+                   }
+
+                 scn = dso->scn[i]; 
+                 data = elf_getdata (scn, NULL);
+                 assert (data != NULL && data->d_buf != NULL);
+                 assert (elf_getdata (scn, data) == NULL);
+                 assert (data->d_off == 0);
+                 assert (data->d_size == dso->shdr[i].sh_size);
+                 debug_sections[j].data = data->d_buf;
+                 debug_sections[j].elf_data = data;
+                 debug_sections[j].size = data->d_size;
+                 debug_sections[j].sec = i;
+                 break;
+               }
+
+           if (debug_sections[j].name == NULL)
+             {
+               error (0, 0, "%s: Unknown debugging section %s",
+                      dso->filename, name);
+             }
+         }
+      }
+
+  if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+    {
+      do_read_16 = buf_read_ule16;
+      do_read_32 = buf_read_ule32;
+      write_32 = dwarf2_write_le32;
+    }
+  else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+    {
+      do_read_16 = buf_read_ube16;
+      do_read_32 = buf_read_ube32;
+      write_32 = dwarf2_write_be32;
+    }
+  else
+    {
+      error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
+      return 1;
+    }
+
+  if (debug_sections[DEBUG_INFO].data != NULL)
+    {
+      unsigned char *ptr, *endcu, *endsec;
+      uint_32 value;
+      htab_t abbrev;
+      struct abbrev_tag tag, *t;
+      int phase;
+
+      for (phase = 0; phase < 2; phase++)
+       {
+         ptr = debug_sections[DEBUG_INFO].data;
+         endsec = ptr + debug_sections[DEBUG_INFO].size;
+         while (ptr < endsec)
+           {
+             if (ptr + 11 > endsec)
+               {
+                 error (0, 0, "%s: .debug_info CU header too small",
+                        dso->filename);
+                 return 1;
+               }
+
+             endcu = ptr + 4;
+             endcu += read_32 (ptr);
+             if (endcu == ptr + 0xffffffff)
+               {
+                 error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+                 return 1;
+               }
+             
+             if (endcu > endsec)
+               {
+                 error (0, 0, "%s: .debug_info too small", dso->filename);
+                 return 1;
+               }
+             
+             value = read_16 (ptr);
+             if (value != 2)
+               {
+                 error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
+                        value);
+                 return 1;
+               }
+             
+             value = read_32 (ptr);
+             if (value >= debug_sections[DEBUG_ABBREV].size)
+               {
+                 if (debug_sections[DEBUG_ABBREV].data == NULL)
+                   error (0, 0, "%s: .debug_abbrev not present", dso->filename);
+                 else
+                   error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
+                          dso->filename);
+                 return 1;
+               }
+             
+             if (ptr_size == 0)
+               {
+                 ptr_size = read_1 (ptr);
+                 if (ptr_size != 4 && ptr_size != 8)
+                   {
+                     error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
+                            dso->filename, ptr_size);
+                     return 1;
+                   }
+               }
+             else if (read_1 (ptr) != ptr_size)
+               {
+                 error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
+                        dso->filename);
+                 return 1;
+               }
+             
+             abbrev = read_abbrev (dso,
+                                   debug_sections[DEBUG_ABBREV].data + value);
+             if (abbrev == NULL)
+               return 1;
+             
+             while (ptr < endcu)
+               {
+                 tag.entry = read_uleb128 (ptr);
+                 if (tag.entry == 0)
+                   continue;
+                 t = htab_find_with_hash (abbrev, &tag, tag.entry);
+                 if (t == NULL)
+                   {
+                     error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
+                            dso->filename, tag.entry);
+                     htab_delete (abbrev);
+                     return 1;
+                   }
+                 
+                 ptr = edit_attributes (dso, ptr, t, phase);
+                 if (ptr == NULL)
+                   break;
+               }
+             
+             htab_delete (abbrev);
+           }
+       }
+    }
+  
+  elf_flagscn (dso->scn[n], ELF_C_SET, ELF_F_DIRTY);
+  return 0;
+}
+
+static struct poptOption optionsTable[] = {
+    { "base-dir",  'b', POPT_ARG_STRING, &base_dir, 0,
+      "base build directory of objects", NULL },
+    { "dest-dir",  'd', POPT_ARG_STRING, &dest_dir, 0,
+      "directory to rewrite base-dir into", NULL },
+    { "list-file",  'l', POPT_ARG_STRING, &list_file, 0,
+      "directory to rewrite base-dir into", NULL },
+      POPT_AUTOHELP
+    { NULL, 0, 0, NULL, 0 }
+};
+
+static DSO *
+fdopen_dso (int fd, const char *name)
+{
+  Elf *elf = NULL;
+  GElf_Ehdr ehdr;
+  int i;
+  DSO *dso = NULL;
+
+  static int section_cmp (const void *A, const void *B)
+    {
+      int *a = (int *) A;
+      int *b = (int *) B;
+
+      if (dso->shdr[*a].sh_offset < dso->shdr[*b].sh_offset)
+       return -1;
+      if (dso->shdr[*a].sh_offset > dso->shdr[*b].sh_offset)
+       return 1;
+      if (*a < *b)
+       return -1;
+      return *a > *b;
+    }
+
+  elf = elf_begin (fd, ELF_C_RDWR, NULL);
+  if (elf == NULL)
+    {
+      error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
+      goto error_out;
+    }
+
+  if (elf_kind (elf) != ELF_K_ELF)
+    {
+      error (0, 0, "\"%s\" is not an ELF file", name);
+      goto error_out;
+    }
+
+  if (gelf_getehdr (elf, &ehdr) == NULL)
+    {
+      error (0, 0, "cannot get the ELF header: %s",
+            elf_errmsg (-1));
+      goto error_out;
+    }
+
+  if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC)
+    {
+      error (0, 0, "\"%s\" is not a shared library", name);
+      goto error_out;
+    }
+
+  /* Allocate DSO structure. Leave place for additional 20 new section
+     headers.  */
+  dso = (DSO *)
+       malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
+               + (ehdr.e_phnum + 1) * sizeof(GElf_Phdr)
+               + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
+  if (!dso)
+    {
+      error (0, ENOMEM, "Could not open DSO");
+      goto error_out;
+    }
+
+  elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
+  
+  memset (dso, 0, sizeof(DSO));
+  dso->elf = elf;
+  dso->ehdr = ehdr;
+  dso->phdr = (GElf_Phdr *) &dso->shdr[ehdr.e_shnum + 20];
+  dso->scn = (Elf_Scn **) &dso->phdr[ehdr.e_phnum + 1];
+  for (i = 0; i < ehdr.e_phnum; ++i)
+    gelf_getphdr (elf, i, dso->phdr + i);
+
+  for (i = 0; i < ehdr.e_shnum; ++i)
+    {
+      dso->scn[i] = elf_getscn (elf, i);
+      gelf_getshdr (dso->scn[i], dso->shdr + i);
+    }
+
+  dso->filename = (const char *) strdup (name);
+  return dso;
+
+error_out:
+  if (dso)
+    {
+      free ((char *) dso->filename);
+      free (dso);
+    }
+  if (elf)
+    elf_end (elf);
+  if (fd != -1)
+    close (fd);
+  return NULL;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  DSO *dso;
+  int fd, i;
+  const char *file;
+  poptContext optCon;   /* context for parsing command-line options */
+  int nextopt;
+  const char **args;
+  char *p;
+  
+  optCon = poptGetContext("debugedit", argc, (const char **)argv,
+                         optionsTable, 0);
+  
+  while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
+    /* do nothing */ ;
+
+  if (nextopt != -1)
+    {
+      fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
+             poptBadOption (optCon, 0),
+             poptStrerror (nextopt),
+             argv[0]);
+      exit (1);
+    }
+  
+  args = poptGetArgs (optCon);
+  if (args == NULL || args[0] == NULL || args[1] != NULL)
+    {
+      poptPrintHelp(optCon, stdout, 0);
+      exit (1);
+    }
+
+  if (dest_dir != NULL)
+    {
+      if (base_dir == NULL)
+       {
+         fprintf (stderr, "You must specify a base dir if you specify a dest dir\n");
+         exit (1);
+       }
+      if (strlen (dest_dir) > strlen (base_dir))
+       {
+         fprintf (stderr, "Only dest dir longer than base dir not supported\n");
+         exit (1);
+       }
+    }
+
+  /* Make sure there are trailing slashes in dirs */
+  if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
+    {
+      p = malloc (strlen (base_dir) + 2);
+      strcpy (p, base_dir);
+      strcat (p, "/");
+      free (base_dir);
+      base_dir = p;
+    }
+  if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
+    {
+      p = malloc (strlen (dest_dir) + 2);
+      strcpy (p, dest_dir);
+      strcat (p, "/");
+      free (dest_dir);
+      dest_dir = p;
+    }
+  
+  if (list_file != NULL)
+    {
+      list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
+    }
+  
+  file = args[0];
+
+  if (elf_version(EV_CURRENT) == EV_NONE)
+    {
+      fprintf (stderr, "library out of date\n");
+      exit (1);
+    }
+
+  fd = open (file, O_RDWR);
+  if (fd < 0)
+    {
+      fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno));
+      exit (1);
+    }
+
+  dso = fdopen_dso (fd, file);
+  
+  for (i = 1; i < dso->ehdr.e_shnum; i++)
+    {
+      const char *name;
+      
+      switch (dso->shdr[i].sh_type)
+       {
+       case SHT_PROGBITS:
+         name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+         /* TODO: Handle stabs */
+#if 0
+         if (strcmp (name, ".stab") == 0)
+           edit_stabs (dso, i);
+#endif
+         if (strcmp (name, ".debug_info") == 0)
+           edit_dwarf2 (dso, i);
+         
+         break;
+       default:
+         break;
+       }
+    }
+
+  elf_update (dso->elf, ELF_C_WRITE);
+  elf_end (dso->elf);
+  close (fd);
+  
+  poptFreeContext (optCon);
+
+  return 0;
+}
+
+
diff --git a/tools/dwarf2.h b/tools/dwarf2.h
new file mode 100644 (file)
index 0000000..fb44762
--- /dev/null
@@ -0,0 +1,478 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+   Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+   
+   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
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define DW_TAG_padding                 0x00
+#define DW_TAG_array_type              0x01
+#define DW_TAG_class_type              0x02
+#define DW_TAG_entry_point             0x03
+#define DW_TAG_enumeration_type                0x04
+#define DW_TAG_formal_parameter                0x05
+#define DW_TAG_imported_declaration    0x08
+#define DW_TAG_label                   0x0a
+#define DW_TAG_lexical_block           0x0b
+#define DW_TAG_member                  0x0d
+#define DW_TAG_pointer_type            0x0f
+#define DW_TAG_reference_type          0x10
+#define DW_TAG_compile_unit            0x11
+#define DW_TAG_string_type             0x12
+#define DW_TAG_structure_type          0x13
+#define DW_TAG_subroutine_type         0x15
+#define DW_TAG_typedef                 0x16
+#define DW_TAG_union_type              0x17
+#define DW_TAG_unspecified_parameters  0x18
+#define DW_TAG_variant                 0x19
+#define DW_TAG_common_block            0x1a
+#define DW_TAG_common_inclusion                0x1b
+#define DW_TAG_inheritance             0x1c
+#define DW_TAG_inlined_subroutine      0x1d
+#define DW_TAG_module                  0x1e
+#define DW_TAG_ptr_to_member_type      0x1f
+#define DW_TAG_set_type                        0x20
+#define DW_TAG_subrange_type           0x21
+#define DW_TAG_with_stmt               0x22
+#define DW_TAG_access_declaration      0x23
+#define DW_TAG_base_type               0x24
+#define DW_TAG_catch_block             0x25
+#define DW_TAG_const_type              0x26
+#define DW_TAG_constant                        0x27
+#define DW_TAG_enumerator              0x28
+#define DW_TAG_file_type               0x29
+#define DW_TAG_friend                  0x2a
+#define DW_TAG_namelist                        0x2b
+#define DW_TAG_namelist_item           0x2c
+#define DW_TAG_packed_type             0x2d
+#define DW_TAG_subprogram              0x2e
+#define DW_TAG_template_type_param     0x2f
+#define DW_TAG_template_value_param    0x30
+#define DW_TAG_thrown_type             0x31
+#define DW_TAG_try_block               0x32
+#define DW_TAG_variant_part            0x33
+#define DW_TAG_variable                        0x34
+#define DW_TAG_volatile_type           0x35
+#define DW_TAG_dwarf_procedure         0x36
+#define DW_TAG_restrict_type           0x37
+#define DW_TAG_interface_type          0x38
+#define DW_TAG_namespace               0x39
+#define DW_TAG_imported_module         0x3a
+#define DW_TAG_unspecified_type                0x3b
+#define DW_TAG_partial_unit            0x3c
+#define DW_TAG_imported_unit           0x3d
+#define DW_TAG_MIPS_loop               0x4081
+#define DW_TAG_format_label            0x4101
+#define DW_TAG_function_template       0x4102
+#define DW_TAG_class_template          0x4103
+#define DW_TAG_GNU_BINCL               0x4104
+#define DW_TAG_GNU_EINCL               0x4105
+#define DW_TAG_lo_user                 0x4080
+#define DW_TAG_hi_user                 0xffff
+
+#define DW_children_no                 0x0
+#define        DW_children_yes                 0x1
+
+#define DW_FORM_addr                   0x01
+#define DW_FORM_block2                 0x03
+#define DW_FORM_block4                 0x04
+#define DW_FORM_data2                  0x05
+#define DW_FORM_data4                  0x06
+#define DW_FORM_data8                  0x07
+#define DW_FORM_string                 0x08
+#define DW_FORM_block                  0x09
+#define DW_FORM_block1                 0x0a
+#define DW_FORM_data1                  0x0b
+#define DW_FORM_flag                   0x0c
+#define DW_FORM_sdata                  0x0d
+#define DW_FORM_strp                   0x0e
+#define DW_FORM_udata                  0x0f
+#define DW_FORM_ref_addr               0x10
+#define DW_FORM_ref1                   0x11
+#define DW_FORM_ref2                   0x12
+#define DW_FORM_ref4                   0x13
+#define DW_FORM_ref8                   0x14
+#define DW_FORM_ref_udata              0x15
+#define DW_FORM_indirect               0x16
+
+#define DW_AT_sibling                  0x01
+#define DW_AT_location                 0x02
+#define DW_AT_name                     0x03
+#define DW_AT_ordering                 0x09
+#define DW_AT_subscr_data              0x0a
+#define DW_AT_byte_size                        0x0b
+#define DW_AT_bit_offset               0x0c
+#define DW_AT_bit_size                 0x0d
+#define DW_AT_element_list             0x0f
+#define DW_AT_stmt_list                        0x10
+#define DW_AT_low_pc                   0x11
+#define DW_AT_high_pc                  0x12
+#define DW_AT_language                 0x13
+#define DW_AT_member                   0x14
+#define DW_AT_discr                    0x15
+#define DW_AT_discr_value              0x16
+#define DW_AT_visibility               0x17
+#define DW_AT_import                   0x18
+#define DW_AT_string_length            0x19
+#define DW_AT_common_reference         0x1a
+#define DW_AT_comp_dir                 0x1b
+#define DW_AT_const_value              0x1c
+#define DW_AT_containing_type          0x1d
+#define DW_AT_default_value            0x1e
+#define DW_AT_inline                   0x20
+#define DW_AT_is_optional              0x21
+#define DW_AT_lower_bound              0x22
+#define DW_AT_producer                 0x25
+#define DW_AT_prototyped               0x27
+#define DW_AT_return_addr              0x2a
+#define DW_AT_start_scope              0x2c
+#define DW_AT_stride_size              0x2e
+#define DW_AT_upper_bound              0x2f
+#define DW_AT_abstract_origin          0x31
+#define DW_AT_accessibility            0x32
+#define DW_AT_address_class            0x33
+#define DW_AT_artificial               0x34
+#define DW_AT_base_types               0x35
+#define DW_AT_calling_convention       0x36
+#define DW_AT_count                    0x37
+#define DW_AT_data_member_location     0x38
+#define DW_AT_decl_column              0x39
+#define DW_AT_decl_file                        0x3a
+#define DW_AT_decl_line                        0x3b
+#define DW_AT_declaration              0x3c
+#define DW_AT_discr_list               0x3d
+#define DW_AT_encoding                 0x3e
+#define DW_AT_external                 0x3f
+#define DW_AT_frame_base               0x40
+#define DW_AT_friend                   0x41
+#define DW_AT_identifier_case          0x42
+#define DW_AT_macro_info               0x43
+#define DW_AT_namelist_items           0x44
+#define DW_AT_priority                 0x45
+#define DW_AT_segment                  0x46
+#define DW_AT_specification            0x47
+#define DW_AT_static_link              0x48
+#define DW_AT_type                     0x49
+#define DW_AT_use_location             0x4a
+#define DW_AT_variable_parameter       0x4b
+#define DW_AT_virtuality               0x4c
+#define DW_AT_vtable_elem_location     0x4d
+#define DW_AT_allocated                        0x4e
+#define DW_AT_associated               0x4f
+#define DW_AT_data_location            0x50 
+#define DW_AT_stride                   0x51
+#define DW_AT_entry_pc                 0x52
+#define DW_AT_use_UTF8                 0x53
+#define DW_AT_extension                        0x54
+#define DW_AT_ranges                   0x55
+#define DW_AT_trampoline               0x56
+#define DW_AT_call_column              0x57 
+#define DW_AT_call_file                        0x58
+#define DW_AT_call_line                        0x59
+#define DW_AT_MIPS_fde                 0x2001
+#define DW_AT_MIPS_loop_begin          0x2002
+#define DW_AT_MIPS_tail_loop_begin     0x2003
+#define DW_AT_MIPS_epilog_begin                0x2004
+#define DW_AT_MIPS_loop_unroll_factor  0x2005
+#define DW_AT_MIPS_software_pipeline_depth 0x2006
+#define DW_AT_MIPS_linkage_name                0x2007
+#define DW_AT_MIPS_stride              0x2008
+#define DW_AT_MIPS_abstract_name       0x2009
+#define DW_AT_MIPS_clone_origin                0x200a
+#define DW_AT_MIPS_has_inlines         0x200b
+#define DW_AT_sf_names                 0x2101
+#define DW_AT_src_info                 0x2102
+#define DW_AT_mac_info                 0x2103
+#define DW_AT_src_coords               0x2104
+#define DW_AT_body_begin               0x2105
+#define DW_AT_body_end                 0x2106
+#define DW_AT_lo_user                  0x2000
+#define DW_AT_hi_user                  0x3ff0
+
+#define DW_OP_addr                     0x03
+#define DW_OP_deref                    0x06
+#define DW_OP_const1u                  0x08
+#define DW_OP_const1s                  0x09
+#define DW_OP_const2u                  0x0a
+#define DW_OP_const2s                  0x0b
+#define DW_OP_const4u                  0x0c
+#define DW_OP_const4s                  0x0d
+#define DW_OP_const8u                  0x0e
+#define DW_OP_const8s                  0x0f
+#define DW_OP_constu                   0x10
+#define DW_OP_consts                   0x11
+#define DW_OP_dup                      0x12
+#define DW_OP_drop                     0x13
+#define DW_OP_over                     0x14
+#define DW_OP_pick                     0x15
+#define DW_OP_swap                     0x16
+#define DW_OP_rot                      0x17
+#define DW_OP_xderef                   0x18
+#define DW_OP_abs                      0x19
+#define DW_OP_and                      0x1a
+#define DW_OP_div                      0x1b
+#define DW_OP_minus                    0x1c
+#define DW_OP_mod                      0x1d
+#define DW_OP_mul                      0x1e
+#define DW_OP_neg                      0x1f
+#define DW_OP_not                      0x20
+#define DW_OP_or                       0x21
+#define DW_OP_plus                     0x22
+#define DW_OP_plus_uconst              0x23
+#define DW_OP_shl                      0x24
+#define DW_OP_shr                      0x25
+#define DW_OP_shra                     0x26
+#define DW_OP_xor                      0x27
+#define DW_OP_bra                      0x28
+#define DW_OP_eq                       0x29
+#define DW_OP_ge                       0x2a
+#define DW_OP_gt                       0x2b
+#define DW_OP_le                       0x2c
+#define DW_OP_lt                       0x2d
+#define DW_OP_ne                       0x2e
+#define DW_OP_skip                     0x2f
+#define DW_OP_lit0                     0x30
+#define DW_OP_lit1                     0x31
+#define DW_OP_lit2                     0x32
+#define DW_OP_lit3                     0x33
+#define DW_OP_lit4                     0x34
+#define DW_OP_lit5                     0x35
+#define DW_OP_lit6                     0x36
+#define DW_OP_lit7                     0x37
+#define DW_OP_lit8                     0x38
+#define DW_OP_lit9                     0x39
+#define DW_OP_lit10                    0x3a
+#define DW_OP_lit11                    0x3b
+#define DW_OP_lit12                    0x3c
+#define DW_OP_lit13                    0x3d
+#define DW_OP_lit14                    0x3e
+#define DW_OP_lit15                    0x3f
+#define DW_OP_lit16                    0x40
+#define DW_OP_lit17                    0x41
+#define DW_OP_lit18                    0x42
+#define DW_OP_lit19                    0x43
+#define DW_OP_lit20                    0x44
+#define DW_OP_lit21                    0x45
+#define DW_OP_lit22                    0x46
+#define DW_OP_lit23                    0x47
+#define DW_OP_lit24                    0x48
+#define DW_OP_lit25                    0x49
+#define DW_OP_lit26                    0x4a
+#define DW_OP_lit27                    0x4b
+#define DW_OP_lit28                    0x4c
+#define DW_OP_lit29                    0x4d
+#define DW_OP_lit30                    0x4e
+#define DW_OP_lit31                    0x4f
+#define DW_OP_reg0                     0x50
+#define DW_OP_reg1                     0x51
+#define DW_OP_reg2                     0x52
+#define DW_OP_reg3                     0x53
+#define DW_OP_reg4                     0x54
+#define DW_OP_reg5                     0x55
+#define DW_OP_reg6                     0x56
+#define DW_OP_reg7                     0x57
+#define DW_OP_reg8                     0x58
+#define DW_OP_reg9                     0x59
+#define DW_OP_reg10                    0x5a
+#define DW_OP_reg11                    0x5b
+#define DW_OP_reg12                    0x5c
+#define DW_OP_reg13                    0x5d
+#define DW_OP_reg14                    0x5e
+#define DW_OP_reg15                    0x5f
+#define DW_OP_reg16                    0x60
+#define DW_OP_reg17                    0x61
+#define DW_OP_reg18                    0x62
+#define DW_OP_reg19                    0x63
+#define DW_OP_reg20                    0x64
+#define DW_OP_reg21                    0x65
+#define DW_OP_reg22                    0x66
+#define DW_OP_reg23                    0x67
+#define DW_OP_reg24                    0x68
+#define DW_OP_reg25                    0x69
+#define DW_OP_reg26                    0x6a
+#define DW_OP_reg27                    0x6b
+#define DW_OP_reg28                    0x6c
+#define DW_OP_reg29                    0x6d
+#define DW_OP_reg30                    0x6e
+#define DW_OP_reg31                    0x6f
+#define DW_OP_breg0                    0x70
+#define DW_OP_breg1                    0x71
+#define DW_OP_breg2                    0x72
+#define DW_OP_breg3                    0x73
+#define DW_OP_breg4                    0x74
+#define DW_OP_breg5                    0x75
+#define DW_OP_breg6                    0x76
+#define DW_OP_breg7                    0x77
+#define DW_OP_breg8                    0x78
+#define DW_OP_breg9                    0x79
+#define DW_OP_breg10                   0x7a
+#define DW_OP_breg11                   0x7b
+#define DW_OP_breg12                   0x7c
+#define DW_OP_breg13                   0x7d
+#define DW_OP_breg14                   0x7e
+#define DW_OP_breg15                   0x7f
+#define DW_OP_breg16                   0x80
+#define DW_OP_breg17                   0x81
+#define DW_OP_breg18                   0x82
+#define DW_OP_breg19                   0x83
+#define DW_OP_breg20                   0x84
+#define DW_OP_breg21                   0x85
+#define DW_OP_breg22                   0x86
+#define DW_OP_breg23                   0x87
+#define DW_OP_breg24                   0x88
+#define DW_OP_breg25                   0x89
+#define DW_OP_breg26                   0x8a
+#define DW_OP_breg27                   0x8b
+#define DW_OP_breg28                   0x8c
+#define DW_OP_breg29                   0x8d
+#define DW_OP_breg30                   0x8e
+#define DW_OP_breg31                   0x8f
+#define DW_OP_regx                     0x90
+#define DW_OP_fbreg                    0x91
+#define DW_OP_bregx                    0x92
+#define DW_OP_piece                    0x93
+#define DW_OP_deref_size               0x94
+#define DW_OP_xderef_size              0x95
+#define DW_OP_nop                      0x96
+#define DW_OP_push_object_address      0x97
+#define DW_OP_call2                    0x98
+#define DW_OP_call4                    0x99
+#define DW_OP_calli                    0x9a
+#define DW_OP_lo_user                  0x80
+#define DW_OP_hi_user                  0xff
+
+#define DW_ATE_void                    0x0
+#define DW_ATE_address                 0x1
+#define DW_ATE_boolean                 0x2
+#define DW_ATE_complex_float           0x3
+#define DW_ATE_float                   0x4
+#define DW_ATE_signed                  0x5
+#define DW_ATE_signed_char             0x6
+#define DW_ATE_unsigned                        0x7
+#define DW_ATE_unsigned_char           0x8
+#define DW_ATE_imaginary_float         0x9
+#define        DW_ATE_lo_user                  0x80
+#define        DW_ATE_hi_user                  0xff
+
+#define DW_ORD_row_major               0x0
+#define DW_ORD_col_major               0x1
+
+#define DW_ACCESS_public               0x1
+#define DW_ACCESS_protected            0x2
+#define DW_ACCESS_private              0x3
+
+#define DW_VIS_local                   0x1
+#define DW_VIS_exported                        0x2
+#define DW_VIS_qualified               0x3
+
+#define DW_VIRTUALITY_none             0x0
+#define DW_VIRTUALITY_virtual          0x1
+#define DW_VIRTUALITY_pure_virtual     0x2
+
+#define DW_ID_case_sensitive           0x0
+#define DW_ID_up_case                  0x1
+#define DW_ID_down_case                        0x2
+#define DW_ID_case_insensitive         0x3
+
+#define DW_CC_normal                   0x1
+#define DW_CC_program                  0x2
+#define DW_CC_nocall                   0x3
+#define DW_CC_lo_user                  0x40
+#define DW_CC_hi_user                  0xff
+
+#define DW_INL_not_inlined             0x0
+#define DW_INL_inlined                 0x1
+#define DW_INL_declared_not_inlined    0x2
+#define DW_INL_declared_inlined                0x3
+
+#define DW_DSC_label                   0x0
+#define DW_DSC_range                   0x1
+
+#define DW_LNS_extended_op             0x0
+#define DW_LNS_copy                    0x1
+#define DW_LNS_advance_pc              0x2
+#define DW_LNS_advance_line            0x3
+#define DW_LNS_set_file                        0x4
+#define DW_LNS_set_column              0x5
+#define DW_LNS_negate_stmt             0x6
+#define DW_LNS_set_basic_block         0x7
+#define DW_LNS_const_add_pc            0x8
+#define DW_LNS_fixed_advance_pc                0x9
+
+#define DW_LNE_end_sequence            0x1
+#define DW_LNE_set_address             0x2
+#define DW_LNE_define_file             0x3
+
+#define DW_CFA_advance_loc             0x40
+#define DW_CFA_offset                  0x80
+#define DW_CFA_restore                 0xc0
+#define DW_CFA_nop                     0x00
+#define DW_CFA_set_loc                 0x01
+#define DW_CFA_advance_loc1            0x02
+#define DW_CFA_advance_loc2            0x03
+#define DW_CFA_advance_loc4            0x04
+#define DW_CFA_offset_extended         0x05
+#define DW_CFA_restore_extended                0x06
+#define DW_CFA_undefined               0x07
+#define DW_CFA_same_value              0x08
+#define DW_CFA_register                        0x09
+#define DW_CFA_remember_state          0x0a
+#define DW_CFA_restore_state           0x0b
+#define DW_CFA_def_cfa                 0x0c
+#define DW_CFA_def_cfa_register                0x0d
+#define DW_CFA_def_cfa_offset          0x0e
+#define DW_CFA_def_cfa_expression      0x0f
+#define DW_CFA_expression              0x10
+#define DW_CFA_offset_extended_sf      0x11
+#define DW_CFA_def_cfa_sf              0x12
+#define DW_CFA_def_cfa_offset_sf       0x13
+#define DW_CFA_MIPS_advance_loc8       0x1d
+#define DW_CFA_GNU_window_save         0x2d
+#define DW_CFA_GNU_args_size           0x2e
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+
+#define DW_CIE_ID                      0xffffffff
+#define DW_CIE_VERSION                 1
+
+#define DW_CFA_extended                0
+#define DW_CFA_low_user                0x1c
+#define DW_CFA_high_user               0x3f
+
+#define DW_CHILDREN_no                 0x00
+#define DW_CHILDREN_yes                        0x01
+
+#define DW_ADDR_none                   0
+
+#define DW_LANG_C89                    0x0001
+#define DW_LANG_C                      0x0002
+#define DW_LANG_Ada83                  0x0003
+#define DW_LANG_C_plus_plus            0x0004
+#define DW_LANG_Cobol74                        0x0005
+#define DW_LANG_Cobol85                        0x0006
+#define DW_LANG_Fortran77              0x0007
+#define DW_LANG_Fortran90              0x0008
+#define DW_LANG_Pascal83               0x0009
+#define DW_LANG_Modula2                        0x000a
+#define DW_LANG_Java                   0x000b
+#define DW_LANG_C99                    0x000c
+#define DW_LANG_Ada95                  0x000d
+#define DW_LANG_Fortran95              0x000e
+#define DW_LANG_Mips_Assembler         0x8001
+#define DW_LANG_lo_user                        0x8000
+#define DW_LANG_hi_user                        0xffff
+
+#define DW_MACINFO_define              1
+#define DW_MACINFO_undef               2
+#define DW_MACINFO_start_file          3
+#define DW_MACINFO_end_file            4
+#define DW_MACINFO_vendor_ext          255
diff --git a/tools/hashtab.c b/tools/hashtab.c
new file mode 100644 (file)
index 0000000..e498545
--- /dev/null
@@ -0,0 +1,523 @@
+/* An expandable hash tables datatype.  
+   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This package implements basic hash table functionality.  It is possible
+   to search for an entry, create an entry and destroy an entry.
+
+   Elements in the table are generic pointers.
+
+   The size of the table is not fixed; if the occupancy of the table
+   grows too high the hash table will be expanded.
+
+   The abstract data implementation is based on generalized Algorithm D
+   from Knuth's book "The art of computer programming".  Hash table is
+   expanded by creation of new hash table and transferring elements from
+   the old table to the new table. */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "hashtab.h"
+
+/* This macro defines reserved value for empty table entry. */
+
+#define EMPTY_ENTRY    ((void *) 0)
+
+/* This macro defines reserved value for table entry which contained
+   a deleted element. */
+
+#define DELETED_ENTRY  ((void *) 1)
+
+static unsigned long higher_prime_number (unsigned long);
+static hashval_t hash_pointer (const void *);
+static int eq_pointer (const void *, const void *);
+static int htab_expand (htab_t);
+static void **find_empty_slot_for_expand  (htab_t, hashval_t);
+
+/* At some point, we could make these be NULL, and modify the
+   hash-table routines to handle NULL specially; that would avoid
+   function-call overhead for the common case of hashing pointers.  */
+htab_hash htab_hash_pointer = hash_pointer;
+htab_eq htab_eq_pointer = eq_pointer;
+
+/* The following function returns a nearest prime number which is
+   greater than N, and near a power of two. */
+
+static unsigned long
+higher_prime_number (n)
+     unsigned long n;
+{
+  /* These are primes that are near, but slightly smaller than, a
+     power of two.  */
+  static unsigned long primes[] = {
+    (unsigned long) 2,
+    (unsigned long) 7,
+    (unsigned long) 13,
+    (unsigned long) 31,
+    (unsigned long) 61,
+    (unsigned long) 127,
+    (unsigned long) 251,
+    (unsigned long) 509,
+    (unsigned long) 1021,
+    (unsigned long) 2039,
+    (unsigned long) 4093,
+    (unsigned long) 8191,
+    (unsigned long) 16381,
+    (unsigned long) 32749,
+    (unsigned long) 65521,
+    (unsigned long) 131071,
+    (unsigned long) 262139,
+    (unsigned long) 524287,
+    (unsigned long) 1048573,
+    (unsigned long) 2097143,
+    (unsigned long) 4194301,
+    (unsigned long) 8388593,
+    (unsigned long) 16777213,
+    (unsigned long) 33554393,
+    (unsigned long) 67108859,
+    (unsigned long) 134217689,
+    (unsigned long) 268435399,
+    (unsigned long) 536870909,
+    (unsigned long) 1073741789,
+    (unsigned long) 2147483647,
+                                       /* 4294967291L */
+    ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+  };
+
+  unsigned long* low = &primes[0];
+  unsigned long* high = &primes[sizeof(primes) / sizeof(primes[0])];
+
+  while (low != high)
+    {
+      unsigned long* mid = low + (high - low) / 2;
+      if (n > *mid)
+       low = mid + 1;
+      else
+       high = mid;
+    }
+
+  /* If we've run out of primes, abort.  */
+  if (n > *low)
+    {
+      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+      abort ();
+    }
+
+  return *low;
+}
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_pointer (p)
+     const void * p;
+{
+  return (hashval_t) ((long)p >> 3);
+}
+
+/* Returns non-zero if P1 and P2 are equal.  */
+
+static int
+eq_pointer (p1, p2)
+     const void * p1;
+     const void * p2;
+{
+  return p1 == p2;
+}
+
+/* This function creates table with length slightly longer than given
+   source length.  The created hash table is initiated as empty (all the
+   hash table entries are EMPTY_ENTRY).  The function returns the created
+   hash table.  Memory allocation may fail; it may return NULL.  */
+
+htab_t
+htab_try_create (size, hash_f, eq_f, del_f)
+     size_t size;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+{
+  htab_t result;
+
+  size = higher_prime_number (size);
+  result = (htab_t) calloc (1, sizeof (struct htab));
+  if (result == NULL)
+    return NULL;
+
+  result->entries = (void **) calloc (size, sizeof (void *));
+  if (result->entries == NULL)
+    {
+      free (result);
+      return NULL;
+    }
+
+  result->size = size;
+  result->hash_f = hash_f;
+  result->eq_f = eq_f;
+  result->del_f = del_f;
+  result->return_allocation_failure = 1;
+  return result;
+}
+
+/* This function frees all memory allocated for given hash table.
+   Naturally the hash table must already exist. */
+
+void
+htab_delete (htab)
+     htab_t htab;
+{
+  int i;
+
+  if (htab->del_f)
+    for (i = htab->size - 1; i >= 0; i--)
+      if (htab->entries[i] != EMPTY_ENTRY
+         && htab->entries[i] != DELETED_ENTRY)
+       (*htab->del_f) (htab->entries[i]);
+
+  free (htab->entries);
+  free (htab);
+}
+
+/* This function clears all entries in the given hash table.  */
+
+void
+htab_empty (htab)
+     htab_t htab;
+{
+  int i;
+
+  if (htab->del_f)
+    for (i = htab->size - 1; i >= 0; i--)
+      if (htab->entries[i] != EMPTY_ENTRY
+         && htab->entries[i] != DELETED_ENTRY)
+       (*htab->del_f) (htab->entries[i]);
+
+  memset (htab->entries, 0, htab->size * sizeof (void *));
+}
+
+/* Similar to htab_find_slot, but without several unwanted side effects:
+    - Does not call htab->eq_f when it finds an existing entry.
+    - Does not change the count of elements/searches/collisions in the
+      hash table.
+   This function also assumes there are no deleted entries in the table.
+   HASH is the hash value for the element to be inserted.  */
+
+static void **
+find_empty_slot_for_expand (htab, hash)
+     htab_t htab;
+     hashval_t hash;
+{
+  size_t size = htab->size;
+  hashval_t hash2 = 1 + hash % (size - 2);
+  unsigned int index = hash % size;
+
+  for (;;)
+    {
+      void **slot = htab->entries + index;
+
+      if (*slot == EMPTY_ENTRY)
+       return slot;
+      else if (*slot == DELETED_ENTRY)
+       abort ();
+
+      index += hash2;
+      if (index >= size)
+       index -= size;
+    }
+}
+
+/* The following function changes size of memory allocated for the
+   entries and repeatedly inserts the table elements.  The occupancy
+   of the table after the call will be about 50%.  Naturally the hash
+   table must already exist.  Remember also that the place of the
+   table entries is changed.  If memory allocation failures are allowed,
+   this function will return zero, indicating that the table could not be
+   expanded.  If all goes well, it will return a non-zero value.  */
+
+static int
+htab_expand (htab)
+     htab_t htab;
+{
+  void **oentries;
+  void **olimit;
+  void **p;
+
+  oentries = htab->entries;
+  olimit = oentries + htab->size;
+
+  htab->size = higher_prime_number (htab->size * 2);
+
+  if (htab->return_allocation_failure)
+    {
+      void **nentries = (void **) calloc (htab->size, sizeof (void **));
+      if (nentries == NULL)
+       return 0;
+      htab->entries = nentries;
+    }
+
+  htab->n_elements -= htab->n_deleted;
+  htab->n_deleted = 0;
+
+  p = oentries;
+  do
+    {
+      void * x = *p;
+
+      if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+       {
+         void **q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x));
+
+         *q = x;
+       }
+
+      p++;
+    }
+  while (p < olimit);
+
+  free (oentries);
+  return 1;
+}
+
+/* This function searches for a hash table entry equal to the given
+   element.  It cannot be used to insert or delete an element.  */
+
+void *
+htab_find_with_hash (htab, element, hash)
+     htab_t htab;
+     const void * element;
+     hashval_t hash;
+{
+  unsigned int index;
+  hashval_t hash2;
+  size_t size;
+  void * entry;
+
+  htab->searches++;
+  size = htab->size;
+  index = hash % size;
+
+  entry = htab->entries[index];
+  if (entry == EMPTY_ENTRY
+      || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+    return entry;
+
+  hash2 = 1 + hash % (size - 2);
+
+  for (;;)
+    {
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+       index -= size;
+
+      entry = htab->entries[index];
+      if (entry == EMPTY_ENTRY
+         || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+       return entry;
+    }
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+   element.  */
+
+void *
+htab_find (htab, element)
+     htab_t htab;
+     const void * element;
+{
+  return htab_find_with_hash (htab, element, (*htab->hash_f) (element));
+}
+
+/* This function searches for a hash table slot containing an entry
+   equal to the given element.  To delete an entry, call this with
+   INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+   after doing some checks).  To insert an entry, call this with
+   INSERT = 1, then write the value you want into the returned slot.
+   When inserting an entry, NULL may be returned if memory allocation
+   fails.  */
+
+void **
+htab_find_slot_with_hash (htab, element, hash, insert)
+     htab_t htab;
+     const void * element;
+     hashval_t hash;
+     enum insert_option insert;
+{
+  void **first_deleted_slot;
+  unsigned int index;
+  hashval_t hash2;
+  size_t size;
+
+  if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4
+      && htab_expand (htab) == 0)
+    return NULL;
+
+  size = htab->size;
+  hash2 = 1 + hash % (size - 2);
+  index = hash % size;
+
+  htab->searches++;
+  first_deleted_slot = NULL;
+
+  for (;;)
+    {
+      void * entry = htab->entries[index];
+      if (entry == EMPTY_ENTRY)
+       {
+         if (insert == NO_INSERT)
+           return NULL;
+
+         htab->n_elements++;
+
+         if (first_deleted_slot)
+           {
+             *first_deleted_slot = EMPTY_ENTRY;
+             return first_deleted_slot;
+           }
+
+         return &htab->entries[index];
+       }
+
+      if (entry == DELETED_ENTRY)
+       {
+         if (!first_deleted_slot)
+           first_deleted_slot = &htab->entries[index];
+       }
+      else  if ((*htab->eq_f) (entry, element))
+       return &htab->entries[index];
+      
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+       index -= size;
+    }
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+   element.  */
+
+void **
+htab_find_slot (htab, element, insert)
+     htab_t htab;
+     const void * element;
+     enum insert_option insert;
+{
+  return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element),
+                                  insert);
+}
+
+/* This function deletes an element with the given value from hash
+   table.  If there is no matching element in the hash table, this
+   function does nothing.  */
+
+void
+htab_remove_elt (htab, element)
+     htab_t htab;
+     void * element;
+{
+  void **slot;
+
+  slot = htab_find_slot (htab, element, NO_INSERT);
+  if (*slot == EMPTY_ENTRY)
+    return;
+
+  if (htab->del_f)
+    (*htab->del_f) (*slot);
+
+  *slot = DELETED_ENTRY;
+  htab->n_deleted++;
+}
+
+/* This function clears a specified slot in a hash table.  It is
+   useful when you've already done the lookup and don't want to do it
+   again.  */
+
+void
+htab_clear_slot (htab, slot)
+     htab_t htab;
+     void **slot;
+{
+  if (slot < htab->entries || slot >= htab->entries + htab->size
+      || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY)
+    abort ();
+
+  if (htab->del_f)
+    (*htab->del_f) (*slot);
+
+  *slot = DELETED_ENTRY;
+  htab->n_deleted++;
+}
+
+/* This function scans over the entire hash table calling
+   CALLBACK for each live entry.  If CALLBACK returns false,
+   the iteration stops.  INFO is passed as CALLBACK's second
+   argument.  */
+
+void
+htab_traverse (htab, callback, info)
+     htab_t htab;
+     htab_trav callback;
+     void * info;
+{
+  void **slot = htab->entries;
+  void **limit = slot + htab->size;
+
+  do
+    {
+      void * x = *slot;
+
+      if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+       if (!(*callback) (slot, info))
+         break;
+    }
+  while (++slot < limit);
+}
+
+/* Return the current size of given hash table. */
+
+size_t
+htab_size (htab)
+     htab_t htab;
+{
+  return htab->size;
+}
+
+/* Return the current number of elements in given hash table. */
+
+size_t
+htab_elements (htab)
+     htab_t htab;
+{
+  return htab->n_elements - htab->n_deleted;
+}
+
+/* Return the fraction of fixed collisions during all work with given
+   hash table. */
+
+double
+htab_collisions (htab)
+     htab_t htab;
+{
+  if (htab->searches == 0)
+    return 0.0;
+
+  return (double) htab->collisions / (double) htab->searches;
+}
diff --git a/tools/hashtab.h b/tools/hashtab.h
new file mode 100644 (file)
index 0000000..9ed18ae
--- /dev/null
@@ -0,0 +1,143 @@
+/* An expandable hash tables datatype.  
+   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+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
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* This package implements basic hash table functionality.  It is possible
+   to search for an entry, create an entry and destroy an entry.
+
+   Elements in the table are generic pointers.
+
+   The size of the table is not fixed; if the occupancy of the table
+   grows too high the hash table will be expanded.
+
+   The abstract data implementation is based on generalized Algorithm D
+   from Knuth's book "The art of computer programming".  Hash table is
+   expanded by creation of new hash table and transferring elements from
+   the old table to the new table.  */
+
+#ifndef __HASHTAB_H__
+#define __HASHTAB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* The type for a hash code.  */
+typedef unsigned int hashval_t;
+
+/* Callback function pointer types.  */
+
+/* Calculate hash of a table entry.  */
+typedef hashval_t (*htab_hash) (const void *);
+
+/* Compare a table entry with a possible entry.  The entry already in
+   the table always comes first, so the second element can be of a
+   different type (but in this case htab_find and htab_find_slot
+   cannot be used; instead the variants that accept a hash value
+   must be used).  */
+typedef int (*htab_eq) (const void *, const void *);
+
+/* Cleanup function called whenever a live element is removed from
+   the hash table.  */
+typedef void (*htab_del) (void *);
+  
+/* Function called by htab_traverse for each live element.  The first
+   arg is the slot of the element (which can be passed to htab_clear_slot
+   if desired), the second arg is the auxiliary pointer handed to
+   htab_traverse.  Return 1 to continue scan, 0 to stop.  */
+typedef int (*htab_trav) (void **, void *);
+
+/* Hash tables are of the following type.  The structure
+   (implementation) of this type is not needed for using the hash
+   tables.  All work with hash table should be executed only through
+   functions mentioned below. */
+
+struct htab
+{
+  /* Pointer to hash function.  */
+  htab_hash hash_f;
+
+  /* Pointer to comparison function.  */
+  htab_eq eq_f;
+
+  /* Pointer to cleanup function.  */
+  htab_del del_f;
+
+  /* Table itself.  */
+  void **entries;
+
+  /* Current size (in entries) of the hash table */
+  size_t size;
+
+  /* Current number of elements including also deleted elements */
+  size_t n_elements;
+
+  /* Current number of deleted elements in the table */
+  size_t n_deleted;
+
+  /* The following member is used for debugging. Its value is number
+     of all calls of `htab_find_slot' for the hash table. */
+  unsigned int searches;
+
+  /* The following member is used for debugging.  Its value is number
+     of collisions fixed for time of work with the hash table. */
+  unsigned int collisions;
+
+  /* This is non-zero if we are allowed to return NULL for function calls
+     that allocate memory.  */
+  int return_allocation_failure;
+};
+
+typedef struct htab *htab_t;
+
+/* An enum saying whether we insert into the hash table or not.  */
+enum insert_option {NO_INSERT, INSERT};
+
+/* The prototypes of the package functions. */
+
+/* This function is like htab_create, but may return NULL if memory
+   allocation fails, and also signals that htab_find_slot_with_hash and
+   htab_find_slot are allowed to return NULL when inserting.  */
+extern htab_t  htab_try_create (size_t, htab_hash, htab_eq, htab_del);
+extern void    htab_delete     (htab_t);
+extern void    htab_empty      (htab_t);
+
+extern void    *htab_find      (htab_t, const void *);
+extern void    **htab_find_slot        (htab_t, const void *, enum insert_option);
+extern void    *htab_find_with_hash (htab_t, const void *, hashval_t);
+extern void    **htab_find_slot_with_hash (htab_t, const void *, hashval_t,
+                                         enum insert_option);
+extern void    htab_clear_slot (htab_t, void **);
+extern void    htab_remove_elt (htab_t, void *);
+
+extern void    htab_traverse   (htab_t, htab_trav, void *);
+
+extern size_t  htab_size       (htab_t);
+extern size_t  htab_elements   (htab_t);
+extern double  htab_collisions (htab_t);
+
+/* A hash function for pointers.  */
+extern htab_hash htab_hash_pointer;
+
+/* An equality function for pointers.  */
+extern htab_eq htab_eq_pointer;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __HASHTAB_H */
index 2e5aa19..914aab6 100644 (file)
@@ -150,10 +150,10 @@ static unsigned int crc32 (unsigned int crc, unsigned char *buf, size_t len)
 {
   unsigned char *end;
 
-  crc = ~crc;
+  crc = ~crc & 0xffffffff;
   for (end = buf + len; buf < end; ++buf)
     crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
-  return ~crc;
+  return ~crc & 0xffffffff;
 }
 
 unsigned int