public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 15/19] libctf: mmappable archives
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
  2019-04-30 22:57 ` [PATCH 02/19] include: new header ctf-api.h Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 05/19] libctf: error handling Nick Alcock
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

If you need to store a large number of CTF containers somewhere, this
provides a dedicated facility for doing so: an mmappable archive format
like a very simple tar or ar without all the system-dependent format
horrors or need for heavy file copying, with built-in compression of
files above a particular size threshold.

libctf automatically mmap()s uncompressed elements of these archives, or
uncompresses them, as needed.

Archive iteration operations are partitioned into raw and non-raw
forms. Raw operations pass thhe raw archive contents to the callback:
non-raw forms open each member with ctf_bufopen() and pass the resulting
ctf_file_t to the iterator instead.  This lets you manipulate the raw
data in the archive, or the contents interpreted as a CTF file, as
needed.

It is not yet known whether we will store CTF archives in a linked ELF
object in one of these (akin to debugdata) or whether they'll get one
section per TU plus one parent container for types shared between them.
(In the case of ELF objects with very large numbers of TUs, an archive
of all of them would seem preferable.)

libctf/
	* ctf-archive.c: New.
include/
	* ctf-api.h (ctf_archive_member_f): New.
	(ctf_archive_raw_member_f): Likewise.
	(ctf_arc_write): Likewise.
	(ctf_arc_open): Likewise.
	(ctf_arc_close): Likewise.
	(ctf_arc_open_by_name): Likewise.
	(ctf_archive_iter): Likewise.
	(ctf_archive_raw_iter): Likewise.
---
 include/ctf-api.h    |  14 ++
 libctf/ctf-archive.c | 491 +++++++++++++++++++++++++++++++++++++++++++
 libctf/ctf-impl.h    |  44 ++++
 3 files changed, 549 insertions(+)
 create mode 100644 libctf/ctf-archive.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 3fcb1d2d6c..8687fa9004 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -208,6 +208,9 @@ typedef int ctf_member_f (const char *name, ctf_id_t membtype,
 typedef int ctf_enum_f (const char *name, int val, void *arg);
 typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg);
 typedef int ctf_type_f (ctf_id_t type, void *arg);
+typedef int ctf_archive_member_f (ctf_file_t *fp, const char *name, void *arg);
+typedef int ctf_archive_raw_member_f (const char *name, const void *content,
+				      size_t len, void *arg);
 extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
 				   size_t, const char *, size_t, int *);
 extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
@@ -218,6 +221,13 @@ extern ctf_file_t *ctf_create (int *);
 extern void ctf_close (ctf_file_t *);
 extern ctf_sect_t ctf_getdatasect (const ctf_file_t *);
 
+extern int ctf_arc_write (const char *, ctf_file_t **, size_t,
+			  const char **, size_t);
+extern ctf_archive_t *ctf_arc_open (const char *, int *);
+extern void ctf_arc_close (ctf_archive_t *);
+extern ctf_file_t *ctf_arc_open_by_name (const ctf_archive_t *,
+					 const char *, int *);
+
 extern ctf_file_t *ctf_parent_file (ctf_file_t *);
 extern const char *ctf_parent_name (ctf_file_t *);
 extern void ctf_parent_name_set (ctf_file_t *, const char *);
@@ -267,6 +277,10 @@ extern int ctf_member_iter (ctf_file_t *, ctf_id_t, ctf_member_f *, void *);
 extern int ctf_enum_iter (ctf_file_t *, ctf_id_t, ctf_enum_f *, void *);
 extern int ctf_type_iter (ctf_file_t *, ctf_type_f *, void *);
 extern int ctf_variable_iter (ctf_file_t *, ctf_variable_f *, void *);
+extern int ctf_archive_iter (const ctf_archive_t *, ctf_archive_member_f *,
+			     void *);
+extern int ctf_archive_raw_iter (const ctf_archive_t *,
+				 ctf_archive_raw_member_f *, void *);
 extern ctf_id_t ctf_add_array (ctf_file_t *, uint32_t,
 			       const ctf_arinfo_t *);
 extern ctf_id_t ctf_add_const (ctf_file_t *, uint32_t, ctf_id_t);
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
new file mode 100644
index 0000000000..ad06ed61c1
--- /dev/null
+++ b/libctf/ctf-archive.c
@@ -0,0 +1,491 @@
+/* CTF archive files.
+   Copyright (C) 2017-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <elf.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static off_t arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold);
+static ctf_file_t *ctf_arc_open_by_offset (const ctf_archive_t * arc,
+					   size_t offset, int *errp);
+static int sort_modent_by_name (const void *one, const void *two, void *n);
+
+/* bsearch() internal state.  */
+static __thread char *search_nametbl;
+
+/* Write out a CTF archive.  The entries in CTF_FILES are referenced by name:
+   the names are passed in the names array, which must have CTF_FILES entries.
+
+   Returns 0 on success, or an errno, or an ECTF_* value.  */
+int
+ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
+	       const char **names, size_t threshold)
+{
+  const char *errmsg;
+  struct ctf_archive *archdr;
+  int fd;
+  size_t i;
+  char dummy = 0;
+  size_t headersz;
+  ssize_t namesz;
+  size_t ctf_startoffs;		/* Start of the section we are working over.  */
+  char *nametbl = NULL;		/* The name table.  */
+  char *np;
+  off_t nameoffs;
+  struct ctf_archive_modent *modent;
+
+  ctf_dprintf ("Writing archive %s with %zi files\n", file, ctf_file_cnt);
+
+  if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
+    {
+      errmsg = "ctf_arc_write(): cannot create %s: %s\n";
+      goto err;
+    }
+
+  /* Figure out the size of the mmap()ed header, including the
+     ctf_archive_modent array.  We assume that all of this needs no
+     padding: a likely assumption, given that it's all made up of
+     uint64_t's.  */
+  headersz = sizeof (struct ctf_archive)
+    + (ctf_file_cnt * sizeof (uint64_t) * 2);
+  ctf_dprintf ("headersz is %zi\n", headersz);
+
+  /* From now on we work in two pieces: an mmap()ed region from zero up to
+     the headersz, and a region updated via write() starting after that,
+     containing all the tables.  */
+  ctf_startoffs = headersz;
+  if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
+    {
+      errmsg = "ctf_arc_write(): cannot extend file while writing %s: %s\n";
+      goto err_close;
+    }
+
+  if (write (fd, &dummy, 1) < 0)
+    {
+      errmsg = "ctf_arc_write(): cannot extend file while writing %s: %s\n";
+      goto err_close;
+    }
+
+  if ((archdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
+		      0)) == MAP_FAILED)
+    {
+      errmsg = "ctf_arc_write(): Cannot mmap() %s: %s\n";
+      goto err_close;
+    }
+
+  /* Fill in everything we can, which is everything other than the name
+     table offset.  */
+  archdr->ctfa_magic = htole64 (CTFA_MAGIC);
+  archdr->ctfa_nfiles = htole64 (ctf_file_cnt);
+  archdr->ctfa_ctfs = htole64 (ctf_startoffs);
+
+  /* We could validate that all CTF files have the same data model, but
+     since any reasonable construction process will be building things of
+     only one bitness anyway, this is pretty pointless, so just use the
+     model of the first CTF file for all of them.  (It *is* valid to
+     create an empty archive: the value of ctfa_model is irrelevant in
+     this case, but we must be sure not to dereference uninitialized
+     memory.)  */
+
+  if (ctf_file_cnt > 0)
+    archdr->ctfa_model = htole64 (ctf_getmodel (ctf_files[0]));
+
+  /* Now write out the CTFs: ctf_archive_modent array via the mapping,
+     ctfs via write().  The names themselves have not been written yet: we
+     track them in a local strtab until the time is right, and sort the
+     modents array after construction.
+
+    The name table is not sorted.  */
+
+  for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_nfiles); i++)
+    namesz += strlen (names[i]) + 1;
+
+  nametbl = malloc (namesz);
+  if (nametbl == NULL)
+    {
+      errmsg = "Error writing named CTF to %s: %s\n";
+      goto err_unmap;
+    }
+
+  for (i = 0, namesz = 0,
+       modent = (ctf_archive_modent_t *) ((char *) archdr
+					  + sizeof (struct ctf_archive));
+       i < le64toh (archdr->ctfa_nfiles); i++)
+    {
+      off_t off;
+
+      strcpy (&nametbl[namesz], names[i]);
+
+      off = arc_write_one_ctf (ctf_files[i], fd, threshold);
+      ctf_dprintf ("Written %s, offset now %zi\n", names[i], off);
+      if ((off < 0) && (off > -ECTF_BASE))
+	{
+	  errmsg = "ctf_arc_write(): Cannot determine file "
+	    "position while writing %s: %s";
+	  goto err_free;
+	}
+      if (off < 0)
+	{
+	  errmsg = "ctf_arc_write(): Cannot write CTF file to %s: %s\n";
+	  errno = off * -1;
+	  goto err_free;
+	}
+
+      modent->name_offset = htole64 (namesz);
+      modent->ctf_offset = htole64 (off - ctf_startoffs);
+      namesz += strlen (names[i]) + 1;
+      modent++;
+    }
+
+  qsort_r ((ctf_archive_modent_t *) ((char *) archdr
+				     + sizeof (struct ctf_archive)),
+	   le64toh (archdr->ctfa_nfiles),
+	   sizeof (struct ctf_archive_modent), sort_modent_by_name, nametbl);
+
+   /* Now the name table.  */
+
+  if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
+    {
+      errmsg = "ctf_arc_write(): Cannot get current file position "
+	"in %s: %s\n";
+      goto err_free;
+    }
+  archdr->ctfa_names = htole64 (nameoffs);
+  np = nametbl;
+  while (namesz > 0)
+    {
+      ssize_t len;
+      if ((len = write (fd, np, namesz)) < 0)
+	{
+	  errmsg = "ctf_arc_write(): Cannot write name table in %s: %s\n";
+	  goto err_free;
+	}
+      namesz -= len;
+      np += len;
+    }
+  free (nametbl);
+
+  if (msync (archdr, headersz, MS_ASYNC) < 0)
+    {
+      errmsg = "ctf_arc_write(): Cannot sync after writing to %s: %s\n";
+      goto err_unmap;
+    }
+  munmap (archdr, headersz);
+  if (close (fd) < 0)
+    {
+      errmsg = "ctf_arc_write(): Cannot close after writing to %s: %s\n";
+      goto err_unlink;
+    }
+
+  return 0;
+
+err_free:
+  free (nametbl);
+err_unmap:
+  munmap (archdr, headersz);
+err_close:
+  close (fd);
+err_unlink:
+  unlink (file);
+err:
+  ctf_dprintf (errmsg, file, errno < ECTF_BASE ? strerror (errno) :
+	       ctf_errmsg (errno));
+  return errno;
+}
+
+/* Write one CTF file out.  Return the file position of the written file (or
+   rather, of the file-size uint64_t that precedes it): negative return is a
+   negative errno or ctf_errno value.  On error, the file position may no longer
+   be at the end of the file.  */
+static off_t
+arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold)
+{
+  off_t off, end_off;
+  uint64_t ctfsz = 0;
+  char *ctfszp;
+  size_t ctfsz_len;
+  int (*writefn) (ctf_file_t * fp, int fd);
+
+  if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
+    return errno * -1;
+
+  if (f->ctf_size > threshold)
+    writefn = ctf_compress_write;
+  else
+    writefn = ctf_write;
+
+  /* This zero-write turns into the size in a moment. */
+  ctfsz_len = sizeof (ctfsz);
+  ctfszp = (char *) &ctfsz;
+  while (ctfsz_len > 0)
+    {
+      ssize_t writelen = write (fd, ctfszp, ctfsz_len);
+      if (writelen < 0)
+	return errno * -1;
+      ctfsz_len -= writelen;
+      ctfszp += writelen;
+    }
+
+  if (writefn (f, fd) != 0)
+    return f->ctf_errno * -1;
+
+  if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
+    return errno * -1;
+  ctfsz = htole64 (end_off - off);
+
+  if ((lseek (fd, off, SEEK_SET)) < 0)
+    return errno * -1;
+
+  /* ... here.  */
+  ctfsz_len = sizeof (ctfsz);
+  ctfszp = (char *) &ctfsz;
+  while (ctfsz_len > 0)
+    {
+      ssize_t writelen = write (fd, ctfszp, ctfsz_len);
+      if (writelen < 0)
+	return errno * -1;
+      ctfsz_len -= writelen;
+      ctfszp += writelen;
+    }
+
+  end_off = LCTF_ALIGN_OFFS (end_off, 8);
+  if ((lseek (fd, end_off, SEEK_SET)) < 0)
+    return errno * -1;
+
+  return off;
+}
+
+/* qsort() function to sort the array of struct ctf_archive_modents into
+   ascending name order.  */
+static int
+sort_modent_by_name (const void *one, const void *two, void *n)
+{
+  const struct ctf_archive_modent *a = one;
+  const struct ctf_archive_modent *b = two;
+  char *nametbl = n;
+
+  return strcmp (&nametbl[le64toh (a->name_offset)],
+		 &nametbl[le64toh (b->name_offset)]);
+}
+
+/* bsearch() function to search for a given name in the sorted array of struct
+   ctf_archive_modents.  */
+static int
+search_modent_by_name (const void *key, const void *ent)
+{
+  const char *k = key;
+  const struct ctf_archive_modent *v = ent;
+
+  return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
+}
+
+/* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
+   not NULL).  */
+ctf_archive_t *
+ctf_arc_open (const char *filename, int *errp)
+{
+  const char *errmsg;
+  int fd;
+  struct stat s;
+  ctf_archive_t *arc;		/* (Actually the whole file.)  */
+
+  if ((fd = open (filename, O_RDONLY)) < 0)
+    {
+      errmsg = "ctf_arc_open(): cannot open %s: %s\n";
+      goto err;
+    }
+  if (fstat (fd, &s) < 0)
+    {
+      errmsg = "ctf_arc_open(): cannot stat %s: %s\n";
+      goto err_close;
+    }
+
+  if ((arc = mmap (NULL, s.st_size, PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE, fd, 0)) == MAP_FAILED)
+    {
+      errmsg = "ctf_arc_open(): Cannot mmap() %s: %s\n";
+      goto err_close;
+    }
+
+  if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
+    {
+      errmsg = "ctf_arc_open(): Invalid magic number";
+      errno = ECTF_FMT;
+      goto err_unmap;
+    }
+
+  /* This horrible hack lets us know how much to unmap when the file is
+     closed.  (We no longer need the magic number, and the mapping
+     is private.)  */
+  arc->ctfa_magic = s.st_size;
+  close (fd);
+  return arc;
+
+err_unmap:
+  munmap (NULL, s.st_size);
+err_close:
+  close (fd);
+err:
+  if (errp)
+    *errp = errno;
+  ctf_dprintf (errmsg, filename, errno < ECTF_BASE ? strerror (errno) :
+	       ctf_errmsg (errno));
+  return NULL;
+}
+
+/* Close an archive.  */
+void
+ctf_arc_close (ctf_archive_t * arc)
+{
+  if (arc == NULL)
+    return;
+
+  /* See the comment in ctf_arc_open().  */
+  munmap (arc, arc->ctfa_magic);
+}
+
+/* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
+   non-NULL.  */
+ctf_file_t *
+ctf_arc_open_by_name (const ctf_archive_t * arc, const char *name, int *errp)
+{
+  struct ctf_archive_modent *modent;
+
+  ctf_dprintf ("ctf_arc_open_by_name(%s): opening\n", name);
+
+  modent = (ctf_archive_modent_t *) ((char *) arc
+				     + sizeof (struct ctf_archive));
+
+  search_nametbl = (char *) arc + le64toh (arc->ctfa_names);
+  modent = bsearch (name, modent, le64toh (arc->ctfa_nfiles),
+		    sizeof (struct ctf_archive_modent),
+		    search_modent_by_name);
+
+  /* This is actually a common case and normal operation: no error
+     debug output.  */
+  if (modent == NULL)
+    {
+      if (errp)
+	*errp = ECTF_ARNNAME;
+      return NULL;
+    }
+
+  return ctf_arc_open_by_offset (arc, le64toh (modent->ctf_offset), errp);
+}
+
+/* Return the ctf_file_t at the given ctfa_ctfs-relative offset, or NULL if
+   none, setting 'err' if non-NULL.  */
+static ctf_file_t *
+ctf_arc_open_by_offset (const ctf_archive_t * arc, size_t offset, int *errp)
+{
+  ctf_sect_t ctfsect;
+  ctf_file_t *fp;
+
+  ctf_dprintf ("ctf_arc_open_by_offset(%zi): opening\n", offset);
+
+  bzero (&ctfsect, sizeof (ctf_sect_t));
+
+  offset += le64toh (arc->ctfa_ctfs);
+
+  ctfsect.cts_name = _CTF_SECTION;
+  ctfsect.cts_type = SHT_PROGBITS;
+  ctfsect.cts_flags = SHF_ALLOC;
+  ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
+  ctfsect.cts_entsize = 1;
+  ctfsect.cts_offset = 0;
+  ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
+  fp = ctf_bufopen (&ctfsect, NULL, NULL, errp);
+  if (fp)
+    ctf_setmodel (fp, le64toh (arc->ctfa_model));
+  return fp;
+}
+
+/* Iterate over all CTF files in an archive.  We pass the raw data for all CTF
+   files in turn to the specified callback function.  */
+int
+ctf_archive_raw_iter (const ctf_archive_t * arc,
+		      ctf_archive_raw_member_f * func, void *data)
+{
+  int rc;
+  size_t i;
+  struct ctf_archive_modent *modent;
+  const char *nametbl;
+
+  modent = (ctf_archive_modent_t *) ((char *) arc
+				     + sizeof (struct ctf_archive));
+  nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
+
+  for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
+    {
+      const char *name;
+      char *fp;
+
+      name = &nametbl[le64toh (modent[i].name_offset)];
+      fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
+	    + le64toh (modent[i].ctf_offset));
+
+      if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
+		      le64toh (*((uint64_t *) fp)), data)) != 0)
+	return rc;
+    }
+  return 0;
+}
+
+/* Iterate over all CTF files in an archive.  We pass all CTF files in turn to
+   the specified callback function.  */
+int
+ctf_archive_iter (const ctf_archive_t * arc, ctf_archive_member_f * func,
+		  void *data)
+{
+  int rc;
+  size_t i;
+  ctf_file_t *f;
+  struct ctf_archive_modent *modent;
+  const char *nametbl;
+
+  modent = (ctf_archive_modent_t *) ((char *) arc
+				     + sizeof (struct ctf_archive));
+  nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
+
+  for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
+    {
+      const char *name;
+
+      name = &nametbl[le64toh (modent[i].name_offset)];
+      if ((f = ctf_arc_open_by_name (arc, name, &rc)) == NULL)
+	return rc;
+
+      if ((rc = func (f, name, data)) != 0)
+	{
+	  ctf_close (f);
+	  return rc;
+	}
+
+      ctf_close (f);
+    }
+  return 0;
+}
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 9f90ff01dd..c2f833c0d1 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -230,6 +230,50 @@ struct ctf_file
   void *ctf_specific;		  /* Data for ctf_get/setspecific().  */
 };
 
+/* The ctf_archive is a collection of ctf_file_t's stored together. The format
+   is suitable for mmap()ing: this control structure merely describes the
+   mmap()ed archive (and overlaps the first few bytes of it), hence the
+   greater care taken with integral types.  All CTF files in an archive
+   must have the same data model.  (This is not validated.)
+
+   All integers in this structure are stored in little-endian byte order.
+
+   The code relies on the fact that everything in this header is a uint64_t
+   and thus the header needs no padding (in particular, that no padding is
+   needed between ctfa_ctfs and the unnamed ctfa_archive_modent array
+   that follows it).  */
+
+#define CTFA_MAGIC 0x8b47f2a4d7623eeb	/* Random.  */
+struct ctf_archive
+{
+  /* Magic number.  (In loaded files, overwritten with the file size
+     so ctf_arc_close() knows how much to munmap()).  */
+  uint64_t ctfa_magic;
+
+  /* CTF data model.  */
+  uint64_t ctfa_model;
+
+  /* Number of CTF files in the archive.  */
+  uint64_t ctfa_nfiles;
+
+  /* Offset of the name table.  */
+  uint64_t ctfa_names;
+
+  /* Offset of the CTF table.  Each element starts with a size (a uint64_t
+     in network byte order) then a ctf_file_t of that size.  */
+  uint64_t ctfa_ctfs;
+};
+
+/* An array of ctfa_nnamed of this structure lies at
+   ctf_archive[ctf_archive->ctfa_modents] and gives the ctfa_ctfs or
+   ctfa_names-relative offsets of each name or ctf_file_t.  */
+
+typedef struct ctf_archive_modent
+{
+  uint64_t name_offset;
+  uint64_t ctf_offset;
+} ctf_archive_modent_t;
+
 /* Return x rounded up to an alignment boundary.
    eg, P2ROUNDUP(0x1234, 0x100) == 0x1300 (0x13*align)
    eg, P2ROUNDUP(0x5600, 0x100) == 0x5600 (0x56*align)  */
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 00/19] libctf, and CTF support for objdump and readelf
@ 2019-04-30 22:57 Nick Alcock
  2019-04-30 22:57 ` [PATCH 02/19] include: new header ctf-api.h Nick Alcock
                   ` (22 more replies)
  0 siblings, 23 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

This submission is the first part of multiple patch series which together add
support for the Compact ANSI-C Type Format to the GNU toolchain.

Compact C Type Format (CTF) is a reduced form of debugging information whose
main purpose is to describe the type of C entities such as structures, unions,
typedefs and function arguments.  CTF format is optimized for compactness: it
was originally designed for use-cases like dynamic tracing and online
in-application debugging, where debugging information is meant to be present
even in stripped binaries.

CTF gains compactness over DWARF in four ways:

  - a more compact encoding, at the cost of irregularity.  Rather than a regular
    scheme of tags and attributes within those tags, the structures are
    customized for each kind of C type described, which allows significant space
    savings.  IDs are omitted and implied wherever possible to save even more
    space (the ID of each type in the type table is implied by its position,
    trading space for the need to scan the table at load time).

  - reuse of strings from the ELF file: CTF files have one string table built
    into the CTF format itself and one "external" table which is usually the
    table in the ELF file.  Further improvements are possible here without
    format changes: we are looking into this.

  - a very compact association between the ELF symbol table and CTF.  No symbol
    table indexes are recorded: all are implied: the data-object section
    is as compact as possible, containing nothing but a stream of type IDs
    describing the type of data symbols in symbol table order.

  - aggressive link-time deduplication will be added in the next patch
    series and will be the default behavior, resulting in further space
    savings.

Types in CTF can be looked up by traversal from other types via a numeric type
ID, by traversal of all types in the file, by ELF symbol table ID or by name
(though not all types need be named). As in C, there are separate namesapces for
top-level types, enums, structs and unions.  There is no analogue of block
scope: types within functions must either be promoted to the top level, stored
in another CTF container (perhaps using CTF's single-level parent/child
relationship), or not represented at all. Since the principal use case of CTF is
to look up types given symbol table entries, and symbol tables are also a single
flat namespace, this is not expected to be a serious limitation.

All types CTF describes have a fixed size at CTF generation time, and there is
nothing like the DWARF exprloc interpreter to compute the size of variably-sized
entities. This is due to the adopted 'top-level model' and, consequently, VLAs
are not supported.

For an overview of the CTF format, see the documentation in the email I'll post
as a followup to this patch series (we have yet to figure out where to put it).

Most of this patch series implements a library that reads and writes this
format, and a header file describing it.  The linker, debugger, and
objdump/objcopy are expected to use the library, while GCC will not.


This first submission consists of the core library in libctf/, and CTF support
in objdump and readelf: this leverages the debugging dump support in libctf, so
the objdump and readelf support is a few dozen lines each on top of that.


This patch series is an RFC. We are still implementing some additional features
in order to capture the full potential of the format.  Enhancements planned
include:

A new section implementing a compact version of DW_AT_call_site et al, allowing
efficient backtracing even when the debuginfo is missing, including recovery of
the value of parameters in at least 99.9% of the cases handled by DWARF 5 in
existing code.

Enhancements to the core data structures (particularly ctf_stype_t and
ctf_member_t) reducing space spent on unused type bits when type IDs are < 2^16.

Nick Alcock (19):
  include: new header ctf.h: file format description
  include: new header ctf-api.h
  libctf: lowest-level memory allocation and debug-dumping wrappers
  libctf: low-level list manipulation and helper utilities
  libctf: error handling
  libctf: hashing
  libctf: implementation definitions related to file creation
  libctf: creation functions
  libctf: opening
  libctf: ELF file opening
  libctf: core type lookup
  libctf: lookups by name and symbol
  libctf: type copying
  libctf: library version enforcement
  libctf: mmappable archives
  libctf: labels
  libctf: debug dumping
  libctf: build system
  binutils: CTF support for objdump and readelf

 Makefile.def                    |    5 +
 Makefile.in                     |  984 ++++-
 binutils/Makefile.am            |   10 +-
 binutils/Makefile.in            |   18 +-
 binutils/aclocal.m4             |   10 +-
 binutils/doc/Makefile.in        |    9 +-
 binutils/doc/binutils.texi      |   12 +
 binutils/doc/ctf.options.texi   |   19 +
 binutils/objdump.c              |  156 +-
 binutils/readelf.c              |  206 +
 configure                       |    2 +-
 configure.ac                    |    2 +-
 include/ctf-api.h               |  354 ++
 include/ctf.h                   |  427 ++
 libctf/Makefile.am              |   31 +
 libctf/Makefile.in              |  767 ++++
 {binutils => libctf}/aclocal.m4 |   99 +-
 libctf/config.h.in              |   98 +
 libctf/configure                | 7120 +++++++++++++++++++++++++++++++
 libctf/configure.ac             |   59 +
 libctf/ctf-archive.c            |  491 +++
 libctf/ctf-create.c             | 1937 +++++++++
 libctf/ctf-decl.c               |  195 +
 libctf/ctf-dump.c               |  595 +++
 libctf/ctf-error.c              |   93 +
 libctf/ctf-hash.c               |  277 ++
 libctf/ctf-impl.h               |  404 ++
 libctf/ctf-labels.c             |  138 +
 libctf/ctf-lib.c                |  506 +++
 libctf/ctf-lookup.c             |  427 ++
 libctf/ctf-open.c               | 1359 ++++++
 libctf/ctf-subr.c               |   74 +
 libctf/ctf-types.c              | 1019 +++++
 libctf/ctf-util.c               |  176 +
 34 files changed, 18008 insertions(+), 71 deletions(-)
 create mode 100644 binutils/doc/ctf.options.texi
 create mode 100644 include/ctf-api.h
 create mode 100644 include/ctf.h
 create mode 100644 libctf/Makefile.am
 create mode 100644 libctf/Makefile.in
 copy {binutils => libctf}/aclocal.m4 (95%)
 create mode 100644 libctf/config.h.in
 create mode 100755 libctf/configure
 create mode 100644 libctf/configure.ac
 create mode 100644 libctf/ctf-archive.c
 create mode 100644 libctf/ctf-create.c
 create mode 100644 libctf/ctf-decl.c
 create mode 100644 libctf/ctf-dump.c
 create mode 100644 libctf/ctf-error.c
 create mode 100644 libctf/ctf-hash.c
 create mode 100644 libctf/ctf-impl.h
 create mode 100644 libctf/ctf-labels.c
 create mode 100644 libctf/ctf-lib.c
 create mode 100644 libctf/ctf-lookup.c
 create mode 100644 libctf/ctf-open.c
 create mode 100644 libctf/ctf-subr.c
 create mode 100644 libctf/ctf-types.c
 create mode 100644 libctf/ctf-util.c

-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 11/19] libctf: core type lookup
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (10 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 08/19] libctf: creation functions Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 04/19] libctf: low-level list manipulation and helper utilities Nick Alcock
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

Finally we get to the functions used to actually look up and enumerate
properties of types in a container (names, sizes, members, what type a
pointer or cv-qual references, determination of whether two types are
assignment-compatible, etc).

With a very few exceptions these do not work for types newly added via
ctf_add_*(): they only work on types in read-only containers, or types
added before the most recent call to ctf_update().

This also adds support for lookup of "variables" (string -> type ID
mappings) and for generation of C type names corresponding to a type ID.

libctf/
	* ctf-decl.c: New file.
	* ctf-types.c: Likewise.
	* ctf-impl.h: New declarations.

include/
	* ctf-api.h (ctf_visit_f): New definition.
	(ctf_member_f): Likewise.
	(ctf_enum_f): Likewise.
	(ctf_variable_f): Likewise.
	(ctf_type_f): Likewise.
	(ctf_type_isparent): Likewise.
	(ctf_type_ischild): Likewise.
	(ctf_type_resolve): Likewise.
	(ctf_type_aname): Likewise.
	(ctf_type_lname): Likewise.
	(ctf_type_name): Likewise.
	(ctf_type_sizee): Likewise.
	(ctf_type_align): Likewise.
	(ctf_type_kind): Likewise.
	(ctf_type_reference): Likewise.
	(ctf_type_pointer): Likewise.
	(ctf_type_encoding): Likewise.
	(ctf_type_visit): Likewise.
	(ctf_type_cmp): Likewise.
	(ctf_type_compat): Likewise.
	(ctf_member_info): Likewise.
	(ctf_array_info): Likewise.
	(ctf_enum_name): Likewise.
	(ctf_enum_value): Likewise.
	(ctf_member_iter): Likewise.
	(ctf_enum_iter): Likewise.
	(ctf_type_iter): Likewise.
	(ctf_variable_iter): Likewise.
---
 include/ctf-api.h  |   37 ++
 libctf/ctf-decl.c  |  195 +++++++++
 libctf/ctf-impl.h  |    8 +
 libctf/ctf-types.c | 1019 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1259 insertions(+)
 create mode 100644 libctf/ctf-decl.c
 create mode 100644 libctf/ctf-types.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index f1a786f451..6e9a0ecf91 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -198,6 +198,16 @@ enum
 #define	CTF_ADD_NONROOT	0	/* Type only visible in nested scope.  */
 #define	CTF_ADD_ROOT	1	/* Type visible at top-level scope.  */
 
+/* These typedefs are used to define the signature for callback functions
+   that can be used with the iteration and visit functions below.  */
+
+typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset,
+			 int depth, void *arg);
+typedef int ctf_member_f (const char *name, ctf_id_t membtype,
+			  unsigned long offset, void *arg);
+typedef int ctf_enum_f (const char *name, int val, void *arg);
+typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg);
+typedef int ctf_type_f (ctf_id_t type, void *arg);
 extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
 				   size_t, const char *, size_t, int *);
 extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
@@ -211,6 +221,8 @@ extern ctf_sect_t ctf_getdatasect (const ctf_file_t *);
 extern ctf_file_t *ctf_parent_file (ctf_file_t *);
 extern const char *ctf_parent_name (ctf_file_t *);
 extern void ctf_parent_name_set (ctf_file_t *, const char *);
+extern int ctf_type_isparent (ctf_file_t *, ctf_id_t);
+extern int ctf_type_ischild (ctf_file_t *, ctf_id_t);
 
 extern int ctf_import (ctf_file_t *, ctf_file_t *);
 extern int ctf_setmodel (ctf_file_t *, int);
@@ -221,6 +233,31 @@ extern void *ctf_getspecific (ctf_file_t *);
 
 extern int ctf_errno (ctf_file_t *);
 extern const char *ctf_errmsg (int);
+extern ctf_id_t ctf_type_resolve (ctf_file_t *, ctf_id_t);
+extern char *ctf_type_aname (ctf_file_t *, ctf_id_t);
+extern ssize_t ctf_type_lname (ctf_file_t *, ctf_id_t, char *, size_t);
+extern char *ctf_type_name (ctf_file_t *, ctf_id_t, char *, size_t);
+extern ssize_t ctf_type_size (ctf_file_t *, ctf_id_t);
+extern ssize_t ctf_type_align (ctf_file_t *, ctf_id_t);
+extern int ctf_type_kind (ctf_file_t *, ctf_id_t);
+extern ctf_id_t ctf_type_reference (ctf_file_t *, ctf_id_t);
+extern ctf_id_t ctf_type_pointer (ctf_file_t *, ctf_id_t);
+extern int ctf_type_encoding (ctf_file_t *, ctf_id_t, ctf_encoding_t *);
+extern int ctf_type_visit (ctf_file_t *, ctf_id_t, ctf_visit_f *, void *);
+extern int ctf_type_cmp (ctf_file_t *, ctf_id_t, ctf_file_t *, ctf_id_t);
+extern int ctf_type_compat (ctf_file_t *, ctf_id_t, ctf_file_t *, ctf_id_t);
+
+extern int ctf_member_info (ctf_file_t *, ctf_id_t, const char *,
+			    ctf_membinfo_t *);
+extern int ctf_array_info (ctf_file_t *, ctf_id_t, ctf_arinfo_t *);
+
+extern const char *ctf_enum_name (ctf_file_t *, ctf_id_t, int);
+extern int ctf_enum_value (ctf_file_t *, ctf_id_t, const char *, int *);
+
+extern int ctf_member_iter (ctf_file_t *, ctf_id_t, ctf_member_f *, void *);
+extern int ctf_enum_iter (ctf_file_t *, ctf_id_t, ctf_enum_f *, void *);
+extern int ctf_type_iter (ctf_file_t *, ctf_type_f *, void *);
+extern int ctf_variable_iter (ctf_file_t *, ctf_variable_f *, void *);
 extern ctf_id_t ctf_add_array (ctf_file_t *, uint32_t,
 			       const ctf_arinfo_t *);
 extern ctf_id_t ctf_add_const (ctf_file_t *, uint32_t, ctf_id_t);
diff --git a/libctf/ctf-decl.c b/libctf/ctf-decl.c
new file mode 100644
index 0000000000..a96562a4d0
--- /dev/null
+++ b/libctf/ctf-decl.c
@@ -0,0 +1,195 @@
+/* C declarator syntax glue.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* CTF Declaration Stack
+
+   In order to implement ctf_type_name(), we must convert a type graph back
+   into a C type declaration.  Unfortunately, a type graph represents a storage
+   class ordering of the type whereas a type declaration must obey the C rules
+   for operator precedence, and the two orderings are frequently in conflict.
+   For example, consider these CTF type graphs and their C declarations:
+
+   CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER  : int (*)()
+   CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER     : int (*)[]
+
+   In each case, parentheses are used to raise operator * to higher lexical
+   precedence, so the string form of the C declaration cannot be constructed by
+   walking the type graph links and forming the string from left to right.
+
+   The functions in this file build a set of stacks from the type graph nodes
+   corresponding to the C operator precedence levels in the appropriate order.
+   The code in ctf_type_name() can then iterate over the levels and nodes in
+   lexical precedence order and construct the final C declaration string.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+void
+ctf_decl_init (ctf_decl_t *cd)
+{
+  int i;
+
+  memset (cd, 0, sizeof (ctf_decl_t));
+
+  for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
+    cd->cd_order[i] = CTF_PREC_BASE - 1;
+
+  cd->cd_qualp = CTF_PREC_BASE;
+  cd->cd_ordp = CTF_PREC_BASE;
+}
+
+void
+ctf_decl_fini (ctf_decl_t *cd)
+{
+  ctf_decl_node_t *cdp, *ndp;
+  int i;
+
+  for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
+    {
+      for (cdp = ctf_list_next (&cd->cd_nodes[i]); cdp != NULL; cdp = ndp)
+	{
+	  ndp = ctf_list_next (cdp);
+	  ctf_free (cdp, sizeof (ctf_decl_node_t));
+	}
+    }
+}
+
+void
+ctf_decl_push (ctf_decl_t *cd, ctf_file_t *fp, ctf_id_t type)
+{
+  ctf_decl_node_t *cdp;
+  ctf_decl_prec_t prec;
+  uint32_t kind, n = 1;
+  int is_qual = 0;
+
+  const ctf_type_t *tp;
+  ctf_arinfo_t ar;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    {
+      cd->cd_err = fp->ctf_errno;
+      return;
+    }
+
+  switch (kind = LCTF_INFO_KIND (fp, tp->ctt_info))
+    {
+    case CTF_K_ARRAY:
+      (void) ctf_array_info (fp, type, &ar);
+      ctf_decl_push (cd, fp, ar.ctr_contents);
+      n = ar.ctr_nelems;
+      prec = CTF_PREC_ARRAY;
+      break;
+
+    case CTF_K_TYPEDEF:
+      if (ctf_strptr (fp, tp->ctt_name)[0] == '\0')
+	{
+	  ctf_decl_push (cd, fp, tp->ctt_type);
+	  return;
+	}
+      prec = CTF_PREC_BASE;
+      break;
+
+    case CTF_K_FUNCTION:
+      ctf_decl_push (cd, fp, tp->ctt_type);
+      prec = CTF_PREC_FUNCTION;
+      break;
+
+    case CTF_K_POINTER:
+      ctf_decl_push (cd, fp, tp->ctt_type);
+      prec = CTF_PREC_POINTER;
+      break;
+
+    case CTF_K_SLICE:
+      ctf_decl_push (cd, fp, ctf_type_reference (fp, type));
+      prec = CTF_PREC_BASE;
+      break;
+
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+      ctf_decl_push (cd, fp, tp->ctt_type);
+      prec = cd->cd_qualp;
+      is_qual++;
+      break;
+
+    default:
+      prec = CTF_PREC_BASE;
+    }
+
+  if ((cdp = ctf_alloc (sizeof (ctf_decl_node_t))) == NULL)
+    {
+      cd->cd_err = EAGAIN;
+      return;
+    }
+
+  cdp->cd_type = type;
+  cdp->cd_kind = kind;
+  cdp->cd_n = n;
+
+  if (ctf_list_next (&cd->cd_nodes[prec]) == NULL)
+    cd->cd_order[prec] = cd->cd_ordp++;
+
+  /* Reset cd_qualp to the highest precedence level that we've seen so
+     far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).  */
+
+  if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
+    cd->cd_qualp = prec;
+
+  /* C array declarators are ordered inside out so prepend them.  Also by
+     convention qualifiers of base types precede the type specifier (e.g.
+     const int vs. int const) even though the two forms are equivalent.  */
+
+  if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
+    ctf_list_prepend (&cd->cd_nodes[prec], cdp);
+  else
+    ctf_list_append (&cd->cd_nodes[prec], cdp);
+}
+
+_libctf_printflike_ (2, 3)
+void ctf_decl_sprintf (ctf_decl_t *cd, const char *format, ...)
+{
+  va_list ap;
+  char *str;
+  int n;
+
+  if (cd->cd_enomem)
+    return;
+
+  va_start (ap, format);
+  n = vasprintf (&str, format, ap);
+  va_end (ap);
+
+  if (n > 0)
+      cd->cd_buf = ctf_str_append (cd->cd_buf, str);
+
+  /* Sticky error condition.  */
+  if (n < 0)
+    {
+      free (cd->cd_buf);
+      cd->cd_buf = NULL;
+      cd->cd_enomem = 1;
+    }
+
+  free (str);
+}
+
+char *ctf_decl_buf (ctf_decl_t *cd)
+{
+  return cd->cd_buf;
+}
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 2f8caed228..9f90ff01dd 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -308,6 +308,14 @@ extern void ctf_dvd_insert (ctf_file_t *, ctf_dvdef_t *);
 extern void ctf_dvd_delete (ctf_file_t *, ctf_dvdef_t *);
 extern ctf_dvdef_t *ctf_dvd_lookup (const ctf_file_t *, const char *);
 
+extern void ctf_decl_init (ctf_decl_t *);
+extern void ctf_decl_fini (ctf_decl_t *);
+extern void ctf_decl_push (ctf_decl_t *, ctf_file_t *, ctf_id_t);
+
+_libctf_printflike_ (2, 3)
+extern void ctf_decl_sprintf (ctf_decl_t *, const char *, ...);
+extern char *ctf_decl_buf (ctf_decl_t *cd);
+
 extern const char *ctf_strraw (ctf_file_t *, uint32_t);
 extern const char *ctf_strptr (ctf_file_t *, uint32_t);
 
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
new file mode 100644
index 0000000000..a28b3d0bc3
--- /dev/null
+++ b/libctf/ctf-types.c
@@ -0,0 +1,1019 @@
+/* Type handling functions.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+/* Determine whether a type is a parent or a child.  */
+
+int
+ctf_type_isparent (ctf_file_t *fp, ctf_id_t id)
+{
+  return (LCTF_TYPE_ISPARENT (fp, id));
+}
+
+int
+ctf_type_ischild (ctf_file_t * fp, ctf_id_t id)
+{
+  return (LCTF_TYPE_ISCHILD (fp, id));
+}
+
+/* Iterate over the members of a STRUCT or UNION.  We pass the name, member
+   type, and offset of each member to the specified callback function.  */
+
+int
+ctf_member_iter (ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  ssize_t size, increment;
+  uint32_t kind, n;
+  int rc;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+  kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+
+  if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+
+  if (size < CTF_LSTRUCT_THRESH)
+    {
+      const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
+						       increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
+	{
+	  const char *name = ctf_strptr (fp, mp->ctm_name);
+	  if ((rc = func (name, mp->ctm_type, mp->ctm_offset, arg)) != 0)
+	    return rc;
+	}
+
+    }
+  else
+    {
+      const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
+							  increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
+	{
+	  const char *name = ctf_strptr (fp, lmp->ctlm_name);
+	  if ((rc = func (name, lmp->ctlm_type,
+			  (unsigned long) CTF_LMEM_OFFSET (lmp), arg)) != 0)
+	    return rc;
+	}
+    }
+
+  return 0;
+}
+
+/* Iterate over the members of an ENUM.  We pass the string name and associated
+   integer value of each enum element to the specified callback function.  */
+
+int
+ctf_enum_iter (ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  const ctf_enum_t *ep;
+  ssize_t increment;
+  uint32_t n;
+  int rc;
+
+  if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+    return (ctf_set_errno (ofp, ECTF_NOTENUM));
+
+  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+
+  ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
+
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      const char *name = ctf_strptr (fp, ep->cte_name);
+      if ((rc = func (name, ep->cte_value, arg)) != 0)
+	return rc;
+    }
+
+  return 0;
+}
+
+/* Iterate over every root (user-visible) type in the given CTF container.
+   We pass the type ID of each type to the specified callback function.  */
+
+int
+ctf_type_iter (ctf_file_t *fp, ctf_type_f *func, void *arg)
+{
+  ctf_id_t id, max = fp->ctf_typemax;
+  int rc, child = (fp->ctf_flags & LCTF_CHILD);
+
+  for (id = 1; id <= max; id++)
+    {
+      const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, id);
+      if (LCTF_INFO_ISROOT (fp, tp->ctt_info)
+	  && (rc = func (LCTF_INDEX_TO_TYPE (fp, id, child), arg)) != 0)
+	return rc;
+    }
+
+  return 0;
+}
+
+/* Iterate over every variable in the given CTF container, in arbitrary order.
+   We pass the name of each variable to the specified callback function.  */
+
+int
+ctf_variable_iter (ctf_file_t *fp, ctf_variable_f *func, void *arg)
+{
+  unsigned long i;
+  int rc;
+
+  if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
+    return ECTF_NOPARENT;
+
+  for (i = 0; i < fp->ctf_nvars; i++)
+    if ((rc = func (ctf_strptr (fp, fp->ctf_vars[i].ctv_name),
+		    fp->ctf_vars[i].ctv_type, arg)) != 0)
+      return rc;
+
+  return 0;
+}
+
+/* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
+   RESTRICT nodes until we reach a "base" type node.  This is useful when
+   we want to follow a type ID to a node that has members or a size.  To guard
+   against infinite loops, we implement simplified cycle detection and check
+   each link against itself, the previous node, and the topmost node.
+
+   Does not drill down through slices to their contained type.  */
+
+ctf_id_t
+ctf_type_resolve (ctf_file_t *fp, ctf_id_t type)
+{
+  ctf_id_t prev = type, otype = type;
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+
+  while ((tp = ctf_lookup_by_id (&fp, type)) != NULL)
+    {
+      switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+	{
+	case CTF_K_TYPEDEF:
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+	  if (tp->ctt_type == type || tp->ctt_type == otype
+	      || tp->ctt_type == prev)
+	    {
+	      ctf_dprintf ("type %ld cycle detected\n", otype);
+	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
+	    }
+	  prev = type;
+	  type = tp->ctt_type;
+	  break;
+	default:
+	  return type;
+	}
+    }
+
+  return CTF_ERR;		/* errno is set for us.  */
+}
+
+/* Like ctf_type_resolve(), but traverse down through slices to their contained
+   type.  */
+
+ctf_id_t
+ctf_type_resolve_unsliced (ctf_file_t *fp, ctf_id_t type)
+{
+  const ctf_type_t *tp;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return -1;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((LCTF_INFO_KIND (fp, tp->ctt_info)) == CTF_K_SLICE)
+    return ctf_type_reference (fp, type);
+  return type;
+}
+
+/* Lookup the given type ID and return its name as a new dynamcally-allocated
+   string.  */
+
+char *
+ctf_type_aname (ctf_file_t *fp, ctf_id_t type)
+{
+  ctf_decl_t cd;
+  ctf_decl_node_t *cdp;
+  ctf_decl_prec_t prec, lp, rp;
+  int ptr, arr;
+  uint32_t k;
+  char *buf;
+
+  if (fp == NULL && type == CTF_ERR)
+    return NULL;	/* Simplify caller code by permitting CTF_ERR.  */
+
+  ctf_decl_init (&cd);
+  ctf_decl_push (&cd, fp, type);
+
+  if (cd.cd_err != 0)
+    {
+      ctf_decl_fini (&cd);
+      ctf_set_errno (fp, cd.cd_err);
+      return NULL;
+    }
+
+  /* If the type graph's order conflicts with lexical precedence order
+     for pointers or arrays, then we need to surround the declarations at
+     the corresponding lexical precedence with parentheses.  This can
+     result in either a parenthesized pointer (*) as in int (*)() or
+     int (*)[], or in a parenthesized pointer and array as in int (*[])().  */
+
+  ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
+  arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
+
+  rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
+  lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
+
+  k = CTF_K_POINTER;		/* Avoid leading whitespace (see below).  */
+
+  for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++)
+    {
+      for (cdp = ctf_list_next (&cd.cd_nodes[prec]);
+	   cdp != NULL; cdp = ctf_list_next (cdp))
+	{
+	  ctf_file_t *rfp = fp;
+	  const ctf_type_t *tp = ctf_lookup_by_id (&rfp, cdp->cd_type);
+	  const char *name = ctf_strptr (rfp, tp->ctt_name);
+
+	  if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
+	    ctf_decl_sprintf (&cd, " ");
+
+	  if (lp == prec)
+	    {
+	      ctf_decl_sprintf (&cd, "(");
+	      lp = -1;
+	    }
+
+	  switch (cdp->cd_kind)
+	    {
+	    case CTF_K_INTEGER:
+	    case CTF_K_FLOAT:
+	    case CTF_K_TYPEDEF:
+	      ctf_decl_sprintf (&cd, "%s", name);
+	      break;
+	    case CTF_K_POINTER:
+	      ctf_decl_sprintf (&cd, "*");
+	      break;
+	    case CTF_K_ARRAY:
+	      ctf_decl_sprintf (&cd, "[%u]", cdp->cd_n);
+	      break;
+	    case CTF_K_FUNCTION:
+	      ctf_decl_sprintf (&cd, "()");
+	      break;
+	    case CTF_K_STRUCT:
+	    case CTF_K_FORWARD:
+	      ctf_decl_sprintf (&cd, "struct %s", name);
+	      break;
+	    case CTF_K_UNION:
+	      ctf_decl_sprintf (&cd, "union %s", name);
+	      break;
+	    case CTF_K_ENUM:
+	      ctf_decl_sprintf (&cd, "enum %s", name);
+	      break;
+	    case CTF_K_VOLATILE:
+	      ctf_decl_sprintf (&cd, "volatile");
+	      break;
+	    case CTF_K_CONST:
+	      ctf_decl_sprintf (&cd, "const");
+	      break;
+	    case CTF_K_RESTRICT:
+	      ctf_decl_sprintf (&cd, "restrict");
+	      break;
+	    case CTF_K_SLICE:
+	      /* No representation: just changes encoding of contained type,
+		 which is not in any case printed.  Skip it.  */
+	      break;
+	    }
+
+	  k = cdp->cd_kind;
+	}
+
+      if (rp == prec)
+	ctf_decl_sprintf (&cd, ")");
+    }
+
+  if (cd.cd_enomem)
+    (void) ctf_set_errno (fp, ENOMEM);
+
+  buf = ctf_decl_buf (&cd);
+
+  ctf_decl_fini (&cd);
+  return buf;
+}
+
+/* Lookup the given type ID and print a string name for it into buf.  Return
+   the actual number of bytes (not including \0) needed to format the name.  */
+
+ssize_t
+ctf_type_lname (ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+{
+  char *str = ctf_type_aname (fp, type);
+  size_t slen = strlen (str);
+
+  if (str == NULL)
+    return CTF_ERR;             /* errno is set for us */
+
+  snprintf (buf, len, "%s", str);
+  free (str);
+
+  if (slen >= len)
+    (void) ctf_set_errno (fp, ECTF_NAMELEN);
+
+  return slen;
+}
+
+/* Lookup the given type ID and print a string name for it into buf.  If buf
+   is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.  */
+
+char *
+ctf_type_name (ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+{
+  ssize_t rv = ctf_type_lname (fp, type, buf, len);
+  return (rv >= 0 && (size_t) rv < len ? buf : NULL);
+}
+
+/* Resolve the type down to a base type node, and then return the size
+   of the type storage in bytes.  */
+
+ssize_t
+ctf_type_size (ctf_file_t *fp, ctf_id_t type)
+{
+  const ctf_type_t *tp;
+  ssize_t size;
+  ctf_arinfo_t ar;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return -1;			/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return -1;			/* errno is set for us.  */
+
+  switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+    {
+    case CTF_K_POINTER:
+      return fp->ctf_dmodel->ctd_pointer;
+
+    case CTF_K_FUNCTION:
+      return 0;		/* Function size is only known by symtab.  */
+
+    case CTF_K_ENUM:
+      return fp->ctf_dmodel->ctd_int;
+
+    case CTF_K_ARRAY:
+      /* ctf_add_array() does not directly encode the element size, but
+	 requires the user to multiply to determine the element size.
+
+	 If ctf_get_ctt_size() returns nonzero, then use the recorded
+	 size instead.  */
+
+      if ((size = ctf_get_ctt_size (fp, tp, NULL, NULL)) > 0)
+	return size;
+
+      if (ctf_array_info (fp, type, &ar) == CTF_ERR
+	  || (size = ctf_type_size (fp, ar.ctr_contents)) == CTF_ERR)
+	return -1;		/* errno is set for us.  */
+
+      return size * ar.ctr_nelems;
+
+    default: /* including slices of enums, etc */
+      return (ctf_get_ctt_size (fp, tp, NULL, NULL));
+    }
+}
+
+/* Resolve the type down to a base type node, and then return the alignment
+   needed for the type storage in bytes.
+
+   XXX may need arch-dependent attention.  */
+
+ssize_t
+ctf_type_align (ctf_file_t *fp, ctf_id_t type)
+{
+  const ctf_type_t *tp;
+  ctf_file_t *ofp = fp;
+  int kind;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return -1;			/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return -1;			/* errno is set for us.  */
+
+  kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+  switch (kind)
+    {
+    case CTF_K_POINTER:
+    case CTF_K_FUNCTION:
+      return fp->ctf_dmodel->ctd_pointer;
+
+    case CTF_K_ARRAY:
+      {
+	ctf_arinfo_t r;
+	if (ctf_array_info (fp, type, &r) == CTF_ERR)
+	  return -1;		/* errno is set for us.  */
+	return (ctf_type_align (fp, r.ctr_contents));
+      }
+
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      {
+	size_t align = 0;
+	ctf_dtdef_t *dtd;
+
+	if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
+	  {
+	    uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+	    ssize_t size, increment;
+	    const void *vmp;
+
+	    (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+	    vmp = (unsigned char *) tp + increment;
+
+	    if (kind == CTF_K_STRUCT)
+	      n = MIN (n, 1);	/* Only use first member for structs.  */
+
+	    if (size < CTF_LSTRUCT_THRESH)
+	      {
+		const ctf_member_t *mp = vmp;
+		for (; n != 0; n--, mp++)
+		  {
+		    ssize_t am = ctf_type_align (fp, mp->ctm_type);
+		    align = MAX (align, am);
+		  }
+	      }
+	    else
+	      {
+		const ctf_lmember_t *lmp = vmp;
+		for (; n != 0; n--, lmp++)
+		  {
+		    ssize_t am = ctf_type_align (fp, lmp->ctlm_type);
+		    align = MAX (align, am);
+		  }
+	      }
+	  }
+	else
+	  {
+	      ctf_dmdef_t *dmd;
+
+	      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+		   dmd != NULL; dmd = ctf_list_next (dmd))
+		{
+		  ssize_t am = ctf_type_align (fp, dmd->dmd_type);
+		  align = MAX (align, am);
+		  if (kind == CTF_K_STRUCT)
+		    break;
+		}
+	  }
+
+	return align;
+      }
+
+    case CTF_K_ENUM:
+      return fp->ctf_dmodel->ctd_int;
+
+    default:  /* including slices of enums, etc */
+      return (ctf_get_ctt_size (fp, tp, NULL, NULL));
+    }
+}
+
+/* Return the kind (CTF_K_* constant) for the specified type ID.  */
+
+int
+ctf_type_kind_unsliced (ctf_file_t *fp, ctf_id_t type)
+{
+  const ctf_type_t *tp;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  return (LCTF_INFO_KIND (fp, tp->ctt_info));
+}
+
+/* Return the kind (CTF_K_* constant) for the specified type ID.
+   Slices are considered to be of the same kind as the type sliced.  */
+
+int
+ctf_type_kind (ctf_file_t *fp, ctf_id_t type)
+{
+  int kind;
+
+  if ((kind = ctf_type_kind_unsliced (fp, type)) == CTF_ERR)
+    return CTF_ERR;
+
+  if (kind == CTF_K_SLICE)
+    {
+      if ((type = ctf_type_reference (fp, type)) == CTF_ERR)
+	return CTF_ERR;
+      kind = ctf_type_kind_unsliced (fp, type);
+    }
+
+  return kind;
+}
+
+/* If the type is one that directly references another type (such as POINTER),
+   then return the ID of the type to which it refers.  */
+
+ctf_id_t
+ctf_type_reference (ctf_file_t *fp, ctf_id_t type)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+    {
+    case CTF_K_POINTER:
+    case CTF_K_TYPEDEF:
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+      return tp->ctt_type;
+      /* Slices store their type in an unusual place.  */
+    case CTF_K_SLICE:
+      {
+	const ctf_slice_t *sp;
+	ssize_t increment;
+	(void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+	sp = (const ctf_slice_t *) ((uintptr_t) tp + increment);
+	return sp->cts_type;
+      }
+    default:
+      return (ctf_set_errno (ofp, ECTF_NOTREF));
+    }
+}
+
+/* Find a pointer to type by looking in fp->ctf_ptrtab.  If we can't find a
+   pointer to the given type, see if we can compute a pointer to the type
+   resulting from resolving the type down to its base type and use that
+   instead.  This helps with cases where the CTF data includes "struct foo *"
+   but not "foo_t *" and the user accesses "foo_t *" in the debugger.
+
+   XXX what about parent containers?  */
+
+ctf_id_t
+ctf_type_pointer (ctf_file_t *fp, ctf_id_t type)
+{
+  ctf_file_t *ofp = fp;
+  ctf_id_t ntype;
+
+  if (ctf_lookup_by_id (&fp, type) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
+    return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+
+  if (ctf_lookup_by_id (&fp, type) == NULL)
+    return (ctf_set_errno (ofp, ECTF_NOTYPE));
+
+  if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0)
+    return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)));
+
+  return (ctf_set_errno (ofp, ECTF_NOTYPE));
+}
+
+/* Return the encoding for the specified INTEGER or FLOAT.  */
+
+int
+ctf_type_encoding (ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
+{
+  ctf_file_t *ofp = fp;
+  ctf_dtdef_t *dtd;
+  const ctf_type_t *tp;
+  ssize_t increment;
+  uint32_t data;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+    {
+      *ep = dtd->dtd_u.dtu_enc;
+      return 0;
+    }
+
+  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+
+  switch (LCTF_INFO_KIND (fp, tp->ctt_info))
+    {
+    case CTF_K_INTEGER:
+      data = *(const uint32_t *) ((uintptr_t) tp + increment);
+      ep->cte_format = CTF_INT_ENCODING (data);
+      ep->cte_offset = CTF_INT_OFFSET (data);
+      ep->cte_bits = CTF_INT_BITS (data);
+      break;
+    case CTF_K_FLOAT:
+      data = *(const uint32_t *) ((uintptr_t) tp + increment);
+      ep->cte_format = CTF_FP_ENCODING (data);
+      ep->cte_offset = CTF_FP_OFFSET (data);
+      ep->cte_bits = CTF_FP_BITS (data);
+      break;
+    case CTF_K_SLICE:
+      {
+	const ctf_slice_t *slice;
+	ctf_encoding_t underlying_en;
+
+	slice = (ctf_slice_t *) ((uintptr_t) tp + increment);
+	data = ctf_type_encoding (fp, slice->cts_type, &underlying_en);
+
+	ep->cte_format = underlying_en.cte_format;
+	ep->cte_offset = slice->cts_offset;
+	ep->cte_bits = slice->cts_bits;
+	break;
+      }
+    default:
+      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+    }
+
+  return 0;
+}
+
+int
+ctf_type_cmp (ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp,
+	      ctf_id_t rtype)
+{
+  int rval;
+
+  if (ltype < rtype)
+    rval = -1;
+  else if (ltype > rtype)
+    rval = 1;
+  else
+    rval = 0;
+
+  if (lfp == rfp)
+    return rval;
+
+  if (LCTF_TYPE_ISPARENT (lfp, ltype) && lfp->ctf_parent != NULL)
+    lfp = lfp->ctf_parent;
+
+  if (LCTF_TYPE_ISPARENT (rfp, rtype) && rfp->ctf_parent != NULL)
+    rfp = rfp->ctf_parent;
+
+  if (lfp < rfp)
+    return -1;
+
+  if (lfp > rfp)
+    return 1;
+
+  return rval;
+}
+
+/* Return a boolean value indicating if two types are compatible.  This function
+   returns true if the two types are the same, or if they (or their ultimate
+   base type) have the same encoding properties, or (for structs / unions /
+   enums / forward declarations) if they have the same name and (for structs /
+   unions) member count.  */
+
+int
+ctf_type_compat (ctf_file_t *lfp, ctf_id_t ltype,
+		 ctf_file_t *rfp, ctf_id_t rtype)
+{
+  const ctf_type_t *ltp, *rtp;
+  ctf_encoding_t le, re;
+  ctf_arinfo_t la, ra;
+  uint32_t lkind, rkind;
+  int same_names = 0;
+
+  if (ctf_type_cmp (lfp, ltype, rfp, rtype) == 0)
+    return 1;
+
+  ltype = ctf_type_resolve (lfp, ltype);
+  lkind = ctf_type_kind (lfp, ltype);
+
+  rtype = ctf_type_resolve (rfp, rtype);
+  rkind = ctf_type_kind (rfp, rtype);
+
+  ltp = ctf_lookup_by_id (&lfp, ltype);
+  rtp = ctf_lookup_by_id (&rfp, rtype);
+
+  if (ltp != NULL && rtp != NULL)
+    same_names = (strcmp (ctf_strptr (lfp, ltp->ctt_name),
+			  ctf_strptr (rfp, rtp->ctt_name)) == 0);
+
+  if (lkind != rkind)
+    return 0;
+
+  switch (lkind)
+    {
+    case CTF_K_INTEGER:
+    case CTF_K_FLOAT:
+      memset (&le, 0, sizeof (le));
+      memset (&re, 0, sizeof (re));
+      return (ctf_type_encoding (lfp, ltype, &le) == 0
+	      && ctf_type_encoding (rfp, rtype, &re) == 0
+	      && memcmp (&le, &re, sizeof (ctf_encoding_t)) == 0);
+    case CTF_K_POINTER:
+      return (ctf_type_compat (lfp, ctf_type_reference (lfp, ltype),
+			       rfp, ctf_type_reference (rfp, rtype)));
+    case CTF_K_ARRAY:
+      return (ctf_array_info (lfp, ltype, &la) == 0
+	      && ctf_array_info (rfp, rtype, &ra) == 0
+	      && la.ctr_nelems == ra.ctr_nelems
+	      && ctf_type_compat (lfp, la.ctr_contents, rfp, ra.ctr_contents)
+	      && ctf_type_compat (lfp, la.ctr_index, rfp, ra.ctr_index));
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      return (same_names && (ctf_type_size (lfp, ltype)
+			     == ctf_type_size (rfp, rtype)));
+    case CTF_K_ENUM:
+      {
+	int lencoded, rencoded;
+	lencoded = ctf_type_encoding (lfp, ltype, &le);
+	rencoded = ctf_type_encoding (rfp, rtype, &re);
+
+	if ((lencoded != rencoded) ||
+	    ((lencoded == 0) && memcmp (&le, &re, sizeof (ctf_encoding_t)) != 0))
+	  return 0;
+      }
+      /* FALLTHRU */
+    case CTF_K_FORWARD:
+      return same_names;   /* No other checks required for these type kinds.  */
+    default:
+      return 0;		      /* Should not get here since we did a resolve.  */
+    }
+}
+
+/* Return the type and offset for a given member of a STRUCT or UNION.  */
+
+int
+ctf_member_info (ctf_file_t *fp, ctf_id_t type, const char *name,
+		 ctf_membinfo_t *mip)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  ssize_t size, increment;
+  uint32_t kind, n;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+  kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+
+  if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+
+  if (size < CTF_LSTRUCT_THRESH)
+    {
+      const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
+						       increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
+	{
+	  if (strcmp (ctf_strptr (fp, mp->ctm_name), name) == 0)
+	    {
+	      mip->ctm_type = mp->ctm_type;
+	      mip->ctm_offset = mp->ctm_offset;
+	      return 0;
+	    }
+	}
+    }
+  else
+    {
+      const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
+							  increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
+	{
+	  if (strcmp (ctf_strptr (fp, lmp->ctlm_name), name) == 0)
+	    {
+	      mip->ctm_type = lmp->ctlm_type;
+	      mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
+	      return 0;
+	    }
+	}
+    }
+
+  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+}
+
+/* Return the array type, index, and size information for the specified ARRAY.  */
+
+int
+ctf_array_info (ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  const ctf_array_t *ap;
+  const ctf_dtdef_t *dtd;
+  ssize_t increment;
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
+    return (ctf_set_errno (ofp, ECTF_NOTARRAY));
+
+  if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+    {
+      *arp = dtd->dtd_u.dtu_arr;
+      return 0;
+    }
+
+  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+
+  ap = (const ctf_array_t *) ((uintptr_t) tp + increment);
+  arp->ctr_contents = ap->cta_contents;
+  arp->ctr_index = ap->cta_index;
+  arp->ctr_nelems = ap->cta_nelems;
+
+  return 0;
+}
+
+/* Convert the specified value to the corresponding enum tag name, if a
+   matching name can be found.  Otherwise NULL is returned.  */
+
+const char *
+ctf_enum_name (ctf_file_t *fp, ctf_id_t type, int value)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  const ctf_enum_t *ep;
+  ssize_t increment;
+  uint32_t n;
+
+  if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
+    return NULL;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return NULL;		/* errno is set for us.  */
+
+  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+    {
+      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      return NULL;
+    }
+
+  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+
+  ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
+
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (ep->cte_value == value)
+	return (ctf_strptr (fp, ep->cte_name));
+    }
+
+  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  return NULL;
+}
+
+/* Convert the specified enum tag name to the corresponding value, if a
+   matching name can be found.  Otherwise CTF_ERR is returned.  */
+
+int
+ctf_enum_value (ctf_file_t * fp, ctf_id_t type, const char *name, int *valp)
+{
+  ctf_file_t *ofp = fp;
+  const ctf_type_t *tp;
+  const ctf_enum_t *ep;
+  ssize_t increment;
+  uint32_t n;
+
+  if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+    {
+      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      return CTF_ERR;
+    }
+
+  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+
+  ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
+
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+	{
+	  if (valp != NULL)
+	    *valp = ep->cte_value;
+	  return 0;
+	}
+    }
+
+  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  return CTF_ERR;
+}
+
+/* Recursively visit the members of any type.  This function is used as the
+   engine for ctf_type_visit, below.  We resolve the input type, recursively
+   invoke ourself for each type member if the type is a struct or union, and
+   then invoke the callback function on the current type.  If any callback
+   returns non-zero, we abort and percolate the error code back up to the top.  */
+
+static int
+ctf_type_rvisit (ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func,
+		 void *arg, const char *name, unsigned long offset, int depth)
+{
+  ctf_id_t otype = type;
+  const ctf_type_t *tp;
+  ssize_t size, increment;
+  uint32_t kind, n;
+  int rc;
+
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((rc = func (name, otype, offset, depth, arg)) != 0)
+    return rc;
+
+  kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+
+  if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+    return 0;
+
+  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+
+  if (size < CTF_LSTRUCT_THRESH)
+    {
+      const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
+						       increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
+	{
+	  if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
+				     func, arg, ctf_strptr (fp, mp->ctm_name),
+				     offset + mp->ctm_offset,
+				     depth + 1)) != 0)
+	    return rc;
+	}
+
+    }
+  else
+    {
+      const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
+							  increment);
+
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
+	{
+	  if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
+				     func, arg, ctf_strptr (fp,
+							    lmp->ctlm_name),
+				     offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
+				     depth + 1)) != 0)
+	    return rc;
+	}
+    }
+
+  return 0;
+}
+
+/* Recursively visit the members of any type.  We pass the name, member
+ type, and offset of each member to the specified callback function.  */
+int
+ctf_type_visit (ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg)
+{
+  return (ctf_type_rvisit (fp, type, func, arg, "", 0, 0));
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 12/19] libctf: lookups by name and symbol
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (13 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 14/19] libctf: library version enforcement Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers Nick Alcock
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

These functions allow you to look up types given a name in a simple
subset of C declarator syntax (no function pointers), to look up the
types of variables given a name, and to look up the types of data
objects and the type signatures of functions given symbol table offsets.

(Despite its name, one function in this commit, ctf_lookup_symbol_name(),
is for the internal use of libctf only, and does not appear in any
public header files.)

libctf/
	* ctf-lookup.c (isqualifier): New.
	(ctf_lookup_by_name): Likewise.
	(struct ctf_lookup_var_key): Likewise.
	(ctf_lookup_var): Likewise.
	(ctf_lookup_variable): Likewise.
	(ctf_lookup_symbol_name): Likewise.
	(ctf_lookup_by_symbol): Likewise.
	(ctf_func_info): Likewise.
	(ctf_func_args): Likewise.

include/
	* ctf-api.h (ctf_func_info): New.
	(ctf_func_args): Likewise.
	(ctf_lookup_by_symbol): Likewise.
	(ctf_lookup_by_symbol): Likewise.
	(ctf_lookup_variable): Likewise.
---
 include/ctf-api.h   |   8 +
 libctf/ctf-lookup.c | 364 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 372 insertions(+)

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 6e9a0ecf91..0adecfee7e 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -233,6 +233,14 @@ extern void *ctf_getspecific (ctf_file_t *);
 
 extern int ctf_errno (ctf_file_t *);
 extern const char *ctf_errmsg (int);
+
+extern int ctf_func_info (ctf_file_t *, unsigned long, ctf_funcinfo_t *);
+extern int ctf_func_args (ctf_file_t *, unsigned long, uint32_t, ctf_id_t *);
+
+extern ctf_id_t ctf_lookup_by_name (ctf_file_t *, const char *);
+extern ctf_id_t ctf_lookup_by_symbol (ctf_file_t *, unsigned long);
+extern ctf_id_t ctf_lookup_variable (ctf_file_t *, const char *);
+
 extern ctf_id_t ctf_type_resolve (ctf_file_t *, ctf_id_t);
 extern char *ctf_type_aname (ctf_file_t *, ctf_id_t);
 extern ssize_t ctf_type_lname (ctf_file_t *, ctf_id_t, char *, size_t);
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 042d632ff2..bd4b79c3b5 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -21,6 +21,290 @@
 #include <gelf.h>
 #include <string.h>
 
+/* Compare the given input string and length against a table of known C storage
+   qualifier keywords.  We just ignore these in ctf_lookup_by_name, below.  To
+   do this quickly, we use a pre-computed Perfect Hash Function similar to the
+   technique originally described in the classic paper:
+
+   R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple",
+   Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19.
+
+   For an input string S of length N, we use hash H = S[N - 1] + N - 105, which
+   for the current set of qualifiers yields a unique H in the range [0 .. 20].
+   The hash can be modified when the keyword set changes as necessary.  We also
+   store the length of each keyword and check it prior to the final strcmp().
+
+   TODO: just use gperf.  */
+
+static int
+isqualifier (const char *s, size_t len)
+{
+  static const struct qual
+  {
+    const char *q_name;
+    size_t q_len;
+  } qhash[] = {
+    {"static", 6}, {"", 0}, {"", 0}, {"", 0},
+    {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0},
+    {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0},
+    {"", 0}, {"", 0}, {"const", 5}, {"register", 8},
+    {"", 0}, {"restrict", 8}, {"_Restrict", 9}
+  };
+
+  int h = s[len - 1] + (int) len - 105;
+  const struct qual *qp = &qhash[h];
+
+  return (h >= 0 && (size_t) h < sizeof (qhash) / sizeof (qhash[0])
+	  && (size_t) len == qp->q_len &&
+	  strncmp (qp->q_name, s, qp->q_len) == 0);
+}
+
+/* Attempt to convert the given C type name into the corresponding CTF type ID.
+   It is not possible to do complete and proper conversion of type names
+   without implementing a more full-fledged parser, which is necessary to
+   handle things like types that are function pointers to functions that
+   have arguments that are function pointers, and fun stuff like that.
+   Instead, this function implements a very simple conversion algorithm that
+   finds the things that we actually care about: structs, unions, enums,
+   integers, floats, typedefs, and pointers to any of these named types.  */
+
+ctf_id_t
+ctf_lookup_by_name (ctf_file_t *fp, const char *name)
+{
+  static const char delimiters[] = " \t\n\r\v\f*";
+
+  const ctf_lookup_t *lp;
+  const char *p, *q, *end;
+  ctf_id_t type = 0;
+  ctf_id_t ntype, ptype;
+
+  if (name == NULL)
+    return (ctf_set_errno (fp, EINVAL));
+
+  for (p = name, end = name + strlen (name); *p != '\0'; p = q)
+    {
+      while (isspace (*p))
+	p++;			/* Skip leading whitespace.  */
+
+      if (p == end)
+	break;
+
+      if ((q = strpbrk (p + 1, delimiters)) == NULL)
+	q = end;		/* Compare until end.  */
+
+      if (*p == '*')
+	{
+	  /* Find a pointer to type by looking in fp->ctf_ptrtab.
+	     If we can't find a pointer to the given type, see if
+	     we can compute a pointer to the type resulting from
+	     resolving the type down to its base type and use
+	     that instead.  This helps with cases where the CTF
+	     data includes "struct foo *" but not "foo_t *" and
+	     the user tries to access "foo_t *" in the debugger.
+
+	     TODO need to handle parent containers too.  */
+
+	  ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)];
+	  if (ntype == 0)
+	    {
+	      ntype = ctf_type_resolve_unsliced (fp, type);
+	      if (ntype == CTF_ERR
+		  || (ntype =
+		      fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, ntype)]) == 0)
+		{
+		  (void) ctf_set_errno (fp, ECTF_NOTYPE);
+		  goto err;
+		}
+	    }
+
+	  type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD));
+
+	  q = p + 1;
+	  continue;
+	}
+
+      if (isqualifier (p, (size_t) (q - p)))
+	continue;		/* Skip qualifier keyword.  */
+
+      for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++)
+	{
+	  /* TODO: This is not MT-safe.  */
+	  if ((lp->ctl_prefix[0] == '\0' ||
+	       strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) &&
+	      (size_t) (q - p) >= lp->ctl_len)
+	    {
+	      for (p += lp->ctl_len; isspace (*p); p++)
+		continue;	/* Skip prefix and next whitespace.  */
+
+	      if ((q = strchr (p, '*')) == NULL)
+		q = end;	/* Compare until end.  */
+
+	      while (isspace (q[-1]))
+		q--;		/* Exclude trailing whitespace.  */
+
+	      /* Expand and/or allocate storage for a slice of the name, then
+		 copy it in.  */
+
+	      if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1)
+		{
+		  memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p));
+		  fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0';
+		}
+	      else
+		{
+		  free (fp->ctf_tmp_typeslice);
+		  fp->ctf_tmp_typeslice = strndup (p, (size_t) (q - p));
+		  if (fp->ctf_tmp_typeslice == NULL)
+		    {
+		      (void) ctf_set_errno (fp, ENOMEM);
+		      return CTF_ERR;
+		    }
+		}
+
+	      if ((type = ctf_hash_lookup_type (lp->ctl_hash, fp,
+						fp->ctf_tmp_typeslice)) == 0)
+		{
+		  (void) ctf_set_errno (fp, ECTF_NOTYPE);
+		  goto err;
+		}
+
+	      break;
+	    }
+	}
+
+      if (lp->ctl_prefix == NULL)
+	{
+	  (void) ctf_set_errno (fp, ECTF_NOTYPE);
+	  goto err;
+	}
+    }
+
+  if (*p != '\0' || type == 0)
+    return (ctf_set_errno (fp, ECTF_SYNTAX));
+
+  return type;
+
+err:
+  if (fp->ctf_parent != NULL
+      && (ptype = ctf_lookup_by_name (fp->ctf_parent, name)) != CTF_ERR)
+    return ptype;
+
+  return CTF_ERR;
+}
+
+typedef struct ctf_lookup_var_key
+{
+  ctf_file_t *clvk_fp;
+  const char *clvk_name;
+} ctf_lookup_var_key_t;
+
+/* A bsearch function for variable names.  */
+
+static int
+ctf_lookup_var (const void *key_, const void *memb_)
+{
+  const ctf_lookup_var_key_t *key = key_;
+  const ctf_varent_t *memb = memb_;
+
+  return (strcmp (key->clvk_name, ctf_strptr (key->clvk_fp, memb->ctv_name)));
+}
+
+/* Given a variable name, return the type of the variable with that name.  */
+
+ctf_id_t
+ctf_lookup_variable (ctf_file_t *fp, const char *name)
+{
+  ctf_varent_t *ent;
+  ctf_lookup_var_key_t key = { fp, name };
+
+  /* This array is sorted, so we can bsearch for it.  */
+
+  ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t),
+		 ctf_lookup_var);
+
+  if (ent == NULL)
+    {
+      if (fp->ctf_parent != NULL)
+	return ctf_lookup_variable (fp->ctf_parent, name);
+
+      return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+    }
+
+  return ent->ctv_type;
+}
+
+/* Given a symbol table index, return the name of that symbol from the secondary
+   string table, or the null string (never NULL).  */
+const char *
+ctf_lookup_symbol_name (ctf_file_t *fp, unsigned long symidx)
+{
+  const ctf_sect_t *sp = &fp->ctf_symtab;
+  Elf64_Sym sym, *gsp;
+
+  if (sp->cts_data == NULL)
+    {
+      ctf_set_errno (fp, ECTF_NOSYMTAB);
+      return _CTF_NULLSTR;
+    }
+
+  if (symidx >= fp->ctf_nsyms)
+    {
+      ctf_set_errno (fp, EINVAL);
+      return _CTF_NULLSTR;
+    }
+
+  if (sp->cts_entsize == sizeof (Elf32_Sym))
+    {
+      const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx;
+      gsp = ctf_sym_to_gelf (symp, &sym);
+    }
+  else
+      gsp = (Elf64_Sym *) sp->cts_data + symidx;
+
+  if (gsp->st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
+    return (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + gsp->st_name;
+
+  return _CTF_NULLSTR;
+}
+
+/* Given a symbol table index, return the type of the data object described
+   by the corresponding entry in the symbol table.  */
+
+ctf_id_t
+ctf_lookup_by_symbol (ctf_file_t *fp, unsigned long symidx)
+{
+  const ctf_sect_t *sp = &fp->ctf_symtab;
+  ctf_id_t type;
+
+  if (sp->cts_data == NULL)
+    return (ctf_set_errno (fp, ECTF_NOSYMTAB));
+
+  if (symidx >= fp->ctf_nsyms)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (sp->cts_entsize == sizeof (Elf32_Sym))
+    {
+      const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx;
+      if (ELF32_ST_TYPE (symp->st_info) != STT_OBJECT)
+	return (ctf_set_errno (fp, ECTF_NOTDATA));
+    }
+  else
+    {
+      const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx;
+      if (ELF64_ST_TYPE (symp->st_info) != STT_OBJECT)
+	return (ctf_set_errno (fp, ECTF_NOTDATA));
+    }
+
+  if (fp->ctf_sxlate[symidx] == -1u)
+    return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+
+  type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]);
+  if (type == 0)
+    return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
+
+  return type;
+}
+
 /* Return the pointer to the internal CTF type data corresponding to the
    given type ID.  If the ID is invalid, the function returns NULL.
    This function is not exported outside of the library.  */
@@ -61,3 +345,83 @@ ctf_lookup_by_id (ctf_file_t **fpp, ctf_id_t type)
   return NULL;
 }
 
+/* Given a symbol table index, return the info for the function described
+   by the corresponding entry in the symbol table.  */
+
+int
+ctf_func_info (ctf_file_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
+{
+  const ctf_sect_t *sp = &fp->ctf_symtab;
+  const uint32_t *dp;
+  uint32_t info, kind, n;
+
+  if (sp->cts_data == NULL)
+    return (ctf_set_errno (fp, ECTF_NOSYMTAB));
+
+  if (symidx >= fp->ctf_nsyms)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (sp->cts_entsize == sizeof (Elf32_Sym))
+    {
+      const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx;
+      if (ELF32_ST_TYPE (symp->st_info) != STT_FUNC)
+	return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    }
+  else
+    {
+      const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx;
+      if (ELF64_ST_TYPE (symp->st_info) != STT_FUNC)
+	return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    }
+
+  if (fp->ctf_sxlate[symidx] == -1u)
+    return (ctf_set_errno (fp, ECTF_NOFUNCDAT));
+
+  dp = (uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]);
+
+  info = *dp++;
+  kind = LCTF_INFO_KIND (fp, info);
+  n = LCTF_INFO_VLEN (fp, info);
+
+  if (kind == CTF_K_UNKNOWN && n == 0)
+    return (ctf_set_errno (fp, ECTF_NOFUNCDAT));
+
+  if (kind != CTF_K_FUNCTION)
+    return (ctf_set_errno (fp, ECTF_CORRUPT));
+
+  fip->ctc_return = *dp++;
+  fip->ctc_argc = n;
+  fip->ctc_flags = 0;
+
+  if (n != 0 && dp[n - 1] == 0)
+    {
+      fip->ctc_flags |= CTF_FUNC_VARARG;
+      fip->ctc_argc--;
+    }
+
+  return 0;
+}
+
+/* Given a symbol table index, return the arguments for the function described
+   by the corresponding entry in the symbol table.  */
+
+int
+ctf_func_args (ctf_file_t * fp, unsigned long symidx, uint32_t argc,
+	       ctf_id_t * argv)
+{
+  const uint32_t *dp;
+  ctf_funcinfo_t f;
+
+  if (ctf_func_info (fp, symidx, &f) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  /* The argument data is two uint32_t's past the translation table
+     offset: one for the function info, and one for the return type. */
+
+  dp = (uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2;
+
+  for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--)
+    *argv++ = *dp++;
+
+  return 0;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 04/19] libctf: low-level list manipulation and helper utilities
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (11 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 11/19] libctf: core type lookup Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-02 16:04   ` Nick Clifton
  2019-04-30 22:57 ` [PATCH 14/19] libctf: library version enforcement Nick Alcock
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

These utilities are a bit of a ragbag of small things needed by more
than one TU: list manipulation, ELF32->64 translators, routines to look
up strings in string tables, dynamically-allocated string appenders, and
routines to set the specialized errno values previously committed in
<ctf-api.h>.

Notes for reviewers:

The distinction betweern this file and ctf-subr.c is lost in the mists
of time: perhaps it was originally that ctf-subr.c contained nothing but
wrappers.  I am quite amenable to combining the two, and also to
splitting the errno-setting stuff out into ctf-error.c with the error
fetchers.

libctf/
	* ctf-util.c: New file.
	* ctf-impl.h: Add definitions.
---
 libctf/ctf-impl.h |  32 +++++++++
 libctf/ctf-util.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+)
 create mode 100644 libctf/ctf-util.c

diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 108c89d2c5..d4d71fbfdc 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -24,6 +24,13 @@
 #include <sys/errno.h>
 #include <ctf-api.h>
 #include <sys/types.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <ctype.h>
+#include <gelf.h>
 
 #ifdef	__cplusplus
 extern "C"
@@ -52,6 +59,25 @@ extern "C"
 
 #endif
 
+typedef struct ctf_list
+{
+  struct ctf_list *l_prev;	/* Previous pointer or tail pointer.  */
+  struct ctf_list *l_next;	/* Next pointer or head pointer.  */
+} ctf_list_t;
+
+#define	ctf_list_prev(elem)	((void *)(((ctf_list_t *)(elem))->l_prev))
+#define	ctf_list_next(elem)	((void *)(((ctf_list_t *)(elem))->l_next))
+
+extern void ctf_list_append (ctf_list_t *, void *);
+extern void ctf_list_prepend (ctf_list_t *, void *);
+extern void ctf_list_delete (ctf_list_t *, void *);
+
+extern const char *ctf_strraw (ctf_file_t *, uint32_t);
+extern const char *ctf_strptr (ctf_file_t *, uint32_t);
+
+extern ctf_file_t *ctf_set_open_errno (int *, int);
+extern long ctf_set_errno (ctf_file_t *, int);
+
 extern void *ctf_data_alloc (size_t);
 extern void ctf_data_free (void *, size_t);
 extern void ctf_data_protect (void *, size_t);
@@ -59,9 +85,15 @@ extern void ctf_data_protect (void *, size_t);
 extern void *ctf_alloc (size_t);
 extern void ctf_free (void *, size_t);
 
+extern char *ctf_strdup (const char *);
+extern char *ctf_str_append (char *, const char *);
+extern const char *ctf_strerror (int);
+
 _libctf_printflike_ (1, 2)
 extern void ctf_dprintf (const char *, ...);
 
+extern Elf64_Sym *ctf_sym_to_gelf (const Elf32_Sym *src, Elf64_Sym *dst);
+
 extern int _libctf_debug;	/* debugging messages enabled */
 
 #ifdef	__cplusplus
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
new file mode 100644
index 0000000000..a3a8d05dd3
--- /dev/null
+++ b/libctf/ctf-util.c
@@ -0,0 +1,176 @@
+/* Miscellaneous utilities.
+   Copyright (C) 2005-2018 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+/* Simple doubly-linked list append routine.  This implementation assumes that
+   each list element contains an embedded ctf_list_t as the first member.
+   An additional ctf_list_t is used to store the head (l_next) and tail
+   (l_prev) pointers.  The current head and tail list elements have their
+   previous and next pointers set to NULL, respectively.  */
+
+void
+ctf_list_append (ctf_list_t *lp, void *new)
+{
+  ctf_list_t *p = lp->l_prev;	/* p = tail list element.  */
+  ctf_list_t *q = new;		/* q = new list element.  */
+
+  lp->l_prev = q;
+  q->l_prev = p;
+  q->l_next = NULL;
+
+  if (p != NULL)
+    p->l_next = q;
+  else
+    lp->l_next = q;
+}
+
+/* Prepend the specified existing element to the given ctf_list_t.  The
+   existing pointer should be pointing at a struct with embedded ctf_list_t.  */
+
+void
+ctf_list_prepend (ctf_list_t * lp, void *new)
+{
+  ctf_list_t *p = new;		/* p = new list element.  */
+  ctf_list_t *q = lp->l_next;	/* q = head list element.  */
+
+  lp->l_next = p;
+  p->l_prev = NULL;
+  p->l_next = q;
+
+  if (q != NULL)
+    q->l_prev = p;
+  else
+    lp->l_prev = p;
+}
+
+/* Delete the specified existing element from the given ctf_list_t.  The
+   existing pointer should be pointing at a struct with embedded ctf_list_t.  */
+
+void
+ctf_list_delete (ctf_list_t *lp, void *existing)
+{
+  ctf_list_t *p = existing;
+
+  if (p->l_prev != NULL)
+    p->l_prev->l_next = p->l_next;
+  else
+    lp->l_next = p->l_next;
+
+  if (p->l_next != NULL)
+    p->l_next->l_prev = p->l_prev;
+  else
+    lp->l_prev = p->l_prev;
+}
+
+/* Convert a 32-bit ELF symbol into GElf (Elf64) and return a pointer to it.  */
+
+Elf64_Sym *
+ctf_sym_to_gelf (const Elf32_Sym *src, Elf64_Sym *dst)
+{
+  dst->st_name = src->st_name;
+  dst->st_value = src->st_value;
+  dst->st_size = src->st_size;
+  dst->st_info = src->st_info;
+  dst->st_other = src->st_other;
+  dst->st_shndx = src->st_shndx;
+
+  return dst;
+}
+
+/* Convert an encoded CTF string name into a pointer to a C string by looking
+  up the appropriate string table buffer and then adding the offset.  */
+
+const char *
+ctf_strraw (ctf_file_t *fp, uint32_t name)
+{
+  ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];
+
+  if (ctsp->cts_strs != NULL && CTF_NAME_OFFSET (name) < ctsp->cts_len)
+    return (ctsp->cts_strs + CTF_NAME_OFFSET (name));
+
+  /* String table not loaded or corrupt offset.  */
+  return NULL;
+}
+
+const char *
+ctf_strptr (ctf_file_t *fp, uint32_t name)
+{
+  const char *s = ctf_strraw (fp, name);
+  return (s != NULL ? s : "(?)");
+}
+
+/* Same as strdup(3C), but use ctf_alloc() to do the memory allocation. */
+
+char *
+ctf_strdup (const char *s1)
+{
+  char *s2 = ctf_alloc (strlen (s1) + 1);
+
+  if (s2 != NULL)
+    (void) strcpy (s2, s1);
+
+  return s2;
+}
+
+/* A string appender working on dynamic strings.  */
+
+char *
+ctf_str_append (char *s, const char *append)
+{
+  size_t s_len = 0;
+
+  if (append == NULL)
+    return s;
+
+  if (s != NULL)
+    s_len = strlen (s);
+
+  size_t append_len = strlen (append);
+
+  if ((s = realloc (s, s_len + append_len + 1)) == NULL)
+    return NULL;
+
+  memcpy (s + s_len, append, append_len);
+  s[s_len + append_len] = '\0';
+
+  return s;
+}
+
+/* Store the specified error code into errp if it is non-NULL, and then
+   return NULL for the benefit of the caller.  */
+
+ctf_file_t *
+ctf_set_open_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return NULL;
+}
+
+/* Store the specified error code into the CTF container, and then return
+   CTF_ERR for the benefit of the caller. */
+
+long
+ctf_set_errno (ctf_file_t * fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 08/19] libctf: creation functions
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (9 preceding siblings ...)
  2019-04-30 22:57 ` CTF format overview Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 11/19] libctf: core type lookup Nick Alcock
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

The CTF creation process looks roughly like (error handling elided):

int err;
ctf_file_t *foo = ctf_create (&err);

ctf_id_t type = ctf_add_THING (foo, ...);
ctf_update (foo);
ctf_*write (...);

Some ctf_add_THING functions accept other type IDs as arguments,
depending on the type: cv-quals, pointers, and structure and union
members all take other types as arguments.  So do 'slices', which
let you take an existing integral type and recast it as a type
with a different bitness or offset within a byte, for bitfields.
One class of THING is not a type: "variables", which are mappings
of names (in the internal string table) to types.  These are mostly
useful when encoding variables that do not appear in a symbol table
but which some external user has some other way to figure out the
address of at runtime (dynamic symbol lookup or querying a VM
interpreter or something).

You can snapshot the creation process at any point: rolling back to a
snapshot deletes all types and variables added since that point.

You can make arbitrary type queries on the CTF container during the
creation process, but you must call ctf_update() first, which
translates the growing dynamic container into a static one (this uses
the CTF opening machinery, added in a later commit), which is quite
expensive.  This function must also be called after adding types
and before writing the container out.

Because addition of types involves looking up existing types, we add a
little of the type lookup machinery here, as well: only enough to
look up types in dynamic containers under construction.

libctf/
	* ctf-create.c: New file.
	* ctf-lib.c: More headers.
	* ctf-lib.c (ctf_gzwrite): New function.
	(ctf_compress_write): Likewise.
	(ctf_write): Likewise.
	* ctf-lookup.c: New file.

include/
	* ctf-api.h (zlib.h): New include.
	(ctf_sect_t): New.
	(ctf_sect_names_t): Likewise.
	(ctf_encoding_t): Likewise.
	(ctf_membinfo_t): Likewise.
	(ctf_arinfo_t): Likewise.
	(ctf_funcinfo_t): Likewise.
	(ctf_lblinfo_t): Likewise.
	(ctf_snapshot_id_t): Likewise.
	(CTF_FUNC_VARARG): Likewise.
	(ctf_simple_open): Likewise.
	(ctf_bufopen): Likewise.
	(ctf_create): Likewise.
	(ctf_add_array): Likewise.
	(ctf_add_const): Likewise.
	(ctf_add_enum_encoded): Likewise.
	(ctf_add_enum): Likewise.
	(ctf_add_float): Likewise.
	(ctf_add_forward): Likewise.
	(ctf_add_function): Likewise.
	(ctf_add_integer): Likewise.
	(ctf_add_slice): Likewise.
	(ctf_add_pointer): Likewise.
	(ctf_add_type): Likewise.
	(ctf_add_typedef): Likewise.
	(ctf_add_restrict): Likewise.
	(ctf_add_struct): Likewise.
	(ctf_add_union): Likewise.
	(ctf_add_struct_sized): Likewise.
	(ctf_add_union_sized): Likewise.
	(ctf_add_volatile): Likewise.
	(ctf_add_enumerator): Likewise.
	(ctf_add_member): Likewise.
	(ctf_add_member_offset): Likewise.
	(ctf_add_member_encoded): Likewise.
	(ctf_add_variable): Likewise.
	(ctf_set_array): Likewise.
	(ctf_update): Likewise.
	(ctf_snapshot): Likewise.
	(ctf_rollback): Likewise.
	(ctf_discard): Likewise.
	(ctf_write): Likewise.
	(ctf_gzwrite): Likewise.
	(ctf_compress_write): Likewise.
---
 include/ctf-api.h   |  129 ++++
 libctf/ctf-create.c | 1452 +++++++++++++++++++++++++++++++++++++++++++
 libctf/ctf-lib.c    |  108 ++++
 libctf/ctf-lookup.c |   63 ++
 4 files changed, 1752 insertions(+)
 create mode 100644 libctf/ctf-create.c
 create mode 100644 libctf/ctf-lookup.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 646e848c84..5847b24752 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -27,6 +27,7 @@
 #include <sys/param.h>
 #include <sys/types.h>
 #include <ctf.h>
+#include <zlib.h>
 
 #ifdef	__cplusplus
 extern "C"
@@ -44,6 +45,81 @@ typedef struct ctf_file ctf_file_t;
 typedef struct ctf_archive ctf_archive_t;
 typedef long ctf_id_t;
 
+/* If the debugger needs to provide the CTF library with a set of raw buffers
+   for use as the CTF data, symbol table, and string table, it can do so by
+   filling in ctf_sect_t structures and passing them to ctf_bufopen().
+
+   The contents of this structure must always be in native endianness (no
+   byteswapping is performed).  */
+
+typedef struct ctf_sect
+{
+  const char *cts_name;		  /* Section name (if any).  */
+  unsigned long cts_type;	  /* Section type (ELF SHT_... value).  */
+  unsigned long cts_flags;	  /* Section flags (ELF SHF_... value).  */
+  const void *cts_data;		  /* Pointer to section data.  */
+  size_t cts_size;		  /* Size of data in bytes.  */
+  size_t cts_entsize;		  /* Size of each section entry (symtab only).  */
+  off64_t cts_offset;		  /* File offset of this section (if any).  */
+} ctf_sect_t;
+
+/* Symbolic names for CTF sections.  */
+
+typedef enum ctf_sect_names
+  {
+   CTF_SECT_HEADER,
+   CTF_SECT_LABEL,
+   CTF_SECT_OBJT,
+   CTF_SECT_FUNC,
+   CTF_SECT_VAR,
+   CTF_SECT_TYPE,
+   CTF_SECT_STR
+  } ctf_sect_names_t;
+
+/* Encoding information for integers, floating-point values, and certain other
+   intrinsics can be obtained by calling ctf_type_encoding(), below.  The flags
+   field will contain values appropriate for the type defined in <ctf.h>.  */
+
+typedef struct ctf_encoding
+{
+  uint32_t cte_format;		 /* Data format (CTF_INT_* or CTF_FP_* flags).  */
+  uint32_t cte_offset;		 /* Offset of value in bits.  */
+  uint32_t cte_bits;		 /* Size of storage in bits.  */
+} ctf_encoding_t;
+
+typedef struct ctf_membinfo
+{
+  ctf_id_t ctm_type;		/* Type of struct or union member.  */
+  unsigned long ctm_offset;	/* Offset of member in bits.  */
+} ctf_membinfo_t;
+
+typedef struct ctf_arinfo
+{
+  ctf_id_t ctr_contents;	/* Type of array contents.  */
+  ctf_id_t ctr_index;		/* Type of array index.  */
+  uint32_t ctr_nelems;		/* Number of elements.  */
+} ctf_arinfo_t;
+
+typedef struct ctf_funcinfo
+{
+  ctf_id_t ctc_return;		/* Function return type.  */
+  uint32_t ctc_argc;		/* Number of typed arguments to function.  */
+  uint32_t ctc_flags;		/* Function attributes (see below).  */
+} ctf_funcinfo_t;
+
+typedef struct ctf_lblinfo
+{
+  ctf_id_t ctb_type;		/* Last type associated with the label.  */
+} ctf_lblinfo_t;
+
+typedef struct ctf_snapshot_id
+{
+  unsigned long dtd_id;		/* Highest DTD ID at time of snapshot.  */
+  unsigned long snapshot_id;	/* Snapshot id at time of snapshot.  */
+} ctf_snapshot_id_t;
+
+#define	CTF_FUNC_VARARG	0x1	/* Function arguments end with varargs.  */
+
 /* Functions that return integer status or a ctf_id_t use the following value
    to indicate failure.  ctf_errno() can be used to obtain an error code.  */
 #define	CTF_ERR	(-1L)
@@ -122,8 +198,61 @@ enum
 #define	CTF_ADD_NONROOT	0	/* Type only visible in nested scope.  */
 #define	CTF_ADD_ROOT	1	/* Type visible at top-level scope.  */
 
+extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
+				   size_t, const char *, size_t, int *);
+extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
+				const ctf_sect_t *, int *);
+extern ctf_file_t *ctf_create (int *);
+
 extern int ctf_errno (ctf_file_t *);
 extern const char *ctf_errmsg (int);
+extern ctf_id_t ctf_add_array (ctf_file_t *, uint32_t,
+			       const ctf_arinfo_t *);
+extern ctf_id_t ctf_add_const (ctf_file_t *, uint32_t, ctf_id_t);
+extern ctf_id_t ctf_add_enum_encoded (ctf_file_t *, uint32_t, const char *,
+				      const ctf_encoding_t *);
+extern ctf_id_t ctf_add_enum (ctf_file_t *, uint32_t, const char *);
+extern ctf_id_t ctf_add_float (ctf_file_t *, uint32_t,
+			       const char *, const ctf_encoding_t *);
+extern ctf_id_t ctf_add_forward (ctf_file_t *, uint32_t, const char *,
+				 uint32_t);
+extern ctf_id_t ctf_add_function (ctf_file_t *, uint32_t,
+				  const ctf_funcinfo_t *, const ctf_id_t *);
+extern ctf_id_t ctf_add_integer (ctf_file_t *, uint32_t, const char *,
+				 const ctf_encoding_t *);
+extern ctf_id_t ctf_add_slice (ctf_file_t *, uint32_t, ctf_id_t, const ctf_encoding_t *);
+extern ctf_id_t ctf_add_pointer (ctf_file_t *, uint32_t, ctf_id_t);
+extern ctf_id_t ctf_add_type (ctf_file_t *, ctf_file_t *, ctf_id_t);
+extern ctf_id_t ctf_add_typedef (ctf_file_t *, uint32_t, const char *,
+				 ctf_id_t);
+extern ctf_id_t ctf_add_restrict (ctf_file_t *, uint32_t, ctf_id_t);
+extern ctf_id_t ctf_add_struct (ctf_file_t *, uint32_t, const char *);
+extern ctf_id_t ctf_add_union (ctf_file_t *, uint32_t, const char *);
+extern ctf_id_t ctf_add_struct_sized (ctf_file_t *, uint32_t, const char *,
+				      size_t);
+extern ctf_id_t ctf_add_union_sized (ctf_file_t *, uint32_t, const char *,
+				     size_t);
+extern ctf_id_t ctf_add_volatile (ctf_file_t *, uint32_t, ctf_id_t);
+
+extern int ctf_add_enumerator (ctf_file_t *, ctf_id_t, const char *, int);
+extern int ctf_add_member (ctf_file_t *, ctf_id_t, const char *, ctf_id_t);
+extern int ctf_add_member_offset (ctf_file_t *, ctf_id_t, const char *,
+				  ctf_id_t, unsigned long);
+extern int ctf_add_member_encoded (ctf_file_t *, ctf_id_t, const char *,
+				   ctf_id_t, unsigned long,
+				   const ctf_encoding_t);
+
+extern int ctf_add_variable (ctf_file_t *, const char *, ctf_id_t);
+
+extern int ctf_set_array (ctf_file_t *, ctf_id_t, const ctf_arinfo_t *);
+
+extern int ctf_update (ctf_file_t *);
+extern ctf_snapshot_id_t ctf_snapshot (ctf_file_t *);
+extern int ctf_rollback (ctf_file_t *, ctf_snapshot_id_t);
+extern int ctf_discard (ctf_file_t *);
+extern int ctf_write (ctf_file_t *, int);
+extern int ctf_gzwrite (ctf_file_t * fp, gzFile fd);
+extern int ctf_compress_write (ctf_file_t * fp, int fd);
 
 #ifdef	__cplusplus
 }
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
new file mode 100644
index 0000000000..cde4c52666
--- /dev/null
+++ b/libctf/ctf-create.c
@@ -0,0 +1,1452 @@
+/* CTF file creation.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <gelf.h>
+#include <string.h>
+
+/* To create an empty CTF container, we just declare a zeroed header and call
+   ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new container r/w
+   and initialize the dynamic members.  We set dtvstrlen to 1 to reserve the
+   first byte of the string table for a \0 byte, and we start assigning type
+   IDs at 1 because type ID 0 is used as a sentinel and a not-found
+   indicator.  */
+
+ctf_file_t *
+ctf_create (int *errp)
+{
+  static const ctf_header_t hdr = { .cth_preamble = { CTF_MAGIC, CTF_VERSION, 0 } };
+
+  ctf_dynhash_t *dthash;
+  ctf_dynhash_t *dvhash;
+  ctf_dynhash_t *dtbyname;
+  ctf_sect_t cts;
+  ctf_file_t *fp;
+
+  dthash = ctf_dynhash_create (ctf_hash_integer, ctf_hash_eq_integer,
+			       NULL, NULL);
+  if (dthash == NULL)
+    {
+      ctf_set_open_errno (errp, EAGAIN);
+      goto err;
+    }
+
+  dvhash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+			       NULL, NULL);
+  if (dvhash == NULL)
+    {
+      ctf_set_open_errno (errp, EAGAIN);
+      goto err_dt;
+    }
+
+  dtbyname = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+				 free, NULL);
+  if (dtbyname == NULL)
+    {
+      ctf_set_open_errno (errp, EAGAIN);
+      goto err_dv;
+    }
+
+  cts.cts_name = _CTF_SECTION;
+  cts.cts_type = SHT_PROGBITS;
+  cts.cts_flags = 0;
+  cts.cts_data = &hdr;
+  cts.cts_size = sizeof (hdr);
+  cts.cts_entsize = 1;
+  cts.cts_offset = 0;
+
+  if ((fp = ctf_bufopen (&cts, NULL, NULL, errp)) == NULL)
+      goto err_dtbyname;
+
+  fp->ctf_flags |= LCTF_RDWR;
+  fp->ctf_dtbyname = dtbyname;
+  fp->ctf_dthash = dthash;
+  fp->ctf_dvhash = dvhash;
+  fp->ctf_dtvstrlen = 1;
+  fp->ctf_dtnextid = 1;
+  fp->ctf_dtoldid = 0;
+  fp->ctf_snapshots = 0;
+  fp->ctf_snapshot_lu = 0;
+
+  return fp;
+
+ err_dtbyname:
+  ctf_dynhash_destroy (dtbyname);
+ err_dv:
+  ctf_dynhash_destroy (dvhash);
+ err_dt:
+  ctf_dynhash_destroy (dthash);
+ err:
+  return NULL;
+}
+
+static unsigned char *
+ctf_copy_smembers (ctf_dtdef_t *dtd, uint32_t soff, unsigned char *t)
+{
+  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+  ctf_member_t ctm;
+
+  for (; dmd != NULL; dmd = ctf_list_next (dmd))
+    {
+      if (dmd->dmd_name)
+	{
+	  ctm.ctm_name = soff;
+	  soff += strlen (dmd->dmd_name) + 1;
+	}
+      else
+	ctm.ctm_name = 0;
+
+      ctm.ctm_type = (uint32_t) dmd->dmd_type;
+      ctm.ctm_offset = (uint32_t) dmd->dmd_offset;
+
+      memcpy (t, &ctm, sizeof (ctm));
+      t += sizeof (ctm);
+    }
+
+  return t;
+}
+
+static unsigned char *
+ctf_copy_lmembers (ctf_dtdef_t *dtd, uint32_t soff, unsigned char *t)
+{
+  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+  ctf_lmember_t ctlm;
+
+  for (; dmd != NULL; dmd = ctf_list_next (dmd))
+    {
+      if (dmd->dmd_name)
+	{
+	  ctlm.ctlm_name = soff;
+	  soff += strlen (dmd->dmd_name) + 1;
+	}
+      else
+	ctlm.ctlm_name = 0;
+
+      ctlm.ctlm_type = (uint32_t) dmd->dmd_type;
+      ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset);
+      ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset);
+
+      memcpy (t, &ctlm, sizeof (ctlm));
+      t += sizeof (ctlm);
+    }
+
+  return t;
+}
+
+static unsigned char *
+ctf_copy_emembers (ctf_dtdef_t *dtd, uint32_t soff, unsigned char *t)
+{
+  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+  ctf_enum_t cte;
+
+  for (; dmd != NULL; dmd = ctf_list_next (dmd))
+    {
+      cte.cte_name = soff;
+      cte.cte_value = dmd->dmd_value;
+      soff += strlen (dmd->dmd_name) + 1;
+      memcpy (t, &cte, sizeof (cte));
+      t += sizeof (cte);
+    }
+
+  return t;
+}
+
+static unsigned char *
+ctf_copy_membnames (ctf_dtdef_t *dtd, unsigned char *s)
+{
+  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+  size_t len;
+
+  for (; dmd != NULL; dmd = ctf_list_next (dmd))
+    {
+      if (dmd->dmd_name == NULL)
+	continue;			/* Skip anonymous members.  */
+      len = strlen (dmd->dmd_name) + 1;
+      memcpy (s, dmd->dmd_name, len);
+      s += len;
+    }
+
+  return s;
+}
+
+/* Sort a newly-constructed static variable array.  */
+
+static int
+ctf_sort_var (const void *one_, const void *two_, void *strtab_)
+{
+  const ctf_varent_t *one = one_;
+  const ctf_varent_t *two = two_;
+  const char *strtab = strtab_;
+  const char *n1 = strtab + CTF_NAME_OFFSET (one->ctv_name);
+  const char *n2 = strtab + CTF_NAME_OFFSET (two->ctv_name);
+
+  return (strcmp (n1, n2));
+}
+
+/* If the specified CTF container is writable and has been modified, reload this
+   container with the updated type definitions.  In order to make this code and
+   the rest of libctf as simple as possible, we perform updates by taking the
+   dynamic type definitions and creating an in-memory CTF file containing the
+   definitions, and then call ctf_simple_open() on it.  This not only leverages
+   ctf_simple_open(), but also avoids having to bifurcate the rest of the library
+   code with different lookup paths for static and dynamic type definitions.  We
+   are therefore optimizing greatly for lookup over update, which we assume will
+   be an uncommon operation.  We perform one extra trick here for the benefit of
+   callers and to keep our code simple: ctf_simple_open() will return a new
+   ctf_file_t, but we want to keep the fp constant for the caller, so after
+   ctf_simple_open() returns, we use memcpy to swap the interior of the old and
+   new ctf_file_t's, and then free the old.  */
+int
+ctf_update (ctf_file_t *fp)
+{
+  ctf_file_t ofp, *nfp;
+  ctf_header_t hdr;
+  ctf_dtdef_t *dtd;
+  ctf_dvdef_t *dvd;
+  ctf_varent_t *dvarents;
+
+  unsigned char *s, *s0, *t;
+  unsigned long i;
+  size_t buf_size, type_size, nvars;
+  void *buf;
+  int err;
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  /* Update required?  */
+  if (!(fp->ctf_flags & LCTF_DIRTY))
+    return 0;
+
+  /* Fill in an initial CTF header.  We will leave the label, object,
+     and function sections empty and only output a header, type section,
+     and string table.  The type section begins at a 4-byte aligned
+     boundary past the CTF header itself (at relative offset zero).  */
+
+  memset (&hdr, 0, sizeof (hdr));
+  hdr.cth_magic = CTF_MAGIC;
+  hdr.cth_version = CTF_VERSION;
+
+  if (fp->ctf_flags & LCTF_CHILD)
+    hdr.cth_parname = 1;		/* parname added just below.  */
+
+  /* Iterate through the dynamic type definition list and compute the
+     size of the CTF type section we will need to generate.  */
+
+  for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
+       dtd != NULL; dtd = ctf_list_next (dtd))
+    {
+      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+	type_size += sizeof (ctf_stype_t);
+      else
+	type_size += sizeof (ctf_type_t);
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  type_size += sizeof (uint32_t);
+	  break;
+	case CTF_K_ARRAY:
+	  type_size += sizeof (ctf_array_t);
+	  break;
+	case CTF_K_SLICE:
+	  type_size += sizeof (ctf_slice_t);
+	  break;
+	case CTF_K_FUNCTION:
+	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
+	  break;
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+	    type_size += sizeof (ctf_member_t) * vlen;
+	  else
+	    type_size += sizeof (ctf_lmember_t) * vlen;
+	  break;
+	case CTF_K_ENUM:
+	  type_size += sizeof (ctf_enum_t) * vlen;
+	  break;
+	}
+    }
+
+  /* Computing the number of entries in the CTF variable section is much
+     simpler.  */
+
+  for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
+       dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
+
+  /* Fill in the string table and type offset and size, compute the size
+     of the entire CTF buffer we need, and then allocate a new buffer and
+     memcpy the finished header to the start of the buffer.  */
+
+  hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
+  hdr.cth_stroff = hdr.cth_typeoff + type_size;
+  hdr.cth_strlen = fp->ctf_dtvstrlen;
+  if (fp->ctf_parname != NULL)
+    hdr.cth_strlen += strlen (fp->ctf_parname) + 1;
+
+  buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
+
+  if ((buf = ctf_data_alloc (buf_size)) == MAP_FAILED)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  memcpy (buf, &hdr, sizeof (ctf_header_t));
+  t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_varoff;
+  s = s0 = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff;
+
+  s[0] = '\0';
+  s++;
+
+  if (fp->ctf_parname != NULL)
+    {
+      memcpy (s, fp->ctf_parname, strlen (fp->ctf_parname) + 1);
+      s += strlen (fp->ctf_parname) + 1;
+    }
+
+  /* Work over the variable list, translating everything into
+     ctf_varent_t's and filling out the string table, then sort the buffer
+     of ctf_varent_t's.  */
+
+  dvarents = (ctf_varent_t *) t;
+  for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
+       dvd = ctf_list_next (dvd), i++)
+    {
+      ctf_varent_t *var = &dvarents[i];
+      size_t len = strlen (dvd->dvd_name) + 1;
+
+      var->ctv_name = (uint32_t) (s - s0);
+      var->ctv_type = dvd->dvd_type;
+      memcpy (s, dvd->dvd_name, len);
+      s += len;
+    }
+  assert (i == nvars);
+
+  qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var, s0);
+  t += sizeof (ctf_varent_t) * nvars;
+
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
+
+  /* We now take a final lap through the dynamic type definition list and
+     copy the appropriate type records and strings to the output buffer.  */
+
+  for (dtd = ctf_list_next (&fp->ctf_dtdefs);
+       dtd != NULL; dtd = ctf_list_next (dtd))
+    {
+
+      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+      ctf_array_t cta;
+      uint32_t encoding;
+      size_t len;
+
+      if (dtd->dtd_name != NULL)
+	{
+	  dtd->dtd_data.ctt_name = (uint32_t) (s - s0);
+	  len = strlen (dtd->dtd_name) + 1;
+	  memcpy (s, dtd->dtd_name, len);
+	  s += len;
+	}
+      else
+	dtd->dtd_data.ctt_name = 0;
+
+      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+	len = sizeof (ctf_stype_t);
+      else
+	len = sizeof (ctf_type_t);
+
+      memcpy (t, &dtd->dtd_data, len);
+      t += len;
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  if (kind == CTF_K_INTEGER)
+	    {
+	      encoding = CTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
+				       dtd->dtd_u.dtu_enc.cte_offset,
+				       dtd->dtd_u.dtu_enc.cte_bits);
+	    }
+	  else
+	    {
+	      encoding = CTF_FP_DATA (dtd->dtd_u.dtu_enc.cte_format,
+				      dtd->dtd_u.dtu_enc.cte_offset,
+				      dtd->dtd_u.dtu_enc.cte_bits);
+	    }
+	  memcpy (t, &encoding, sizeof (encoding));
+	  t += sizeof (encoding);
+	  break;
+
+	case CTF_K_SLICE:
+	  memcpy (t, &dtd->dtd_u.dtu_slice, sizeof (struct ctf_slice));
+	  t += sizeof (struct ctf_slice);
+	  break;
+
+	case CTF_K_ARRAY:
+	  cta.cta_contents = (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents;
+	  cta.cta_index = (uint32_t) dtd->dtd_u.dtu_arr.ctr_index;
+	  cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
+	  memcpy (t, &cta, sizeof (cta));
+	  t += sizeof (cta);
+	  break;
+
+	case CTF_K_FUNCTION:
+	  {
+	    uint32_t *argv = (uint32_t *) (uintptr_t) t;
+	    uint32_t argc;
+
+	    for (argc = 0; argc < vlen; argc++)
+	      *argv++ = (uint32_t) dtd->dtd_u.dtu_argv[argc];
+
+	    if (vlen & 1)
+	      *argv++ = 0;	/* Pad to 4-byte boundary.  */
+
+	    t = (unsigned char *) argv;
+	    break;
+	  }
+
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+	    t = ctf_copy_smembers (dtd, (uint32_t) (s - s0), t);
+	  else
+	    t = ctf_copy_lmembers (dtd, (uint32_t) (s - s0), t);
+	  s = ctf_copy_membnames (dtd, s);
+	  break;
+
+	case CTF_K_ENUM:
+	  t = ctf_copy_emembers (dtd, (uint32_t) (s - s0), t);
+	  s = ctf_copy_membnames (dtd, s);
+	  break;
+	}
+    }
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
+
+  /* Finally, we are ready to ctf_simple_open() the new container.  If this
+     is successful, we then switch nfp and fp and free the old container.  */
+
+  ctf_data_protect (buf, buf_size);
+
+  if ((nfp = ctf_simple_open (buf, buf_size, NULL, 0, 0, NULL, 0, &err)) == NULL)
+    {
+      ctf_data_free (buf, buf_size);
+      return (ctf_set_errno (fp, err));
+    }
+
+  (void) ctf_setmodel (nfp, ctf_getmodel (fp));
+  (void) ctf_import (nfp, fp->ctf_parent);
+
+  nfp->ctf_refcnt = fp->ctf_refcnt;
+  nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
+  nfp->ctf_data.cts_data = NULL;	/* Force ctf_data_free() on close.  */
+  nfp->ctf_dthash = fp->ctf_dthash;
+  nfp->ctf_dtdefs = fp->ctf_dtdefs;
+  nfp->ctf_dtbyname = fp->ctf_dtbyname;
+  nfp->ctf_dvhash = fp->ctf_dvhash;
+  nfp->ctf_dvdefs = fp->ctf_dvdefs;
+  nfp->ctf_dtvstrlen = fp->ctf_dtvstrlen;
+  nfp->ctf_dtnextid = fp->ctf_dtnextid;
+  nfp->ctf_dtoldid = fp->ctf_dtnextid - 1;
+  nfp->ctf_snapshots = fp->ctf_snapshots + 1;
+  nfp->ctf_specific = fp->ctf_specific;
+
+  nfp->ctf_snapshot_lu = fp->ctf_snapshots;
+
+  fp->ctf_dtbyname = NULL;
+  fp->ctf_dthash = NULL;
+  memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t));
+
+  fp->ctf_dvhash = NULL;
+  memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
+
+  memcpy (&ofp, fp, sizeof (ctf_file_t));
+  memcpy (fp, nfp, sizeof (ctf_file_t));
+  memcpy (nfp, &ofp, sizeof (ctf_file_t));
+
+  /* Initialize the ctf_lookup_by_name top-level dictionary.  We keep an
+     array of type name prefixes and the corresponding ctf_dynhash to use.
+     NOTE: This code must be kept in sync with the code in ctf_bufopen().  */
+
+  fp->ctf_lookups[0].ctl_hash = fp->ctf_structs;
+  fp->ctf_lookups[1].ctl_hash = fp->ctf_unions;
+  fp->ctf_lookups[2].ctl_hash = fp->ctf_enums;
+  fp->ctf_lookups[3].ctl_hash = fp->ctf_names;
+
+  nfp->ctf_refcnt = 1;		/* Force nfp to be freed.  */
+  ctf_close (nfp);
+
+  return 0;
+}
+
+static char *
+ctf_prefixed_name (int kind, const char *name)
+{
+  char *prefixed;
+
+  switch (kind)
+    {
+    case CTF_K_STRUCT:
+      prefixed = ctf_strdup ("struct ");
+      break;
+    case CTF_K_UNION:
+      prefixed = ctf_strdup ("union ");
+      break;
+    case CTF_K_ENUM:
+      prefixed = ctf_strdup ("enum ");
+      break;
+    default:
+      prefixed = ctf_strdup ("");
+    }
+
+  prefixed = ctf_str_append (prefixed, name);
+  return prefixed;
+}
+
+void
+ctf_dtd_insert (ctf_file_t *fp, ctf_dtdef_t *dtd)
+{
+  ctf_dynhash_insert (fp->ctf_dthash, (void *) dtd->dtd_type, dtd);
+  ctf_list_append (&fp->ctf_dtdefs, dtd);
+  if (dtd->dtd_name)
+    {
+      int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      ctf_dynhash_insert (fp->ctf_dtbyname, ctf_prefixed_name (kind,
+							       dtd->dtd_name),
+			  dtd);
+    }
+}
+
+void
+ctf_dtd_delete (ctf_file_t *fp, ctf_dtdef_t *dtd)
+{
+  ctf_dmdef_t *dmd, *nmd;
+  size_t len;
+  int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+
+  ctf_dynhash_remove (fp->ctf_dthash, (void *) dtd->dtd_type);
+
+  switch (kind)
+    {
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+    case CTF_K_ENUM:
+      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+	   dmd != NULL; dmd = nmd)
+	{
+	  if (dmd->dmd_name != NULL)
+	    {
+	      len = strlen (dmd->dmd_name) + 1;
+	      ctf_free (dmd->dmd_name, len);
+	      fp->ctf_dtvstrlen -= len;
+	    }
+	  nmd = ctf_list_next (dmd);
+	  ctf_free (dmd, sizeof (ctf_dmdef_t));
+	}
+      break;
+    case CTF_K_FUNCTION:
+      ctf_free (dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
+		LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info));
+      break;
+    }
+
+  if (dtd->dtd_name)
+    {
+      char *name;
+
+      name = ctf_prefixed_name (kind, dtd->dtd_name);
+      ctf_dynhash_remove (fp->ctf_dtbyname, name);
+      free (name);
+
+      len = strlen (dtd->dtd_name) + 1;
+      ctf_free (dtd->dtd_name, len);
+      fp->ctf_dtvstrlen -= len;
+    }
+
+  ctf_list_delete (&fp->ctf_dtdefs, dtd);
+  ctf_free (dtd, sizeof (ctf_dtdef_t));
+}
+
+ctf_dtdef_t *
+ctf_dtd_lookup (const ctf_file_t *fp, ctf_id_t type)
+{
+  return (ctf_dtdef_t *) ctf_dynhash_lookup (fp->ctf_dthash, (void *) type);
+}
+
+static ctf_id_t
+ctf_dtd_lookup_type_by_name (ctf_file_t *fp, int kind, const char *name)
+{
+  ctf_dtdef_t *dtd;
+  char *decorated = ctf_prefixed_name (kind, name);
+
+  dtd = (ctf_dtdef_t *) ctf_dynhash_lookup (fp->ctf_dtbyname, decorated);
+  free (decorated);
+
+  if (dtd)
+    return dtd->dtd_type;
+
+  return 0;
+}
+
+ctf_dtdef_t *
+ctf_dynamic_type (const ctf_file_t *fp, ctf_id_t id)
+{
+  ctf_id_t idx;
+
+  if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id))
+    fp = fp->ctf_parent;
+
+  idx = LCTF_TYPE_TO_INDEX(fp, id);
+
+  if (((unsigned long) idx > fp->ctf_typemax) &&
+      ((unsigned long) idx < fp->ctf_dtnextid))
+    return ctf_dtd_lookup (fp, id);
+  return NULL;
+}
+
+void
+ctf_dvd_insert (ctf_file_t *fp, ctf_dvdef_t *dvd)
+{
+  ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd);
+  ctf_list_append (&fp->ctf_dvdefs, dvd);
+}
+
+void
+ctf_dvd_delete (ctf_file_t *fp, ctf_dvdef_t *dvd)
+{
+  size_t len = strlen (dvd->dvd_name);
+  ctf_dynhash_remove (fp->ctf_dvhash, dvd->dvd_name);
+
+  ctf_free (dvd->dvd_name, len + 1);
+  fp->ctf_dtvstrlen -= len + 1;
+
+  ctf_list_delete (&fp->ctf_dvdefs, dvd);
+  ctf_free (dvd, sizeof (ctf_dvdef_t));
+}
+
+ctf_dvdef_t *
+ctf_dvd_lookup (const ctf_file_t *fp, const char *name)
+{
+  return (ctf_dvdef_t *) ctf_dynhash_lookup (fp->ctf_dvhash, name);
+}
+
+/* Discard all of the dynamic type definitions and variable definitions that
+   have been added to the container since the last call to ctf_update().  We
+   locate such types by scanning the dtd list and deleting elements that have
+   type IDs greater than ctf_dtoldid, which is set by ctf_update(), above, and
+   by scanning the variable list and deleting elements that have update IDs
+   equal to the current value of the last-update snapshot count (indicating that
+   they were added after the most recent call to ctf_update()).  */
+int
+ctf_discard (ctf_file_t *fp)
+{
+  ctf_snapshot_id_t last_update =
+    { fp->ctf_dtoldid,
+      fp->ctf_snapshot_lu + 1 };
+
+  /* Update required?  */
+  if (!(fp->ctf_flags & LCTF_DIRTY))
+    return 0;
+
+  return (ctf_rollback (fp, last_update));
+}
+
+ctf_snapshot_id_t
+ctf_snapshot (ctf_file_t *fp)
+{
+  ctf_snapshot_id_t snapid;
+  snapid.dtd_id = fp->ctf_dtnextid - 1;
+  snapid.snapshot_id = fp->ctf_snapshots++;
+  return snapid;
+}
+
+/* Like ctf_discard(), only discards everything after a particular ID.  */
+int
+ctf_rollback (ctf_file_t *fp, ctf_snapshot_id_t id)
+{
+  ctf_dtdef_t *dtd, *ntd;
+  ctf_dvdef_t *dvd, *nvd;
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (fp->ctf_dtoldid > id.dtd_id)
+    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+
+  if (fp->ctf_snapshot_lu >= id.snapshot_id)
+    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+
+  for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
+    {
+      ntd = ctf_list_next (dtd);
+
+      if (LCTF_TYPE_TO_INDEX (fp, dtd->dtd_type) <= id.dtd_id)
+	continue;
+
+      ctf_dtd_delete (fp, dtd);
+    }
+
+  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
+    {
+      nvd = ctf_list_next (dvd);
+
+      if (dvd->dvd_snapshots <= id.snapshot_id)
+	continue;
+
+      ctf_dvd_delete (fp, dvd);
+    }
+
+  fp->ctf_dtnextid = id.dtd_id + 1;
+  fp->ctf_snapshots = id.snapshot_id;
+
+  if (fp->ctf_snapshots == fp->ctf_snapshot_lu)
+    fp->ctf_flags &= ~LCTF_DIRTY;
+
+  return 0;
+}
+
+static ctf_id_t
+ctf_add_generic (ctf_file_t *fp, uint32_t flag, const char *name,
+		 ctf_dtdef_t **rp)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  char *s = NULL;
+
+  if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_dtnextid, 1) > CTF_MAX_TYPE)
+    return (ctf_set_errno (fp, ECTF_FULL));
+
+  if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_dtnextid, 1) == CTF_MAX_PTYPE)
+    return (ctf_set_errno (fp, ECTF_FULL));
+
+  if ((dtd = ctf_alloc (sizeof (ctf_dtdef_t))) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  if (name != NULL && (s = ctf_strdup (name)) == NULL)
+    {
+      ctf_free (dtd, sizeof (ctf_dtdef_t));
+      return (ctf_set_errno (fp, EAGAIN));
+    }
+
+  type = fp->ctf_dtnextid++;
+  type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD));
+
+  memset (dtd, 0, sizeof (ctf_dtdef_t));
+  dtd->dtd_name = s;
+  dtd->dtd_type = type;
+
+  if (s != NULL)
+    fp->ctf_dtvstrlen += strlen (s) + 1;
+
+  ctf_dtd_insert (fp, dtd);
+  fp->ctf_flags |= LCTF_DIRTY;
+
+  *rp = dtd;
+  return type;
+}
+
+/* When encoding integer sizes, we want to convert a byte count in the range
+   1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
+   is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.  */
+static size_t
+clp2 (size_t x)
+{
+  x--;
+
+  x |= (x >> 1);
+  x |= (x >> 2);
+  x |= (x >> 4);
+  x |= (x >> 8);
+  x |= (x >> 16);
+
+  return (x + 1);
+}
+
+static ctf_id_t
+ctf_add_encoded (ctf_file_t *fp, uint32_t flag,
+		 const char *name, const ctf_encoding_t *ep, uint32_t kind)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+
+  if (ep == NULL)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
+  dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, NBBY) / NBBY);
+  dtd->dtd_u.dtu_enc = *ep;
+
+  return type;
+}
+
+static ctf_id_t
+ctf_add_reftype (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  ctf_file_t *tmp = fp;
+
+  if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (ctf_lookup_by_id (&tmp, ref) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
+  dtd->dtd_data.ctt_type = (uint32_t) ref;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_slice (ctf_file_t *fp, uint32_t flag, ctf_id_t ref,
+	       const ctf_encoding_t *ep)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  int kind;
+  const ctf_type_t *tp;
+  ctf_file_t *tmp = fp;
+
+  if (ep == NULL)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
+    return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
+
+  if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  kind = ctf_type_kind_unsliced (tmp, ref);
+  if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
+      (kind != CTF_K_ENUM))
+    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+
+  if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
+  dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, NBBY) / NBBY);
+  dtd->dtd_u.dtu_slice.cts_type = ref;
+  dtd->dtd_u.dtu_slice.cts_bits = ep->cte_bits;
+  dtd->dtd_u.dtu_slice.cts_offset = ep->cte_offset;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_integer (ctf_file_t *fp, uint32_t flag,
+		 const char *name, const ctf_encoding_t *ep)
+{
+  return (ctf_add_encoded (fp, flag, name, ep, CTF_K_INTEGER));
+}
+
+ctf_id_t
+ctf_add_float (ctf_file_t *fp, uint32_t flag,
+	       const char *name, const ctf_encoding_t *ep)
+{
+  return (ctf_add_encoded (fp, flag, name, ep, CTF_K_FLOAT));
+}
+
+ctf_id_t
+ctf_add_pointer (ctf_file_t *fp, uint32_t flag, ctf_id_t ref)
+{
+  return (ctf_add_reftype (fp, flag, ref, CTF_K_POINTER));
+}
+
+ctf_id_t
+ctf_add_array (ctf_file_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  ctf_file_t *tmp = fp;
+
+  if (arp == NULL)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  tmp = fp;
+  if (ctf_lookup_by_id (&tmp, arp->ctr_index) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
+  dtd->dtd_data.ctt_size = 0;
+  dtd->dtd_u.dtu_arr = *arp;
+
+  return type;
+}
+
+int
+ctf_set_array (ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
+{
+  ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (dtd == NULL
+      || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
+    return (ctf_set_errno (fp, ECTF_BADID));
+
+  fp->ctf_flags |= LCTF_DIRTY;
+  dtd->dtd_u.dtu_arr = *arp;
+
+  return 0;
+}
+
+ctf_id_t
+ctf_add_function (ctf_file_t *fp, uint32_t flag,
+		  const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  uint32_t vlen;
+  ctf_id_t *vdat = NULL;
+  ctf_file_t *tmp = fp;
+  size_t i;
+
+  if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
+      || (ctc->ctc_argc != 0 && argv == NULL))
+    return (ctf_set_errno (fp, EINVAL));
+
+  vlen = ctc->ctc_argc;
+  if (ctc->ctc_flags & CTF_FUNC_VARARG)
+    vlen++;	       /* Add trailing zero to indicate varargs (see below).  */
+
+  if (ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  for (i = 0; i < ctc->ctc_argc; i++)
+    {
+      tmp = fp;
+      if (ctf_lookup_by_id (&tmp, argv[i]) == NULL)
+	return CTF_ERR;		/* errno is set for us.  */
+    }
+
+  if (vlen > CTF_MAX_VLEN)
+    return (ctf_set_errno (fp, EOVERFLOW));
+
+  if (vlen != 0 && (vdat = ctf_alloc (sizeof (ctf_id_t) * vlen)) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  if ((type = ctf_add_generic (fp, flag, NULL, &dtd)) == CTF_ERR)
+    {
+      ctf_free (vdat, sizeof (ctf_id_t) * vlen);
+      return CTF_ERR;		   /* errno is set for us.  */
+    }
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
+  dtd->dtd_data.ctt_type = (uint32_t) ctc->ctc_return;
+
+  memcpy (vdat, argv, sizeof (ctf_id_t) * ctc->ctc_argc);
+  if (ctc->ctc_flags & CTF_FUNC_VARARG)
+    vdat[vlen - 1] = 0;		   /* Add trailing zero to indicate varargs.  */
+  dtd->dtd_u.dtu_argv = vdat;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_struct_sized (ctf_file_t *fp, uint32_t flag, const char *name,
+		      size_t size)
+{
+  ctf_hash_t *hp = fp->ctf_structs;
+  ctf_dtdef_t *dtd;
+  ctf_id_t type = 0;
+
+  /* Promote forwards to structs.  */
+
+  if (name != NULL)
+    {
+      type = ctf_hash_lookup_type (hp, fp, name);
+      if (type == 0)
+	type = ctf_dtd_lookup_type_by_name (fp, CTF_K_STRUCT, name);
+    }
+
+  if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
+    dtd = ctf_dtd_lookup (fp, type);
+  else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
+
+  if (size > CTF_MAX_SIZE)
+    {
+      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+    }
+  else
+    dtd->dtd_data.ctt_size = (uint32_t) size;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_struct (ctf_file_t *fp, uint32_t flag, const char *name)
+{
+  return (ctf_add_struct_sized (fp, flag, name, 0));
+}
+
+ctf_id_t
+ctf_add_union_sized (ctf_file_t *fp, uint32_t flag, const char *name,
+		     size_t size)
+{
+  ctf_hash_t *hp = fp->ctf_unions;
+  ctf_dtdef_t *dtd;
+  ctf_id_t type = 0;
+
+  /* Promote forwards to unions.  */
+  if (name != NULL)
+    {
+      type = ctf_hash_lookup_type (hp, fp, name);
+      if (type == 0)
+	type = ctf_dtd_lookup_type_by_name (fp, CTF_K_UNION, name);
+    }
+
+  if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
+    dtd = ctf_dtd_lookup (fp, type);
+  else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
+
+  if (size > CTF_MAX_SIZE)
+    {
+      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+    }
+  else
+    dtd->dtd_data.ctt_size = (uint32_t) size;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_union (ctf_file_t *fp, uint32_t flag, const char *name)
+{
+  return (ctf_add_union_sized (fp, flag, name, 0));
+}
+
+ctf_id_t
+ctf_add_enum (ctf_file_t *fp, uint32_t flag, const char *name)
+{
+  ctf_hash_t *hp = fp->ctf_enums;
+  ctf_dtdef_t *dtd;
+  ctf_id_t type = 0;
+
+  /* Promote forwards to enums.  */
+  if (name != NULL)
+    {
+      type = ctf_hash_lookup_type (hp, fp, name);
+      if (type == 0)
+	type = ctf_dtd_lookup_type_by_name (fp, CTF_K_ENUM, name);
+    }
+
+  if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
+    dtd = ctf_dtd_lookup (fp, type);
+  else if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
+  dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_enum_encoded (ctf_file_t *fp, uint32_t flag, const char *name,
+		      const ctf_encoding_t *ep)
+{
+  ctf_hash_t *hp = fp->ctf_enums;
+  ctf_id_t type = 0;
+
+  /* First, create the enum if need be, using most of the same machinery as
+     ctf_add_enum(), to ensure that we do not allow things past that are not
+     enums or forwards to them.  (This includes other slices: you cannot slice a
+     slice, which would be a useless thing to do anyway.)  */
+
+  if (name != NULL)
+    {
+      type = ctf_hash_lookup_type (hp, fp, name);
+      if (type == 0)
+	type = ctf_dtd_lookup_type_by_name (fp, CTF_K_ENUM, name);
+    }
+
+  if (type != 0)
+    {
+      if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
+	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
+	return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    }
+  else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  /* Now attach a suitable slice to it.  */
+
+  return ctf_add_slice (fp, flag, type, ep);
+}
+
+ctf_id_t
+ctf_add_forward (ctf_file_t *fp, uint32_t flag, const char *name,
+		 uint32_t kind)
+{
+  ctf_hash_t *hp;
+  ctf_dtdef_t *dtd;
+  ctf_id_t type = 0;
+
+  switch (kind)
+    {
+    case CTF_K_STRUCT:
+      hp = fp->ctf_structs;
+      break;
+    case CTF_K_UNION:
+      hp = fp->ctf_unions;
+      break;
+    case CTF_K_ENUM:
+      hp = fp->ctf_enums;
+      break;
+    default:
+      return (ctf_set_errno (fp, ECTF_NOTSUE));
+    }
+
+  /* If the type is already defined or exists as a forward tag, just
+     return the ctf_id_t of the existing definition.  */
+
+  if (name != NULL)
+    {
+      if (((type = ctf_hash_lookup_type (hp, fp, name)) != 0)
+	  || (type = ctf_dtd_lookup_type_by_name (fp, kind, name)) != 0)
+	return type;
+    }
+
+  if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
+  dtd->dtd_data.ctt_type = kind;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_typedef (ctf_file_t *fp, uint32_t flag, const char *name,
+		 ctf_id_t ref)
+{
+  ctf_dtdef_t *dtd;
+  ctf_id_t type;
+  ctf_file_t *tmp = fp;
+
+  if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (ctf_lookup_by_id (&tmp, ref) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((type = ctf_add_generic (fp, flag, name, &dtd)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0);
+  dtd->dtd_data.ctt_type = (uint32_t) ref;
+
+  return type;
+}
+
+ctf_id_t
+ctf_add_volatile (ctf_file_t *fp, uint32_t flag, ctf_id_t ref)
+{
+  return (ctf_add_reftype (fp, flag, ref, CTF_K_VOLATILE));
+}
+
+ctf_id_t
+ctf_add_const (ctf_file_t *fp, uint32_t flag, ctf_id_t ref)
+{
+  return (ctf_add_reftype (fp, flag, ref, CTF_K_CONST));
+}
+
+ctf_id_t
+ctf_add_restrict (ctf_file_t *fp, uint32_t flag, ctf_id_t ref)
+{
+  return (ctf_add_reftype (fp, flag, ref, CTF_K_RESTRICT));
+}
+
+int
+ctf_add_enumerator (ctf_file_t *fp, ctf_id_t enid, const char *name,
+		    int value)
+{
+  ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
+  ctf_dmdef_t *dmd;
+
+  uint32_t kind, vlen, root;
+  char *s;
+
+  if (name == NULL)
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (dtd == NULL)
+    return (ctf_set_errno (fp, ECTF_BADID));
+
+  kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+  root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
+  vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+  if (kind != CTF_K_ENUM)
+    return (ctf_set_errno (fp, ECTF_NOTENUM));
+
+  if (vlen == CTF_MAX_VLEN)
+    return (ctf_set_errno (fp, ECTF_DTFULL));
+
+  for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+       dmd != NULL; dmd = ctf_list_next (dmd))
+    {
+      if (strcmp (dmd->dmd_name, name) == 0)
+	return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    }
+
+  if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  if ((s = ctf_strdup (name)) == NULL)
+    {
+      ctf_free (dmd, sizeof (ctf_dmdef_t));
+      return (ctf_set_errno (fp, EAGAIN));
+    }
+
+  dmd->dmd_name = s;
+  dmd->dmd_type = CTF_ERR;
+  dmd->dmd_offset = 0;
+  dmd->dmd_value = value;
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+  ctf_list_append (&dtd->dtd_u.dtu_members, dmd);
+
+  fp->ctf_dtvstrlen += strlen (s) + 1;
+  fp->ctf_flags |= LCTF_DIRTY;
+
+  return 0;
+}
+
+int
+ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
+		       ctf_id_t type, unsigned long bit_offset)
+{
+  ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid);
+  ctf_dmdef_t *dmd;
+
+  ssize_t msize, malign, ssize;
+  uint32_t kind, vlen, root;
+  char *s = NULL;
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (dtd == NULL)
+    return (ctf_set_errno (fp, ECTF_BADID));
+
+  kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+  root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
+  vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+  if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
+    return (ctf_set_errno (fp, ECTF_NOTSOU));
+
+  if (vlen == CTF_MAX_VLEN)
+    return (ctf_set_errno (fp, ECTF_DTFULL));
+
+  if (name != NULL)
+    {
+      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+	   dmd != NULL; dmd = ctf_list_next (dmd))
+	{
+	  if (dmd->dmd_name != NULL && strcmp (dmd->dmd_name, name) == 0)
+	    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	}
+    }
+
+  if ((msize = ctf_type_size (fp, type)) == CTF_ERR ||
+      (malign = ctf_type_align (fp, type)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  if (name != NULL && (s = ctf_strdup (name)) == NULL)
+    {
+      ctf_free (dmd, sizeof (ctf_dmdef_t));
+      return (ctf_set_errno (fp, EAGAIN));
+    }
+
+  dmd->dmd_name = s;
+  dmd->dmd_type = type;
+  dmd->dmd_value = -1;
+
+  if (kind == CTF_K_STRUCT && vlen != 0)
+    {
+      if (bit_offset == (unsigned long) - 1)
+	{
+	  /* Natural alignment.  */
+
+	  ctf_dmdef_t *lmd = ctf_list_prev (&dtd->dtd_u.dtu_members);
+	  ctf_id_t ltype = ctf_type_resolve (fp, lmd->dmd_type);
+	  size_t off = lmd->dmd_offset;
+
+	  ctf_encoding_t linfo;
+	  ssize_t lsize;
+
+	  if (ctf_type_encoding (fp, ltype, &linfo) != CTF_ERR)
+	    off += linfo.cte_bits;
+	  else if ((lsize = ctf_type_size (fp, ltype)) != CTF_ERR)
+	    off += lsize * NBBY;
+
+	  /* Round up the offset of the end of the last member to
+	     the next byte boundary, convert 'off' to bytes, and
+	     then round it up again to the next multiple of the
+	     alignment required by the new member.  Finally,
+	     convert back to bits and store the result in
+	     dmd_offset.  Technically we could do more efficient
+	     packing if the new member is a bit-field, but we're
+	     the "compiler" and ANSI says we can do as we choose.  */
+
+	  off = roundup (off, NBBY) / NBBY;
+	  off = roundup (off, MAX (malign, 1));
+	  dmd->dmd_offset = off * NBBY;
+	  ssize = off + msize;
+	}
+      else
+	{
+	  /* Specified offset in bits.  */
+
+	  dmd->dmd_offset = bit_offset;
+	  ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
+	  ssize = MAX (ssize, (bit_offset / NBBY) + msize);
+	}
+    }
+  else
+    {
+      dmd->dmd_offset = 0;
+      ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
+      ssize = MAX (ssize, msize);
+    }
+
+  if (ssize > CTF_MAX_SIZE)
+    {
+      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
+      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize);
+    }
+  else
+    dtd->dtd_data.ctt_size = (uint32_t) ssize;
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+  ctf_list_append (&dtd->dtd_u.dtu_members, dmd);
+
+  if (s != NULL)
+    fp->ctf_dtvstrlen += strlen (s) + 1;
+
+  fp->ctf_flags |= LCTF_DIRTY;
+  return 0;
+}
+
+int
+ctf_add_member_encoded (ctf_file_t *fp, ctf_id_t souid, const char *name,
+			ctf_id_t type, unsigned long bit_offset,
+			const ctf_encoding_t encoding)
+{
+  ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
+  int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+  int otype = type;
+
+  if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
+    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+
+  if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  return ctf_add_member_offset (fp, souid, name, type, bit_offset);
+}
+
+int
+ctf_add_member (ctf_file_t *fp, ctf_id_t souid, const char *name,
+		ctf_id_t type)
+{
+  return ctf_add_member_offset (fp, souid, name, type, (unsigned long) - 1);
+}
+
+int
+ctf_add_variable (ctf_file_t *fp, const char *name, ctf_id_t ref)
+{
+  ctf_dvdef_t *dvd;
+  ctf_file_t *tmp = fp;
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  if (ctf_dvd_lookup (fp, name) != NULL)
+    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+
+  if (ctf_lookup_by_id (&tmp, ref) == NULL)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if ((dvd = ctf_alloc (sizeof (ctf_dvdef_t))) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  if (name != NULL && (dvd->dvd_name = ctf_strdup (name)) == NULL)
+    {
+      ctf_free (dvd, sizeof (ctf_dvdef_t));
+      return (ctf_set_errno (fp, EAGAIN));
+    }
+  dvd->dvd_type = ref;
+  dvd->dvd_snapshots = fp->ctf_snapshots;
+
+  ctf_dvd_insert (fp, dvd);
+
+  fp->ctf_dtvstrlen += strlen (name) + 1;
+  fp->ctf_flags |= LCTF_DIRTY;
+  return 0;
+}
diff --git a/libctf/ctf-lib.c b/libctf/ctf-lib.c
index 1e81f3d20e..afe9cbefa6 100644
--- a/libctf/ctf-lib.c
+++ b/libctf/ctf-lib.c
@@ -18,9 +18,117 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <ctf-impl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <zlib.h>
 
 _libctf_constructor_(_libctf_init)
 static void _libctf_init (void)
 {
   _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL;
 }
+
+/* Write the compressed CTF data stream to the specified gzFile descriptor.
+   This is useful for saving the results of dynamic CTF containers.  */
+int
+ctf_gzwrite (ctf_file_t *fp, gzFile fd)
+{
+  const unsigned char *buf = fp->ctf_base;
+  ssize_t resid = fp->ctf_size;
+  ssize_t len;
+
+  while (resid != 0)
+    {
+      if ((len = gzwrite (fd, buf, resid)) <= 0)
+	return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  return 0;
+}
+
+/* Compress the specified CTF data stream and write it to the specified file
+   descriptor.  */
+int
+ctf_compress_write (ctf_file_t *fp, int fd)
+{
+  unsigned char *buf;
+  unsigned char *bp;
+  ctf_header_t h;
+  ctf_header_t *hp = &h;
+  ssize_t header_len = sizeof (ctf_header_t);
+  ssize_t compress_len;
+  size_t max_compress_len = compressBound (fp->ctf_size - header_len);
+  ssize_t len;
+  int rc;
+  int err = 0;
+
+  memcpy (hp, fp->ctf_base, header_len);
+  hp->cth_flags |= CTF_F_COMPRESS;
+
+  if ((buf = ctf_data_alloc (max_compress_len)) == MAP_FAILED)
+    return (ctf_set_errno (fp, ECTF_ZALLOC));
+
+  compress_len = max_compress_len;
+  if ((rc = compress (buf, (uLongf *) & compress_len,
+		      fp->ctf_base + header_len,
+		      fp->ctf_size - header_len)) != Z_OK)
+    {
+      ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
+      err = ctf_set_errno (fp, ECTF_COMPRESS);
+      goto ret;
+    }
+
+  while (header_len > 0)
+    {
+      if ((len = write (fd, hp, header_len)) < 0)
+	{
+	  err = ctf_set_errno (fp, errno);
+	  goto ret;
+	}
+      header_len -= len;
+      hp += len;
+    }
+
+  bp = buf;
+  while (compress_len > 0)
+    {
+      if ((len = write (fd, bp, compress_len)) < 0)
+	{
+	  err = ctf_set_errno (fp, errno);
+	  goto ret;
+	}
+      compress_len -= len;
+      bp += len;
+    }
+
+ret:
+  ctf_data_free (buf, max_compress_len);
+  return err;
+}
+
+/* Write the uncompressed CTF data stream to the specified file descriptor.
+   This is useful for saving the results of dynamic CTF containers.  */
+int
+ctf_write (ctf_file_t *fp, int fd)
+{
+  const unsigned char *buf = fp->ctf_base;
+  ssize_t resid = fp->ctf_size;
+  ssize_t len;
+
+  while (resid != 0)
+    {
+      if ((len = write (fd, buf, resid)) < 0)
+	return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  return 0;
+}
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
new file mode 100644
index 0000000000..042d632ff2
--- /dev/null
+++ b/libctf/ctf-lookup.c
@@ -0,0 +1,63 @@
+/* Type lookup.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <gelf.h>
+#include <string.h>
+
+/* Return the pointer to the internal CTF type data corresponding to the
+   given type ID.  If the ID is invalid, the function returns NULL.
+   This function is not exported outside of the library.  */
+
+const ctf_type_t *
+ctf_lookup_by_id (ctf_file_t **fpp, ctf_id_t type)
+{
+  ctf_file_t *fp = *fpp;	/* Caller passes in starting CTF container.  */
+  ctf_id_t idx;
+
+  if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type)
+      && (fp = fp->ctf_parent) == NULL)
+    {
+      (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
+      return NULL;
+    }
+
+  idx = LCTF_TYPE_TO_INDEX (fp, type);
+  if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax)
+    {
+      *fpp = fp;		/* Function returns ending CTF container.  */
+      return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
+    }
+
+  /* If this container is writable, check for a dynamic type.  */
+
+  if (fp->ctf_flags & LCTF_RDWR)
+    {
+      ctf_dtdef_t *dtd;
+
+      if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
+	{
+	  *fpp = fp;
+	  return &dtd->dtd_data;
+	}
+    }
+  (void) ctf_set_errno (*fpp, ECTF_BADID);
+  return NULL;
+}
+
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 10/19] libctf: ELF file opening
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (6 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 06/19] libctf: hashing Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 19/19] binutils: CTF support for objdump and readelf Nick Alcock
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

These functions let you open an ELF file with a customarily-named CTF
section in it, automatically opening the CTF file and associating the
symbol and string tables in the ELF file with the CTF container, so that
you can look up the types of symbols in the ELF file via
ctf_lookup_by_symbol(), and so that strings can be shared between the
ELF file and CTF container, to save space.

These functions are both quite rusty (unused since 2009, though nothing
has changed that should have broken them) and likely to change in the
near future, since the naming of CTF sections in this implementation has
not been nailed down yet -- it is likely there will be many of them, one
per translation unit, plus one shared across many TUs, so ctf_open() and
ctf_fdopen() will probably grow a parameter indicating which of the many
possible CTF containers is wanted, as well as a variant returning an
array or a hash allowing you to open all of them at once.

I am amenable to dropping these functions for now, until things are more
nailed down, but introducing them here helps answer people's questions
about what the function with the obvious name of ctf_open() does. :)

libctf/
	* ctf-lib.c (_PAGESIZE): New.
	(_PAGEMASK): Likewise.
	(_libctf_init): Populate them.
	(ehdr_to_gelf): New.
	(shdr_to_gelf): Likewise.
	(ctf_sect_mmap): Likewise.
	(ctf_sect_munmap): Likewise.
	(ctf_fdopen): Likewise.
	(ctf_open): Likewise.
	* ctf-impl.h: New definitions.

include/
	* ctf-api.h (ctf_fdopen): New.
	(ctf_open): Likewise.
---
 include/ctf-api.h |   2 +
 libctf/ctf-impl.h |   3 +
 libctf/ctf-lib.c  | 346 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 351 insertions(+)

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 4329c6b2f7..f1a786f451 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -202,6 +202,8 @@ extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
 				   size_t, const char *, size_t, int *);
 extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
 				const ctf_sect_t *, int *);
+extern ctf_file_t *ctf_fdopen (int, int *);
+extern ctf_file_t *ctf_open (const char *, int *);
 extern ctf_file_t *ctf_create (int *);
 extern void ctf_close (ctf_file_t *);
 extern ctf_sect_t ctf_getdatasect (const ctf_file_t *);
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 0d33cdb01e..2f8caed228 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -314,6 +314,9 @@ extern const char *ctf_strptr (ctf_file_t *, uint32_t);
 extern ctf_file_t *ctf_set_open_errno (int *, int);
 extern long ctf_set_errno (ctf_file_t *, int);
 
+extern const void *ctf_sect_mmap (ctf_sect_t *, int);
+extern void ctf_sect_munmap (const ctf_sect_t *);
+
 extern void *ctf_data_alloc (size_t);
 extern void ctf_data_free (void *, size_t);
 extern void ctf_data_protect (void *, size_t);
diff --git a/libctf/ctf-lib.c b/libctf/ctf-lib.c
index afe9cbefa6..e60d2c985b 100644
--- a/libctf/ctf-lib.c
+++ b/libctf/ctf-lib.c
@@ -25,12 +25,358 @@
 #include <string.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <dlfcn.h>
+#include <endian.h>
+#include <gelf.h>
 #include <zlib.h>
 
+static size_t _PAGESIZE;
+static size_t _PAGEMASK;
+
 _libctf_constructor_(_libctf_init)
 static void _libctf_init (void)
 {
   _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL;
+
+  _PAGESIZE = getpagesize ();
+  _PAGEMASK = ~(_PAGESIZE - 1);
+}
+
+/* Convert a 32-bit ELF file header into GElf.  */
+
+static void
+ehdr_to_gelf (const Elf32_Ehdr *src, GElf_Ehdr *dst)
+{
+  memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
+  dst->e_type = src->e_type;
+  dst->e_machine = src->e_machine;
+  dst->e_version = src->e_version;
+  dst->e_entry = (Elf64_Addr) src->e_entry;
+  dst->e_phoff = (Elf64_Off) src->e_phoff;
+  dst->e_shoff = (Elf64_Off) src->e_shoff;
+  dst->e_flags = src->e_flags;
+  dst->e_ehsize = src->e_ehsize;
+  dst->e_phentsize = src->e_phentsize;
+  dst->e_phnum = src->e_phnum;
+  dst->e_shentsize = src->e_shentsize;
+  dst->e_shnum = src->e_shnum;
+  dst->e_shstrndx = src->e_shstrndx;
+}
+
+/* Convert a 32-bit ELF section header into GElf.  */
+
+static void
+shdr_to_gelf (const Elf32_Shdr *src, GElf_Shdr *dst)
+{
+  dst->sh_name = src->sh_name;
+  dst->sh_type = src->sh_type;
+  dst->sh_flags = src->sh_flags;
+  dst->sh_addr = src->sh_addr;
+  dst->sh_offset = src->sh_offset;
+  dst->sh_size = src->sh_size;
+  dst->sh_link = src->sh_link;
+  dst->sh_info = src->sh_info;
+  dst->sh_addralign = src->sh_addralign;
+  dst->sh_entsize = src->sh_entsize;
+}
+
+/* In order to mmap a section from the ELF file, we must round down sh_offset
+   to the previous page boundary, and mmap the surrounding page.  We store
+   the pointer to the start of the actual section data back into sp->cts_data.  */
+
+const void *
+ctf_sect_mmap (ctf_sect_t *sp, int fd)
+{
+  size_t pageoff = sp->cts_offset & ~_PAGEMASK;
+
+  caddr_t base = mmap (NULL, sp->cts_size + pageoff, PROT_READ,
+		       MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
+
+  if (base != MAP_FAILED)
+    sp->cts_data = base + pageoff;
+
+  return base;
+}
+
+/* Since sp->cts_data has the adjusted offset, we have to again round down
+   to get the actual mmap address and round up to get the size.  */
+
+void
+ctf_sect_munmap (const ctf_sect_t *sp)
+{
+  uintptr_t addr = (uintptr_t) sp->cts_data;
+  uintptr_t pageoff = addr & ~_PAGEMASK;
+
+  (void) munmap ((void *) (addr - pageoff), sp->cts_size + pageoff);
+}
+
+/* Open the specified file descriptor and return a pointer to a CTF container.
+   The file can be either an ELF file or raw CTF file.  The caller is
+   responsible for closing the file descriptor when it is no longer needed.  */
+
+ctf_file_t *
+ctf_fdopen (int fd, int *errp)
+{
+  ctf_sect_t ctfsect, symsect, strsect;
+  ctf_file_t *fp = NULL;
+
+  struct stat st;
+  ssize_t nbytes;
+
+  union
+  {
+    ctf_preamble_t ctf;
+    Elf32_Ehdr e32;
+    GElf_Ehdr e64;
+  } hdr;
+
+  memset (&ctfsect, 0, sizeof (ctf_sect_t));
+  memset (&symsect, 0, sizeof (ctf_sect_t));
+  memset (&strsect, 0, sizeof (ctf_sect_t));
+  memset (&hdr.ctf, 0, sizeof (hdr));
+
+  if (fstat (fd, &st) == -1)
+    return (ctf_set_open_errno (errp, errno));
+
+  if ((nbytes = pread (fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
+    return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT));
+
+  /*
+   * If we have read enough bytes to form a CTF header and the magic
+   * string matches, attempt to interpret the file as raw CTF.
+   */
+  if ((size_t) nbytes >= sizeof (ctf_preamble_t) &&
+      hdr.ctf.ctp_magic == CTF_MAGIC)
+    {
+      void *data;
+
+      if (hdr.ctf.ctp_version > CTF_VERSION)
+	return (ctf_set_open_errno (errp, ECTF_CTFVERS));
+
+      data = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+      if (data == MAP_FAILED)
+	return (ctf_set_open_errno (errp, errno));
+
+      ctfsect.cts_name = _CTF_SECTION;
+      ctfsect.cts_type = SHT_PROGBITS;
+      ctfsect.cts_flags = SHF_ALLOC;
+      ctfsect.cts_size = (size_t) st.st_size;
+      ctfsect.cts_entsize = 1;
+      ctfsect.cts_offset = 0;
+
+      if ((fp = ctf_simple_open (data, (size_t) st.st_size, NULL, 0, 0,
+				 NULL, 0, errp)) == NULL)
+	ctf_sect_munmap (&ctfsect);
+
+      return fp;
+    }
+
+  /* If we have read enough bytes to form an ELF header and the magic
+     string matches, attempt to interpret the file as an ELF file.  We
+     do our own largefile ELF processing, and convert everything to
+     GElf structures so that clients can operate on any data model.  */
+
+  if ((size_t) nbytes >= sizeof (Elf32_Ehdr)
+     && memcmp (&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
+    {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      unsigned char order = ELFDATA2MSB;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+      unsigned char order = ELFDATA2LSB;
+#else
+#error Unknown endianness
+#endif
+      GElf_Half i, n;
+      GElf_Shdr *sp;
+
+      void *strs_map;
+      size_t strs_mapsz;
+      const char *strs;
+
+      if (hdr.e32.e_ident[EI_DATA] != order)
+	return (ctf_set_open_errno (errp, ECTF_ENDIAN));
+      if (hdr.e32.e_version != EV_CURRENT)
+	return (ctf_set_open_errno (errp, ECTF_ELFVERS));
+
+      if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64)
+	{
+	  if ((size_t) nbytes < sizeof (GElf_Ehdr))
+	    return (ctf_set_open_errno (errp, ECTF_FMT));
+	}
+      else
+	{
+	  Elf32_Ehdr e32 = hdr.e32;
+	  ehdr_to_gelf (&e32, &hdr.e64);
+	}
+
+      if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
+	return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+
+      n = hdr.e64.e_shnum;
+      nbytes = sizeof (GElf_Shdr) * n;
+
+      if ((sp = malloc (nbytes)) == NULL)
+	return (ctf_set_open_errno (errp, errno));
+
+      /* Read in and convert to GElf the array of Shdr structures
+	 from e_shoff so we can locate sections of interest.  */
+
+      if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
+	{
+	  Elf32_Shdr *sp32;
+
+	  nbytes = sizeof (Elf32_Shdr) * n;
+
+	  if ((sp32 = malloc (nbytes)) == NULL || pread (fd, sp32, nbytes,
+							 hdr.e64.e_shoff) !=
+	      nbytes)
+	    {
+	      free (sp);
+	      return (ctf_set_open_errno (errp, errno));
+	    }
+
+	  for (i = 0; i < n; i++)
+	    shdr_to_gelf (&sp32[i], &sp[i]);
+
+	  free (sp32);
+
+	}
+      else if (pread (fd, sp, nbytes, hdr.e64.e_shoff) != nbytes)
+	{
+	  free (sp);
+	  return (ctf_set_open_errno (errp, errno));
+	}
+
+      /* Now mmap the section header strings section so that we can
+         perform string comparison on the section names.  */
+
+      strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
+	(sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+
+      strs_map = mmap (NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
+		       fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
+
+      strs = (const char *) strs_map
+	+ (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+
+      if (strs_map == MAP_FAILED)
+	{
+	  free (sp);
+	  return (ctf_set_open_errno (errp, ECTF_MMAP));
+	}
+
+      /* Iterate over the section header array looking for the CTF
+	 section and symbol table.  The strtab is linked to symtab.  */
+
+      for (i = 0; i < n; i++)
+	{
+	  const GElf_Shdr *shp = &sp[i];
+	  const GElf_Shdr *lhp = &sp[shp->sh_link];
+
+	  if (shp->sh_link >= hdr.e64.e_shnum)
+	    continue;		/* Corrupt sh_link field.  */
+
+	  if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
+	      lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
+	    continue;		/* Corrupt sh_name field.  */
+
+	  if (shp->sh_type == SHT_PROGBITS
+	      && strcmp (strs + shp->sh_name, _CTF_SECTION) == 0)
+	    {
+	      ctfsect.cts_name = strs + shp->sh_name;
+	      ctfsect.cts_type = shp->sh_type;
+	      ctfsect.cts_flags = shp->sh_flags;
+	      ctfsect.cts_size = shp->sh_size;
+	      ctfsect.cts_entsize = shp->sh_entsize;
+	      ctfsect.cts_offset = (off64_t) shp->sh_offset;
+
+	    }
+	  else if (shp->sh_type == SHT_SYMTAB)
+	    {
+	      symsect.cts_name = strs + shp->sh_name;
+	      symsect.cts_type = shp->sh_type;
+	      symsect.cts_flags = shp->sh_flags;
+	      symsect.cts_size = shp->sh_size;
+	      symsect.cts_entsize = shp->sh_entsize;
+	      symsect.cts_offset = (off64_t) shp->sh_offset;
+
+	      strsect.cts_name = strs + lhp->sh_name;
+	      strsect.cts_type = lhp->sh_type;
+	      strsect.cts_flags = lhp->sh_flags;
+	      strsect.cts_size = lhp->sh_size;
+	      strsect.cts_entsize = lhp->sh_entsize;
+	      strsect.cts_offset = (off64_t) lhp->sh_offset;
+	    }
+	}
+
+      free (sp);		/* Free section header array.  */
+
+      if (ctfsect.cts_type == SHT_NULL)
+	{
+	  (void) munmap (strs_map, strs_mapsz);
+	  return (ctf_set_open_errno (errp, ECTF_NOCTFDATA));
+	}
+
+      /* Now mmap the CTF data, symtab, and strtab sections and
+	 call ctf_bufopen() to do the rest of the work.  */
+
+      if (ctf_sect_mmap (&ctfsect, fd) == MAP_FAILED)
+	{
+	  (void) munmap (strs_map, strs_mapsz);
+	  return (ctf_set_open_errno (errp, ECTF_MMAP));
+	}
+
+      if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL)
+	{
+	  if (ctf_sect_mmap (&symsect, fd) == MAP_FAILED ||
+	      ctf_sect_mmap (&strsect, fd) == MAP_FAILED)
+	    {
+	      (void) ctf_set_open_errno (errp, ECTF_MMAP);
+	      goto bad;
+	    }
+	  fp = ctf_bufopen (&ctfsect, &symsect, &strsect, errp);
+	}
+      else
+	fp = ctf_bufopen (&ctfsect, NULL, NULL, errp);
+
+    bad:
+      /* Unmap all and abort.  */
+      if (fp == NULL)
+	{
+	  ctf_sect_munmap (&ctfsect);
+	  ctf_sect_munmap (&symsect);
+	  ctf_sect_munmap (&strsect);
+	}
+      else
+	fp->ctf_flags |= LCTF_MMAP;
+
+      (void) munmap (strs_map, strs_mapsz);
+      return fp;
+    }
+
+  return (ctf_set_open_errno (errp, ECTF_FMT));
+}
+
+/* Open the specified file and return a pointer to a CTF container.  The file
+   can be either an ELF file or raw CTF file.  This is just a convenient
+   wrapper around ctf_fdopen() for callers.  */
+ctf_file_t *
+ctf_open (const char *filename, int *errp)
+{
+  ctf_file_t *fp;
+  int fd;
+
+  if ((fd = open (filename, O_RDONLY)) == -1)
+    {
+      if (errp != NULL)
+	*errp = errno;
+      return NULL;
+    }
+
+  fp = ctf_fdopen (fd, errp);
+  (void) close (fd);
+  return fp;
 }
 
 /* Write the compressed CTF data stream to the specified gzFile descriptor.
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (14 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 12/19] libctf: lookups by name and symbol Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-02 15:29   ` Nick Clifton
  2019-04-30 22:58 ` [PATCH 18/19] libctf: build system Nick Alcock
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

Note for reviewers:

I could easily be convinced that all of these wrappers serve no purpose
and should be globally removed, but the debugging tracer is frequently
useful, and the malloc/free/mmap/munmap wrappers have proved mildly
useful in conjunction with symbol interposition for allocation debugging
in the (relatively distant) past.

(The debugging dumper is initialized via an ELF constructor in a different
TU, ctf-lib.c, because this ELF constructor also does other things, mostly
specific ctf-lib.c, which will be introduced in later commits, and we wanted
to keep the number of ELF constructors down.)

(I am amenable to replacing the environment-variable triggering of
ctf_dprintf() with something else in the binutils commit, and dropping
the other wrappers entirely, if you prefer.  If some other way of triggering
debugging trace output is preferred, or if the tracer should be replaced with
a do-nothing wrapper in binutils, that is fine too.)

libctf/
	* ctf-impl.h: New file.
	* ctf-lib.c: New file.
	* ctf-subr.c: New file.
---
 libctf/ctf-impl.h | 71 +++++++++++++++++++++++++++++++++++++++++++++
 libctf/ctf-lib.c  | 26 +++++++++++++++++
 libctf/ctf-subr.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 libctf/ctf-impl.h
 create mode 100644 libctf/ctf-lib.c
 create mode 100644 libctf/ctf-subr.c

diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
new file mode 100644
index 0000000000..108c89d2c5
--- /dev/null
+++ b/libctf/ctf-impl.h
@@ -0,0 +1,71 @@
+/* Implementation header.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_CTF_IMPL_H
+#define	_CTF_IMPL_H
+
+#include "config.h"
+#include <sys/errno.h>
+#include <ctf-api.h>
+#include <sys/types.h>
+
+#ifdef	__cplusplus
+extern "C"
+  {
+#endif
+
+/* Compiler attributes.  */
+
+#if defined (__GNUC__)
+
+/* GCC.  We assume that all compilers claiming to be GCC support sufficiently
+   many GCC attributes that the code below works.  If some non-GCC compilers
+   masquerading as GCC in fact do not implement these attributes, version checks
+   may be required.  */
+
+/* We use the _libctf_*_ pattern to avoid clashes with any future attribute
+   macros glibc may introduce, which have names of the pattern
+   __attribute_blah__.  */
+
+#define _libctf_constructor_(x) __attribute__ ((__constructor__))
+#define _libctf_destructor_(x) __attribute__ ((__destructor__))
+#define _libctf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+#define _libctf_unlikely_(x) __builtin_expect ((x), 0)
+#define _libctf_unused_ __attribute__ ((__unused__))
+
+#endif
+
+extern void *ctf_data_alloc (size_t);
+extern void ctf_data_free (void *, size_t);
+extern void ctf_data_protect (void *, size_t);
+
+extern void *ctf_alloc (size_t);
+extern void ctf_free (void *, size_t);
+
+_libctf_printflike_ (1, 2)
+extern void ctf_dprintf (const char *, ...);
+
+extern int _libctf_debug;	/* debugging messages enabled */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _CTF_IMPL_H */
diff --git a/libctf/ctf-lib.c b/libctf/ctf-lib.c
new file mode 100644
index 0000000000..1e81f3d20e
--- /dev/null
+++ b/libctf/ctf-lib.c
@@ -0,0 +1,26 @@
+/* Miscellary.
+   Copyright (C) 2003-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+
+_libctf_constructor_(_libctf_init)
+static void _libctf_init (void)
+{
+  _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL;
+}
diff --git a/libctf/ctf-subr.c b/libctf/ctf-subr.c
new file mode 100644
index 0000000000..f358298b7d
--- /dev/null
+++ b/libctf/ctf-subr.c
@@ -0,0 +1,74 @@
+/* Simple subrs.
+   Copyright (C) 2003-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <string.h>
+
+void *
+ctf_data_alloc (size_t size)
+{
+  return (mmap (NULL, size, PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANON, -1, 0));
+}
+
+void
+ctf_data_free (void *buf, size_t size)
+{
+  (void) munmap (buf, size);
+}
+
+void
+ctf_data_protect (void *buf, size_t size)
+{
+  (void) mprotect (buf, size, PROT_READ);
+}
+
+void *
+ctf_alloc (size_t size)
+{
+  return (malloc (size));
+}
+
+void
+ctf_free (void *buf, size_t size _libctf_unused_)
+{
+  free (buf);
+}
+
+const char *
+ctf_strerror (int err)
+{
+  return (const char *) (strerror (err));
+}
+
+_libctf_printflike_ (1, 2)
+void ctf_dprintf (const char *format, ...)
+{
+  if (_libctf_debug)
+    {
+      va_list alist;
+
+      va_start (alist, format);
+      (void) fputs ("libctf DEBUG: ", stderr);
+      (void) vfprintf (stderr, format, alist);
+      va_end (alist);
+    }
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* CTF format overview
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (8 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 19/19] binutils: CTF support for objdump and readelf Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 08/19] libctf: creation functions Nick Alcock
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

CTF FILE FORMAT
---------------

A CTF file ("container", since it is usually not a file, but an ELF section or
something or that sort) is divided into a number of sections internally,
identified by offset from the header. In order, the sections are:

 - Type label section
 - Data object section
 - Function info section
 - Variable info section
 - Data type section
 - String table

We'll consider these in order of importance (not the same as order in the file).

Other things in the header:
  - a preamble containing a magic number (used to determine container
    endianness: libctf will endian-flip foreign-endian containers into the
    native endianness at open time), a version number, whose current value is
    the CTF_VERSION constant, and a set of CTF_F global flags
  - a parent container name and label, which indicates (in some
    consumer-dependent way) the name of the container containing types whose ID
    has its MSB turned on (the "parent container"): it is only nonzero if this
    container is not itself a parent.  This allows types to be shared between
    containers: with one container being the parent of potentially many others.
    (The parent label has space allocated in the header, but is not used by any
    code in libctf at present.)

This does mean that a container cannot be used both as a parent and as a child
container at the same time, because type IDs referring to types within the same
container will have their MSB turned on if this was constructed as a parent
container.  While there is a parent name and parent label in the header, it is
purely up to the CTF consumer and convention how this is interpreted: neither
libctf nor the format prohibits ctf_import()ing any container at all as a parent
container, though you should in general import the same parent at consumption
time as you did when you generated the container, or things wil misbehave.


Data type section
-----------------

This is the core section in a CTF file, an array of variable-length entries,
each entry a struct ctf_stype or struct ctf_type followed by optional
variable-length data.  Each array index is transformed into a type ID by
flipping on the MSB iff this is a parent type container.  These type IDs are how
types are referenced within CTF containers.  The ID of each type is not stored
witih the type, but is implied by its array index.

The ctf_type_t and ctf_stype_t act as a discriminated union with an identical
first few members:

typedef struct ctf_stype
{
  uint32_t ctt_name;		/* Reference to name in string table.  */
  uint32_t ctt_info;		/* Encoded kind, variant length (see below).  */
  union
  {
    uint32_t ctt_size;		/* Size of entire type in bytes.  */
    uint32_t ctt_type;		/* Reference to another type.  */
  };
} ctf_stype_t;

All types are represented by an instance of one of these structures: ctt_name is
0 for unnamed types, while ctt_info is a tiny bitfielded structure accessed via
masking:

               ------------------------
   ctt_info:   | kind | isroot | vlen |
               ------------------------
               31    26    25  24     0
where

kind: a CTF_K_* constant indicating whether this type is an int, a float, an array,
      a pointer, a structure or what-have-you (see below)
isroot: is 1 if this type has a name, 0 otherwise
vlen: the length of a kind-specific variable data region ("variant data") which
      immediately follows the ctf_stype or ctf_type structure, and contains 
      type-kind-specific properties (array length, an array of structure
      members, or whatever). The data in the vlen region is the closest thing to
      most of the attributes used by DWARF to describe types.  In general, only
      kinds for which the vlen is actually variable can be trusted to have
      useful values in this field: for all other kinds, the vlen is meaningless
      and is usually hardwwiired for that kind where needed.  ctf.h defines the
      currently-valid set of kinds:

#define CTF_K_UNKNOWN	0	/* Unknown type (used for padding).  */
#define CTF_K_INTEGER	1	/* Variant data is CTF_INT_DATA (see below).  */
#define CTF_K_FLOAT	2	/* Variant data is CTF_FP_DATA (see below).  */
#define CTF_K_POINTER	3	/* ctt_type is referenced type.  */
#define CTF_K_ARRAY	4	/* Variant data is single ctf_array_t.  */
#define CTF_K_FUNCTION	5	/* ctt_type is return type, variant data is
				   list of argument types (unsigned short's for v1,
				   uint32_t's for v2).  */
#define CTF_K_STRUCT	6	/* Variant data is list of ctf_member_t's.  */
#define CTF_K_UNION	7	/* Variant data is list of ctf_member_t's.  */
#define CTF_K_ENUM	8	/* Variant data is list of ctf_enum_t's.  */
#define CTF_K_FORWARD	9	/* No additional data; ctt_name is tag.  */
#define CTF_K_TYPEDEF	10	/* ctt_type is referenced type.  */
#define CTF_K_VOLATILE	11	/* ctt_type is base type.  */
#define CTF_K_CONST	12	/* ctt_type is base type.  */
#define CTF_K_RESTRICT	13	/* ctt_type is base type.  */
#define CTF_K_SLICE	14	/* Variant data is a ctf_slice_t.  */

#define CTF_K_MAX	63	/* Maximum possible (V2) CTF_K_* value.  */

Most of these obviously relate directly to specific C types: the only strange
one is 'slice', which allows you to take an integral type and modify its
bitness, for easy construction of bitfields (a slice of a CTF_K_ENUM is the only
way to specify an enum bitfield).


Looking at the rest of the ctf_stype_t, the ctt_size / ctt_type union is a trick
to reduce sizes. Most type-kinds that refer to another type (like pointers, or
cv-quals) have a fixed size, defined by the platform ABI (libctf calls this the
'machine model'): most types that have a variable size do not refer to another
type: all the most voluminous type kinds either do one or the other. So the
ctt_size / ctt_type contains whichever of these is applicable to the type in
question. (A few kinds, like structures or function pointers, refer to more than
one type ID: in this case, relevant type IDs are carried in the vlen data.)

For very large types the ctf_stype is not enough: the size of types can exceed
that representable by a uint32_t.  For these, we use a ctf_type_t instead:

typedef struct ctf_type
{
  uint32_t ctt_name;		/* Reference to name in string table.  */
  uint32_t ctt_info;		/* Encoded kind, variant length (see below).  */
  union
  {
    uint32_t ctt_size;		/* Always CTF_LSIZE_SENT.  */
    uint32_t ctt_type;		/* Do not use.  */
  };
  uint32_t ctt_lsizehi;		/* High 32 bits of type size in bytes.  */
  uint32_t ctt_lsizelo;		/* Low 32 bits of type size in bytes.  */
} ctf_type_t;

As noted above, this overlays on top of the ctf_stype_t, so almost all code can
just deal directly with whichever it prefers and check ctt_size to see if this
is a ctf_type or ctf_stype. You distinguish a ctf_type_t from a ctf_stype_t
because ctf_type_t has ctt_size == CTF_LSIZE_SENT (which is an invalid value for
a type ID).

Structure members use a similar trick. Almost all the time, the size of the
structure (the ctt_size) is less than 2^32 bytes, and the variable data is an
array of ctf_member_t's:

typedef struct ctf_member_v2
{
  uint32_t ctm_name;		/* Reference to name in string table.  */
  uint32_t ctm_offset;		/* Offset of this member in bits.  */
  uint32_t ctm_type;		/* Reference to type of member.  */
} ctf_member_t;

But if the structure is really huge (above CTF_LSTRUCT_THRESH bytes in length),
the ctt_size overflows the range of the ctm_offset, and every member in this
structure is instead described by the larger ctf_lmember_t:

typedef struct ctf_lmember_v2
{
  uint32_t ctlm_name;		/* Reference to name in string table.  */
  uint32_t ctlm_offsethi;	/* High 32 bits of member offset in bits.  */
  uint32_t ctlm_type;		/* Reference to type of member.  */
  uint32_t ctlm_offsetlo;	/* Low 32 bits of member offset in bits.  */
} ctf_lmember_t;

Unions are identical, and you can represent unnamed structure and union fields
as well with no extensions, by just adding members at the appropriate bit offset
in the containing struct/union (which is how unnamed structs/unions appear to
the programmer, and thus how they should appear to debuggers).


Structure members show the general theme for variant data: in most cases, the
variant data is some sort of structure, or an array of structures, or is not
present at all (things like typedefs don't have one): but function types, and
integral and floating-point types, use different sorts of vlen.  Function types
use a list of argument types with vlen / sizeof (uint32_t) members, with the
ctt_type being the return type; integer and floating-point types use flags
packed into a single uint32_t in the variant data encoding things like format,
bitness, etc:

#define CTF_INT_ENCODING(data) (((data) & 0xff000000) >> 24)
#define CTF_INT_OFFSET(data)   (((data) & 0x00ff0000) >> 16)
#define CTF_INT_BITS(data)     (((data) & 0x0000ffff))

#define CTF_INT_DATA(encoding, offset, bits) \
       (((encoding) << 24) | ((offset) << 16) | (bits))

#define CTF_INT_SIGNED	0x01	/* Integer is signed (otherwise unsigned).  */
#define CTF_INT_CHAR	0x02	/* Character display format.  */
#define CTF_INT_BOOL	0x04	/* Boolean display format.  */
#define CTF_INT_VARARGS	0x08	/* Varargs display format.  */

Or, for floats:

#define CTF_FP_ENCODING(data)  (((data) & 0xff000000) >> 24)
#define CTF_FP_OFFSET(data)    (((data) & 0x00ff0000) >> 16)
#define CTF_FP_BITS(data)      (((data) & 0x0000ffff))

#define CTF_FP_DATA(encoding, offset, bits) \
       (((encoding) << 24) | ((offset) << 16) | (bits))

/* Variant data when kind is CTF_K_FLOAT is an encoding in the top eight bits.  */
#define CTF_FP_ENCODING(data)	(((data) & 0xff000000) >> 24)

#define CTF_FP_SINGLE	1	/* IEEE 32-bit float encoding.  */
#define CTF_FP_DOUBLE	2	/* IEEE 64-bit float encoding.  */
#define CTF_FP_CPLX	3	/* Complex encoding.  */
#define CTF_FP_DCPLX	4	/* Double complex encoding.  */
#define CTF_FP_LDCPLX	5	/* Long double complex encoding.  */
#define CTF_FP_LDOUBLE	6	/* Long double encoding.  */
#define CTF_FP_INTRVL	7	/* Interval (2x32-bit) encoding.  */
#define CTF_FP_DINTRVL	8	/* Double interval (2x64-bit) encoding.  */
#define CTF_FP_LDINTRVL	9	/* Long double interval (2x128-bit) encoding.  */
#define CTF_FP_IMAGRY	10	/* Imaginary (32-bit) encoding.  */
#define CTF_FP_DIMAGRY	11	/* Long imaginary (64-bit) encoding.  */
#define CTF_FP_LDIMAGRY	12	/* Long double imaginary (128-bit) encoding.  */

#define CTF_FP_MAX	12	/* Maximum possible CTF_FP_* value */

Some of the formats, particularly in the floating-point realm, are somewhat
debatable, and we hope for discussion of what formats are appropriate (C99
complex types appear to be provided for, but not much else).

It is notable that there are two redundant ways to encode the bitness of
bitfield types, and three redundant ways to encode their offset: you can put
either directly into the encoding, or put it into a slice, or specify the offset
via bit-specific values in the containing structure or union. libctf hides as
much of this as possible by making it appear that slices are the same kind as
the kind they point to, contributing only an encoding: the only difference
between the slice and its underlying type is that you can call
ctf_type_reference() on the slice to get that underlying type, which you cannot
do on an int.

(In the header alone, but not in the data format, there is an additional
feature: the CTF_CHAR macro is an integral type of the same signedness as the
build target's char type, turning on CTF_INT_SIGNED, nor not, appropriately.)


Function info and data object sections
--------------------------------------

These two sections, taken together, map 1:1 to the symbols of type STT_OBJECT
and STT_FUNC in an ELF symbol table (usually the symbol table in the ELF object
in which the CTF section is embedded). It is generated by traversing the symbol
table, and whenever a suitable symbol is encountered, adding an entry for it
to the data object or function info sections, depending on whether this is a
STT_OBJECT or STT_FUNC symbol.

Both producer and consumer must agree on the definition of 'suitable', since
there is no cross-checking here, and if even one symbol is treated differently,
all symbols following it will be misattributed.

For both STT_FUNC and STT_OBJECT symbols, symbols that have a name that _START_
or _END_ or that is SHN_UNDEF are omitted; for STT_OBJECT symbols, we further
omit zero-valued SHN_ABS symbols.

The data object section is an array of type IDs, one entry per suitable entry in
the symbol table: each type ID is the type of the corresponding symbol.

The function object section is an array of things that (if they were in
structures rather than just a stream of bytes) would look fairly similar to the
variant data for CTF_K_FUNCTION types, described above:

uint32_t ctt_info; # vlen is number of args
ctf_id_t ctc_return;
ctf_id_t args[vlen];

If the last arg is zero, this is a varargs function, and libctf will flip on the
CTF_FUNC_VARARG flag in the funcinfo on return.


Variable info section
---------------------

This is a very simple section, an array of ctf_varent_t sorted in ascending
strcmp() order by ctv_name.  It is used for systems in which there is nothing
resembling a string table, in which address -> name lookup for data objects is
done by machinery outside the purview of CTF, and the caller wants to resolve
string names to types.  This covers data objects only: there is currently
nothing resembling the function info section with manual lookup like this.


Label section
-------------

This section is an array of ctf_lblent, which can be used to tile the type space
into named regions.  It might be useful for parallel deduplicators, or to have
distinct parent containers for different regions of the type space (with names
denoted by the label), or such things.


String table
------------

This is a perfectly normal ELF string table, with a first entry which is simply
\0 (so unnamed items can be denoted by the integer 0): it is specific to the CTF
contianer alone.  String table references in CTF have an MSB which, when 1
(CTF_STRTAB_1), means to use a specific ELF string table (usually the one
accompanying the symbol table used for the function info and data object
sections).

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 06/19] libctf: hashing
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (5 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 09/19] libctf: opening Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-02 16:16   ` Nick Clifton
  2019-04-30 22:57 ` [PATCH 10/19] libctf: ELF file opening Nick Alcock
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

libctf maintains two distinct hash ADTs, one (ctf_dynhash) for wrapping
dynamically-generated unknown-sized hashes during CTF file construction,
one (ctf_hash) for wrapping unchanging hashes whose size is known at
creation time for reading CTF files that were previously created.

In the binutils implementation, these are both fairly thin wrappers
around libiberty hashtab.

Unusually, this code is not kept synchronized with libdtrace-ctf,
due to its dependence on libiberty hashtab.

libctf/
	* ctf-hash.c: New file.
	* ctf-impl.h: New declarations.
---
 libctf/ctf-hash.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++
 libctf/ctf-impl.h |  29 +++++
 2 files changed, 306 insertions(+)
 create mode 100644 libctf/ctf-hash.c

diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c
new file mode 100644
index 0000000000..fccc90f2cf
--- /dev/null
+++ b/libctf/ctf-hash.c
@@ -0,0 +1,277 @@
+/* Interface to hashtable implementations.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+#include "libiberty.h"
+#include "hashtab.h"
+
+/* We have two hashtable implementations: one, ctf_dynhash_*(), is an interface to
+   a dynamically-expanding hash with unknown size that should support addition
+   of large numbers of items, and removal as well, and is used only at
+   type-insertion time; the other, ctf_dynhash_*(), is an interface to a
+   fixed-size hash from const char * -> ctf_id_t with number of elements
+   specified at creation time, that should support addition of items but need
+   not support removal.  These can be implemented by the same underlying hashmap
+   if you wish.  */
+
+typedef struct ctf_helem
+{
+  void *key;			 /* Either a pointer, or a coerced ctf_id_t.  */
+  void *value;			 /* The value (possibly a coerced int).  */
+  ctf_hash_free_fun key_free;
+  ctf_hash_free_fun value_free;
+} ctf_helem_t;
+
+struct ctf_dynhash
+{
+  struct htab *htab;
+  ctf_hash_free_fun key_free;
+  ctf_hash_free_fun value_free;
+};
+
+/* Hash functions. */
+
+unsigned int
+ctf_hash_integer (const void *ptr)
+{
+  ctf_helem_t *hep = (ctf_helem_t *) ptr;
+
+  return htab_hash_pointer (hep->key);
+}
+
+int
+ctf_hash_eq_integer (const void *a, const void *b)
+{
+  ctf_helem_t *hep_a = (ctf_helem_t *) a;
+  ctf_helem_t *hep_b = (ctf_helem_t *) b;
+
+  return htab_eq_pointer (hep_a->key, hep_b->key);
+}
+
+unsigned int
+ctf_hash_string (const void *ptr)
+{
+  ctf_helem_t *hep = (ctf_helem_t *) ptr;
+
+  return htab_hash_string (hep->key);
+}
+
+int
+ctf_hash_eq_string (const void *a, const void *b)
+{
+  ctf_helem_t *hep_a = (ctf_helem_t *) a;
+  ctf_helem_t *hep_b = (ctf_helem_t *) b;
+
+  return !strcmp((const char *) hep_a->key, (const char *) hep_b->key);
+}
+
+/* The dynhash, used for hashes whose size is not known at creation time. */
+
+/* Free a single ctf_helem.  */
+
+static void
+ctf_dynhash_item_free (void *item)
+{
+  ctf_helem_t *helem = item;
+
+  if (helem->key_free && helem->key)
+    helem->key_free (helem->key);
+  if (helem->value_free && helem->value)
+    helem->value_free (helem->value);
+  free (helem);
+}
+
+ctf_dynhash_t *
+ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
+                    ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
+{
+  ctf_dynhash_t *dynhash;
+
+  dynhash = malloc (sizeof (ctf_dynhash_t));
+  if (!dynhash)
+    return NULL;
+
+  /* 7 is arbitrary and untested for now..  */
+  if ((dynhash->htab = htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
+                                          ctf_dynhash_item_free, xcalloc, free)) == NULL)
+    {
+      free (dynhash);
+      return NULL;
+    }
+
+  dynhash->key_free = key_free;
+  dynhash->value_free = value_free;
+
+  return dynhash;
+}
+
+static ctf_helem_t **
+ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option insert)
+{
+  ctf_helem_t tmp = { .key = (void *) key };
+  return (ctf_helem_t **) htab_find_slot (htab, &tmp, insert);
+}
+
+static ctf_helem_t *
+ctf_hashtab_insert (struct htab *htab, void *key, void *value)
+{
+  ctf_helem_t **slot;
+
+  slot = ctf_hashtab_lookup (htab, key, INSERT);
+
+  if (!slot)
+    {
+      errno = -ENOMEM;
+      return NULL;
+    }
+
+  if (!*slot)
+    {
+      *slot = malloc (sizeof (ctf_helem_t));
+      if (!*slot)
+	return NULL;
+      (*slot)->key = key;
+    }
+  (*slot)->value = value;
+  return *slot;
+}
+
+int
+ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
+{
+  ctf_helem_t *slot;
+
+  slot = ctf_hashtab_insert (hp->htab, key, value);
+
+  if (!slot)
+    return errno;
+
+  /* We need to keep the key_free and value_free around in each item because the
+     del function has no visiblity into the hash as a whole, only into the
+     individual items.  */
+
+  slot->key_free = hp->key_free;
+  slot->value_free = hp->value_free;
+
+  return 0;
+}
+
+void
+ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key)
+{
+  htab_remove_elt (hp->htab, (void *) key);
+}
+
+void *
+ctf_dynhash_lookup (ctf_dynhash_t *hp, const void *key)
+{
+  ctf_helem_t **slot;
+
+  slot = ctf_hashtab_lookup (hp->htab, key, NO_INSERT);
+
+  if (slot)
+    return (*slot)->value;
+
+  return NULL;
+}
+
+void
+ctf_dynhash_destroy (ctf_dynhash_t *hp)
+{
+  if (hp != NULL)
+    htab_delete (hp->htab);
+  free (hp);
+}
+
+/* ctf_hash, used for fixed-size maps from const char * -> ctf_id_t without
+   removal.  This is a straight cast of a hashtab.  */
+
+ctf_hash_t *
+ctf_hash_create (unsigned long nelems, ctf_hash_fun hash_fun,
+		 ctf_hash_eq_fun eq_fun)
+{
+  return (ctf_hash_t *) htab_create_alloc (nelems, (htab_hash) hash_fun,
+					   eq_fun, free, xcalloc, free);
+}
+
+uint32_t
+ctf_hash_size (const ctf_hash_t *hp)
+{
+  return htab_elements ((struct htab *) hp);
+}
+
+int
+ctf_hash_insert_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
+		      uint32_t name)
+{
+  ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];
+  const char *str = ctsp->cts_strs + CTF_NAME_OFFSET (name);
+
+  if (type == 0)
+    return EINVAL;
+
+  if (ctsp->cts_strs == NULL)
+    return ECTF_STRTAB;
+
+  if (ctsp->cts_len <= CTF_NAME_OFFSET (name))
+    return ECTF_BADNAME;
+
+  if (str[0] == '\0')
+    return 0;		   /* Just ignore empty strings on behalf of caller.  */
+
+  if (ctf_hashtab_insert ((struct htab *) hp, (char *) str,
+			  (void *) (ptrdiff_t) type) != NULL)
+    return 0;
+  return errno;
+}
+
+/* if the key is already in the hash, override the previous definition with
+   this new official definition. If the key is not present, then call
+   ctf_hash_insert_type() and hash it in.  */
+int
+ctf_hash_define_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
+                      uint32_t name)
+{
+  /* This matches the semantics of ctf_hash_insert_type() in this
+     implementation anyway.  */
+
+  return ctf_hash_insert_type (hp, fp, type, name);
+}
+
+ctf_id_t
+ctf_hash_lookup_type (ctf_hash_t *hp, ctf_file_t *fp __attribute__ ((__unused__)),
+		      const char *key)
+{
+  ctf_helem_t **slot;
+
+  slot = ctf_hashtab_lookup ((struct htab *) hp, key, NO_INSERT);
+
+  if (slot)
+    return (ctf_id_t) ((*slot)->value);
+
+  return 0;
+}
+
+void
+ctf_hash_destroy (ctf_hash_t *hp)
+{
+  if (hp != NULL)
+    htab_delete ((struct htab *) hp);
+}
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index d4d71fbfdc..32f4bfeaef 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -59,12 +59,41 @@ extern "C"
 
 #endif
 
+/* libctf in-memory state.  */
+
+typedef struct ctf_fixed_hash ctf_hash_t; /* Private to ctf-hash.c.  */
+typedef struct ctf_dynhash ctf_dynhash_t; /* Private to ctf-hash.c.  */
+
 typedef struct ctf_list
 {
   struct ctf_list *l_prev;	/* Previous pointer or tail pointer.  */
   struct ctf_list *l_next;	/* Next pointer or head pointer.  */
 } ctf_list_t;
 
+typedef unsigned int (*ctf_hash_fun) (const void *ptr);
+extern unsigned int ctf_hash_integer (const void *ptr);
+extern unsigned int ctf_hash_string (const void *ptr);
+
+typedef int (*ctf_hash_eq_fun) (const void *, const void *);
+extern int ctf_hash_eq_integer (const void *, const void *);
+extern int ctf_hash_eq_string (const void *, const void *);
+
+typedef void (*ctf_hash_free_fun) (void *);
+
+extern ctf_hash_t *ctf_hash_create (unsigned long, ctf_hash_fun, ctf_hash_eq_fun);
+extern int ctf_hash_insert_type (ctf_hash_t *, ctf_file_t *, uint32_t, uint32_t);
+extern int ctf_hash_define_type (ctf_hash_t *, ctf_file_t *, uint32_t, uint32_t);
+extern ctf_id_t ctf_hash_lookup_type (ctf_hash_t *, ctf_file_t *, const char *);
+extern uint32_t ctf_hash_size (const ctf_hash_t *);
+extern void ctf_hash_destroy (ctf_hash_t *);
+
+extern ctf_dynhash_t *ctf_dynhash_create (ctf_hash_fun, ctf_hash_eq_fun,
+					  ctf_hash_free_fun, ctf_hash_free_fun);
+extern int ctf_dynhash_insert (ctf_dynhash_t *, void *, void *);
+extern void ctf_dynhash_remove (ctf_dynhash_t *, const void *);
+extern void *ctf_dynhash_lookup (ctf_dynhash_t *, const void *);
+extern void ctf_dynhash_destroy (ctf_dynhash_t *);
+
 #define	ctf_list_prev(elem)	((void *)(((ctf_list_t *)(elem))->l_prev))
 #define	ctf_list_next(elem)	((void *)(((ctf_list_t *)(elem))->l_next))
 
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 02/19] include: new header ctf-api.h
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-02 15:07   ` Nick Clifton
  2019-04-30 22:57 ` [PATCH 15/19] libctf: mmappable archives Nick Alcock
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

This non-installed header is the means by which libctf consumers
communicate with libctf.

This header will be extended in subsequent commits.

include/
	* ctf-api.h: New file.
---
 include/ctf-api.h | 130 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)
 create mode 100644 include/ctf-api.h

diff --git a/include/ctf-api.h b/include/ctf-api.h
new file mode 100644
index 0000000000..e2f5dc7571
--- /dev/null
+++ b/include/ctf-api.h
@@ -0,0 +1,130 @@
+/* Public API to libctf.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This header file defines the interfaces available from the CTF debugger
+   library, libctf.  This API can be used by a debugger to operate on data in
+   the Compact ANSI-C Type Format (CTF).  */
+
+#ifndef	_CTF_API_H
+#define	_CTF_API_H
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <ctf.h>
+
+#ifdef	__cplusplus
+extern "C"
+  {
+#endif
+
+/* Clients can open one or more CTF containers and obtain a pointer to an
+   opaque ctf_file_t.  Types are identified by an opaque ctf_id_t token.
+   They can also open or create read-only archives of CTF containers in a
+   ctf_archive_t.
+
+   These opaque definitions allow libctf to evolve without breaking clients.  */
+
+typedef struct ctf_file ctf_file_t;
+typedef struct ctf_archive ctf_archive_t;
+typedef long ctf_id_t;
+
+/* Functions that return integer status or a ctf_id_t use the following value
+   to indicate failure.  ctf_errno() can be used to obtain an error code.  */
+#define	CTF_ERR	(-1L)
+
+#define	ECTF_BASE	1000	/* Base value for libctf errnos.  */
+
+
+enum
+  {
+   ECTF_FMT = ECTF_BASE,	/* File is not in CTF or ELF format.  */
+   ECTF_ELFVERS,		/* ELF version is more recent than libctf.  */
+   ECTF_CTFVERS,		/* CTF version is more recent than libctf.  */
+   ECTF_ENDIAN,			/* Data is different endian-ness than lib.  */
+   ECTF_SYMTAB,			/* Symbol table uses invalid entry size.  */
+   ECTF_SYMBAD,			/* Symbol table data buffer invalid.  */
+   ECTF_STRBAD,			/* String table data buffer invalid.  */
+   ECTF_CORRUPT,		/* File data corruption detected.  */
+   ECTF_NOCTFDATA,		/* ELF file does not contain CTF data.  */
+   ECTF_NOCTFBUF,		/* Buffer does not contain CTF data.  */
+   ECTF_NOSYMTAB,		/* Symbol table data is not available.  */
+   ECTF_NOPARENT,		/* Parent CTF container is not available.  */
+   ECTF_DMODEL,			/* Data model mismatch.  */
+   ECTF_MMAP,			/* Failed to mmap a data section.  */
+   ECTF_ZALLOC,			/* Failed to allocate (de)compression buffer.  */
+   ECTF_DECOMPRESS,		/* Failed to decompress CTF data.  */
+   ECTF_STRTAB,			/* String table for this string is missing.  */
+   ECTF_BADNAME,		/* String offset is corrupt w.r.t. strtab.  */
+   ECTF_BADID,			/* Invalid type ID number.  */
+   ECTF_NOTSOU,			/* Type is not a struct or union.  */
+   ECTF_NOTENUM,		/* Type is not an enum.  */
+   ECTF_NOTSUE,			/* Type is not a struct, union, or enum.  */
+   ECTF_NOTINTFP,		/* Type is not an integer, float, or enum.  */
+   ECTF_NOTARRAY,		/* Type is not an array.  */
+   ECTF_NOTREF,			/* Type does not reference another type.  */
+   ECTF_NAMELEN,		/* Buffer is too small to hold type name.  */
+   ECTF_NOTYPE,			/* No type found corresponding to name.  */
+   ECTF_SYNTAX,			/* Syntax error in type name.  */
+   ECTF_NOTFUNC,		/* Symtab entry does not refer to a function.  */
+   ECTF_NOFUNCDAT,		/* No func info available for function.  */
+   ECTF_NOTDATA,		/* Symtab entry does not refer to a data obj.  */
+   ECTF_NOTYPEDAT,		/* No type info available for object.  */
+   ECTF_NOLABEL,		/* No label found corresponding to name.  */
+   ECTF_NOLABELDATA,		/* File does not contain any labels.  */
+   ECTF_NOTSUP,			/* Feature not supported.  */
+   ECTF_NOENUMNAM,		/* Enum element name not found.  */
+   ECTF_NOMEMBNAM,		/* Member name not found.  */
+   ECTF_RDONLY,			/* CTF container is read-only.  */
+   ECTF_DTFULL,			/* CTF type is full (no more members allowed).  */
+   ECTF_FULL,			/* CTF container is full.  */
+   ECTF_DUPLICATE,		/* Duplicate member or variable name.  */
+   ECTF_CONFLICT,		/* Conflicting type definition present.  */
+   ECTF_OVERROLLBACK,		/* Attempt to roll back past a ctf_update.  */
+   ECTF_COMPRESS,		/* Failed to compress CTF data.  */
+   ECTF_ARCREATE,		/* Error creating CTF archive.  */
+   ECTF_ARNNAME,		/* Name not found in CTF archive.  */
+   ECTF_SLICEOVERFLOW,		/* Overflow of type bitness or offset in slice.  */
+   ECTF_DUMPSECTUNKNOWN,	/* Unknown section number in dump.  */
+   ECTF_DUMPSECTCHANGED		/* Section changed in middle of dump.  */
+  };
+
+/* The CTF data model is inferred to be the caller's data model or the data
+   model of the given object, unless ctf_setmodel() is explicitly called.  */
+#define	CTF_MODEL_ILP32 1	/* Object data model is ILP32.  */
+#define	CTF_MODEL_LP64  2	/* Object data model is LP64.  */
+#ifdef _LP64
+# define CTF_MODEL_NATIVE CTF_MODEL_LP64
+#else
+# define CTF_MODEL_NATIVE CTF_MODEL_ILP32
+#endif
+
+/* Dynamic CTF containers can be created using ctf_create().  The ctf_add_*
+   routines can be used to add new definitions to the dynamic container.
+   New types are labeled as root or non-root to determine whether they are
+   visible at the top-level program scope when subsequently doing a lookup.  */
+
+#define	CTF_ADD_NONROOT	0	/* Type only visible in nested scope.  */
+#define	CTF_ADD_ROOT	1	/* Type visible at top-level scope.  */
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _CTF_API_H */
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 09/19] libctf: opening
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (4 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 01/19] include: new header ctf.h: file format description Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 06/19] libctf: hashing Nick Alcock
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

This fills in the other half of the opening/creation puzzle: opening of
already-existing CTF files.  Such files are always read-only: if you
want to add to a CTF file opened with one of the opening functions in
this file, use ctf_add_type(), in a later commit, to copy appropriate
types into a newly ctf_create()d, writable container.

The lowest-level opening functions are in here: ctf_bufopen(), which
takes ctf_sect_t structures akin to ELF section headers, and
ctf_simple_open(), which can be used if you don't have an entire ELF
section header to work from.  Both will malloc() new space for the
buffers only if necessary, will mmap() directly from the file if
requested, and will mprotect() it afterwards to prevent accidental
corruption of the types. These functions are also used by ctf_update()
when converting types in a writable container into read-only types that
can be looked up using the lookup functions (in later commits).

The files are always of the native endianness of the system that created
them: at read time, the endianness of the header magic number is used to
determine whether or not the file needs byte-swapping, and the entire
thing is aggressively byte-swapped. (Similarly, in the upstream version
in which older versions of CTF with incompatible file formats are
supported, older versions are aggressively upgraded to newer versions at
open time.)

The agggressive nature of this swapping avoids complicating the rest of
the code with endianness conversions, while the native endianness
introduces no byte-swapping overhead in the common case. (The
endianness-independence code is also much newer than everything else in
this file, and deserves closer scrutiny.)

The accessors at the top of the file are there to transparently support
older versions of the CTF file format, allowing translation from older
formats that have different sizes for the structures in ctf.h: they are
only NULL because this version doesn't support any of the older
formats. In time they may grow new ones.  The ctf_set_base() function is
split out for the same reason: when conversion code to a newer format is
written, it would need to malloc() new storage for the entire ctf_file_t
if a file format change causes it to grow, and for that we need
ctf_set_base() to be a separate function.

One pair of linked data structures supported by this file has no
creation code in libctf yet: the data and function object sections read
by init_symtab(). These will probably arrive soon, when the linker comes
to need them. (init_symtab() has hardly been changed since 2009, but if
any code in libctf has rotted over time, this will.)

A few simple accessors are also present that can even be called on
read-only containers because they don't actually modify them, since the
relevant things are not stored in the container but merely change its
operation: ctf_setmodel(), which lets you specify whether a container is
LP64 or not (used to statically determine the sizes of a few types),
ctf_import(), which is the only way to associate a parent container with
a child container, and ctf_setspecific(), which lets the caller
associate an arbitrary pointer with the CTF container for any use. If
the user doesn't call these functions correctly, libctf will misbehave:
this is particularly important for ctf_import(), since a container built
against a given parent container will not be able to resolve types that
depend on types in the parent unless it is ctf_import()ed with a parent
container with the same set of types at the same IDs, or a superset.

Possible future extensions (also noted in the ctf-hash.c file) include
storing a count of things so that we don't need to do one pass over the
CTF file counting everything, and computing a perfect hash at CTF
creation time in some compact form, storing it in the CTF file, and
using it to hash things so we don't need to do a second pass over the
entire CTF file to set up the hashes used to go from names to type IDs.
(There are multiple such hashes, one for each C type namespace: types,
enums, structs, and unions.)

libctf/
	* ctf-open.c: New file.
include/
	* ctf-api.h (ctf_close): New declaration.
	(ctf_getdatasect): Likewise.
	(ctf_parent_file): Likewise.
	(ctf_parent_name): Likewise.
	(ctf_parent_name_set): Likewise.
	(ctf_import): Likewise.
	(ctf_setmodel): Likewise.
	(ctf_getmodel): Likewise.
	(ctf_setspecific): Likewise.
	(ctf_getspecific): Likewise.
---
 include/ctf-api.h |   13 +
 libctf/ctf-open.c | 1359 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1372 insertions(+)
 create mode 100644 libctf/ctf-open.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 5847b24752..4329c6b2f7 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -203,6 +203,19 @@ extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
 extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
 				const ctf_sect_t *, int *);
 extern ctf_file_t *ctf_create (int *);
+extern void ctf_close (ctf_file_t *);
+extern ctf_sect_t ctf_getdatasect (const ctf_file_t *);
+
+extern ctf_file_t *ctf_parent_file (ctf_file_t *);
+extern const char *ctf_parent_name (ctf_file_t *);
+extern void ctf_parent_name_set (ctf_file_t *, const char *);
+
+extern int ctf_import (ctf_file_t *, ctf_file_t *);
+extern int ctf_setmodel (ctf_file_t *, int);
+extern int ctf_getmodel (ctf_file_t *);
+
+extern void ctf_setspecific (ctf_file_t *, void *);
+extern void *ctf_getspecific (ctf_file_t *);
 
 extern int ctf_errno (ctf_file_t *);
 extern const char *ctf_errmsg (int);
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
new file mode 100644
index 0000000000..77c4790b8b
--- /dev/null
+++ b/libctf/ctf-open.c
@@ -0,0 +1,1359 @@
+/* Opening CTF files.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <gelf.h>
+#include <sys/mman.h>
+#include <byteswap.h>
+#include <zlib.h>
+
+static const ctf_dmodel_t _libctf_models[] = {
+  {"ILP32", CTF_MODEL_ILP32, 4, 1, 2, 4, 4},
+  {"LP64", CTF_MODEL_LP64, 8, 1, 2, 4, 8},
+  {NULL, 0, 0, 0, 0, 0, 0}
+};
+
+const char _CTF_SECTION[] = ".ctf";
+const char _CTF_NULLSTR[] = "";
+
+int _libctf_version = CTF_VERSION;	      /* Library client version.  */
+int _libctf_debug = 0;			      /* Debugging messages enabled.  */
+
+/* Version-sensitive accessors.  (In the !NO_COMPAT case, there are many of
+   these, one per version per field and sometimes more.)  */
+
+
+static uint32_t
+get_kind_v2 (uint32_t info)
+{
+  return (CTF_V2_INFO_KIND (info));
+}
+
+static uint32_t
+get_root_v2 (uint32_t info)
+{
+  return (CTF_V2_INFO_ISROOT (info));
+}
+
+static uint32_t
+get_vlen_v2 (uint32_t info)
+{
+  return (CTF_V2_INFO_VLEN (info));
+}
+
+static inline ssize_t
+get_ctt_size_common (const ctf_file_t *fp _libctf_unused_,
+		     const ctf_type_t *tp _libctf_unused_,
+		     ssize_t *sizep, ssize_t *incrementp, size_t lsize,
+		     size_t csize, size_t ctf_type_size,
+		     size_t ctf_stype_size, size_t ctf_lsize_sent)
+{
+  ssize_t size, increment;
+
+  if (csize == ctf_lsize_sent)
+    {
+      size = lsize;
+      increment = ctf_type_size;
+    }
+  else
+    {
+      size = csize;
+      increment = ctf_stype_size;
+    }
+
+  if (sizep)
+    *sizep = size;
+  if (incrementp)
+    *incrementp = increment;
+
+  return size;
+}
+
+
+static ssize_t
+get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp,
+		 ssize_t *sizep, ssize_t *incrementp)
+{
+  return (get_ctt_size_common (fp, tp, sizep, incrementp,
+			       CTF_TYPE_LSIZE (tp), tp->ctt_size,
+			       sizeof (ctf_type_t), sizeof (ctf_stype_t),
+			       CTF_LSIZE_SENT));
+}
+
+static ssize_t
+get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_,
+		   size_t vlen)
+{
+  switch (kind)
+    {
+    case CTF_K_INTEGER:
+    case CTF_K_FLOAT:
+      return (sizeof (uint32_t));
+    case CTF_K_SLICE:
+      return (sizeof (ctf_slice_t));
+    case CTF_K_ENUM:
+      return (sizeof (ctf_enum_t) * vlen);
+    case CTF_K_FORWARD:
+    case CTF_K_UNKNOWN:
+    case CTF_K_POINTER:
+    case CTF_K_TYPEDEF:
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+      return 0;
+    default:
+      ctf_dprintf ("detected invalid CTF kind -- %x\n", kind);
+      return ECTF_CORRUPT;
+    }
+}
+
+
+static ssize_t
+get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen)
+{
+  switch (kind)
+    {
+    case CTF_K_ARRAY:
+      return (sizeof (ctf_array_t));
+    case CTF_K_FUNCTION:
+      return (sizeof (uint32_t) * (vlen + (vlen & 1)));
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      if (size < CTF_LSTRUCT_THRESH)
+	return (sizeof (ctf_member_t) * vlen);
+      else
+	return (sizeof (ctf_lmember_t) * vlen);
+    }
+
+  return (get_vbytes_common (kind, size, vlen));
+}
+
+static const ctf_fileops_t ctf_fileops[] = {
+  {NULL, NULL, NULL, NULL, NULL},
+  /* CTF_VERSION_1 */
+  {NULL, NULL, NULL, NULL, NULL},
+  /* CTF_VERSION_1_UPGRADED_3 */
+  {NULL, NULL, NULL, NULL, NULL},
+  /* CTF_VERSION_2 */
+  {NULL, NULL, NULL, NULL, NULL},
+  /* CTF_VERSION_3, identical to 2: only new type kinds */
+  {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
+};
+
+/* Initialize the symtab translation table by filling each entry with the
+  offset of the CTF type or function data corresponding to each STT_FUNC or
+  STT_OBJECT entry in the symbol table.  */
+
+static int
+init_symtab (ctf_file_t *fp, const ctf_header_t *hp,
+	     const ctf_sect_t *sp, const ctf_sect_t *strp)
+{
+  const unsigned char *symp = sp->cts_data;
+  uint32_t *xp = fp->ctf_sxlate;
+  uint32_t *xend = xp + fp->ctf_nsyms;
+
+  uint32_t objtoff = hp->cth_objtoff;
+  uint32_t funcoff = hp->cth_funcoff;
+
+  uint32_t info, vlen;
+  Elf64_Sym sym, *gsp;
+  const char *name;
+
+  /* The CTF data object and function type sections are ordered to match
+     the relative order of the respective symbol types in the symtab.
+     If no type information is available for a symbol table entry, a
+     pad is inserted in the CTF section.  As a further optimization,
+     anonymous or undefined symbols are omitted from the CTF data.  */
+
+  for (; xp < xend; xp++, symp += sp->cts_entsize)
+    {
+      if (sp->cts_entsize == sizeof (Elf32_Sym))
+	gsp = ctf_sym_to_gelf ((Elf32_Sym *) (uintptr_t) symp, &sym);
+      else
+	gsp = (Elf64_Sym *) (uintptr_t) symp;
+
+      if (gsp->st_name < strp->cts_size)
+	name = (const char *) strp->cts_data + gsp->st_name;
+      else
+	name = _CTF_NULLSTR;
+
+      if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF
+	  || strcmp (name, "_START_") == 0 || strcmp (name, "_END_") == 0)
+	{
+	  *xp = -1u;
+	  continue;
+	}
+
+      switch (ELF64_ST_TYPE (gsp->st_info))
+	{
+	case STT_OBJECT:
+	  if (objtoff >= hp->cth_funcoff
+	      || (gsp->st_shndx == SHN_ABS && gsp->st_value == 0))
+	    {
+	      *xp = -1u;
+	      break;
+	    }
+
+	  *xp = objtoff;
+	  objtoff += sizeof (uint32_t);
+	  break;
+
+	case STT_FUNC:
+	  if (funcoff >= hp->cth_typeoff)
+	    {
+	      *xp = -1u;
+	      break;
+	    }
+
+	  *xp = funcoff;
+
+	  info = *(uint32_t *) ((uintptr_t) fp->ctf_buf + funcoff);
+	  vlen = LCTF_INFO_VLEN (fp, info);
+
+	  /* If we encounter a zero pad at the end, just skip it.  Otherwise
+	     skip over the function and its return type (+2) and the argument
+	     list (vlen).
+	   */
+	  if (LCTF_INFO_KIND (fp, info) == CTF_K_UNKNOWN && vlen == 0)
+	    funcoff += sizeof (uint32_t);	/* Skip pad.  */
+	  else
+	    funcoff += sizeof (uint32_t) * (vlen + 2);
+	  break;
+
+	default:
+	  *xp = -1u;
+	  break;
+	}
+    }
+
+  ctf_dprintf ("loaded %lu symtab entries\n", fp->ctf_nsyms);
+  return 0;
+}
+
+/* Set the CTF base pointer and derive the buf pointer from it, initializing
+   everything in the ctf_file that depends on the base or buf pointers.  */
+
+static void
+ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, void *base)
+{
+  fp->ctf_base = base;
+  fp->ctf_buf = fp->ctf_base + sizeof (ctf_header_t);
+  fp->ctf_vars = (ctf_varent_t *) ((const char *) fp->ctf_buf +
+				   hp->cth_varoff);
+  fp->ctf_nvars = (hp->cth_typeoff - hp->cth_varoff) / sizeof (ctf_varent_t);
+
+  fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *) fp->ctf_buf
+    + hp->cth_stroff;
+  fp->ctf_str[CTF_STRTAB_0].cts_len = hp->cth_strlen;
+
+  /* If we have a parent container name and label, store the relocated
+     string pointers in the CTF container for easy access later. */
+
+
+  if (hp->cth_parlabel != 0)
+    fp->ctf_parlabel = ctf_strptr (fp, hp->cth_parlabel);
+  if (hp->cth_parname != 0)
+    fp->ctf_parname = ctf_strptr (fp, hp->cth_parname);
+
+  ctf_dprintf ("ctf_set_base: parent name %s (label %s)\n",
+	       fp->ctf_parname ? fp->ctf_parname : "<NULL>",
+	       fp->ctf_parlabel ? fp->ctf_parlabel : "<NULL>");
+}
+
+/* Free a ctf_base pointer: the pointer passed, or (if NULL) fp->ctf_base.  */
+static void
+ctf_free_base (ctf_file_t *fp, unsigned char *ctf_base, size_t ctf_size)
+{
+  unsigned char *base;
+  size_t size;
+
+  if (ctf_base)
+    {
+      base = ctf_base;
+      size = ctf_size;
+    }
+  else
+    {
+      base = (unsigned char *) fp->ctf_base;
+      size = fp->ctf_size;
+    }
+
+  if (base != fp->ctf_data.cts_data && base != NULL)
+    ctf_data_free (base, size);
+}
+
+/* Set the version of the CTF file. */
+
+
+static void
+ctf_set_version (ctf_file_t * fp, ctf_header_t * cth, int ctf_version)
+{
+  fp->ctf_version = ctf_version;
+  cth->cth_version = ctf_version;
+  fp->ctf_fileops = &ctf_fileops[ctf_version];
+}
+
+
+/* Initialize the type ID translation table with the byte offset of each type,
+   and initialize the hash tables of each named type.  Upgrade the type table to
+   the latest supported representation in the process, if needed, and if this
+   recension of libctf supports upgrading.  */
+
+static int
+init_types (ctf_file_t *fp, ctf_header_t *cth)
+{
+  const ctf_type_t *tbuf;
+  const ctf_type_t *tend;
+
+  unsigned long pop[CTF_K_MAX + 1] = { 0 };
+  const ctf_type_t *tp;
+  ctf_hash_t *hp;
+  uint32_t id, dst;
+  uint32_t *xp;
+
+  /* We determine whether the container is a child or a parent based on
+     the value of cth_parname.  */
+
+  int child = cth->cth_parname != 0;
+  int nlstructs = 0, nlunions = 0;
+  int err;
+
+
+  tbuf = (ctf_type_t *) (fp->ctf_buf + cth->cth_typeoff);
+  tend = (ctf_type_t *) (fp->ctf_buf + cth->cth_stroff);
+
+  /* We make two passes through the entire type section.  In this first
+     pass, we count the number of each type and the total number of types.  */
+
+  for (tp = tbuf; tp < tend; fp->ctf_typemax++)
+    {
+      unsigned short kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+      unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info);
+      ssize_t size, increment, vbytes;
+
+      (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+      vbytes = LCTF_VBYTES (fp, kind, size, vlen);
+
+      if (vbytes < 0)
+	return ECTF_CORRUPT;
+
+      if (kind == CTF_K_FORWARD)
+	{
+	  /* For forward declarations, ctt_type is the CTF_K_* kind for the tag,
+	     so bump that population count too.  If ctt_type is unknown, treat
+	     the tag as a struct.  */
+
+	  if (tp->ctt_type == CTF_K_UNKNOWN || tp->ctt_type >= CTF_K_MAX)
+	    pop[CTF_K_STRUCT]++;
+	  else
+	    pop[tp->ctt_type]++;
+	}
+      tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes);
+      pop[kind]++;
+    }
+
+  if (child)
+    {
+      ctf_dprintf ("CTF container %p is a child\n", (void *) fp);
+      fp->ctf_flags |= LCTF_CHILD;
+    }
+  else
+    ctf_dprintf ("CTF container %p is a parent\n", (void *) fp);
+
+  /* Now that we've counted up the number of each type, we can allocate
+     the hash tables, type translation table, and pointer table.  */
+
+  if ((fp->ctf_structs = ctf_hash_create (pop[CTF_K_STRUCT], ctf_hash_string,
+					  ctf_hash_eq_string)) == NULL)
+    return ENOMEM;
+
+  if ((fp->ctf_unions = ctf_hash_create (pop[CTF_K_UNION], ctf_hash_string,
+					 ctf_hash_eq_string)) == NULL)
+    return ENOMEM;
+
+  if ((fp->ctf_enums = ctf_hash_create (pop[CTF_K_ENUM], ctf_hash_string,
+					ctf_hash_eq_string)) == NULL)
+    return ENOMEM;
+
+  if ((fp->ctf_names = ctf_hash_create (pop[CTF_K_INTEGER] +
+					pop[CTF_K_FLOAT] +
+					pop[CTF_K_FUNCTION] +
+					pop[CTF_K_TYPEDEF] +
+					pop[CTF_K_POINTER] +
+					pop[CTF_K_VOLATILE] +
+					pop[CTF_K_CONST] +
+					pop[CTF_K_RESTRICT],
+					ctf_hash_string,
+					ctf_hash_eq_string)) == NULL)
+    return ENOMEM;
+
+  fp->ctf_txlate = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1));
+  fp->ctf_ptrtab = ctf_alloc (sizeof (uint32_t) * (fp->ctf_typemax + 1));
+
+  if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL)
+    return ENOMEM;		/* Memory allocation failed.  */
+
+  xp = fp->ctf_txlate;
+  *xp++ = 0;			/* Type id 0 is used as a sentinel value.  */
+
+  memset (fp->ctf_txlate, 0, sizeof (uint32_t) * (fp->ctf_typemax + 1));
+  memset (fp->ctf_ptrtab, 0, sizeof (uint32_t) * (fp->ctf_typemax + 1));
+
+  /* In the second pass through the types, we fill in each entry of the
+     type and pointer tables and add names to the appropriate hashes.  */
+
+  for (id = 1, tp = tbuf; tp < tend; xp++, id++)
+    {
+      unsigned short kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+      unsigned short flag = LCTF_INFO_ISROOT (fp, tp->ctt_info);
+      unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info);
+      ssize_t size, increment, vbytes;
+
+      const char *name;
+
+      (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+      name = ctf_strptr (fp, tp->ctt_name);
+      vbytes = LCTF_VBYTES (fp, kind, size, vlen);
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  /* Names are reused by bit-fields, which are differentiated by their
+	     encodings, and so typically we'd record only the first instance of
+	     a given intrinsic.  However, we replace an existing type with a
+	     root-visible version so that we can be sure to find it when
+	     checking for conflicting definitions in ctf_add_type().  */
+
+	  if (((ctf_hash_lookup_type (fp->ctf_names, fp, name)) == 0)
+	      || (flag & CTF_ADD_ROOT))
+	    {
+	      err = ctf_hash_define_type (fp->ctf_names, fp,
+					  LCTF_INDEX_TO_TYPE (fp, id, child),
+					  tp->ctt_name);
+	      if (err != 0 && err != ECTF_STRTAB)
+		return err;
+	    }
+	  break;
+
+	  /* These kinds have no name, so do not need interning into any
+	     hashtables.  */
+	case CTF_K_ARRAY:
+	case CTF_K_SLICE:
+	  break;
+
+	case CTF_K_FUNCTION:
+	  err = ctf_hash_insert_type (fp->ctf_names, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+	  break;
+
+	case CTF_K_STRUCT:
+	  err = ctf_hash_define_type (fp->ctf_structs, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+
+	  if (size >= CTF_LSTRUCT_THRESH)
+	    nlstructs++;
+	  break;
+
+	case CTF_K_UNION:
+	  err = ctf_hash_define_type (fp->ctf_unions, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+
+	  if (size >= CTF_LSTRUCT_THRESH)
+	    nlunions++;
+	  break;
+
+	case CTF_K_ENUM:
+	  err = ctf_hash_define_type (fp->ctf_enums, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+	  break;
+
+	case CTF_K_TYPEDEF:
+	  err = ctf_hash_insert_type (fp->ctf_names, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+	  break;
+
+	case CTF_K_FORWARD:
+	  /* Only insert forward tags into the given hash if the type or tag
+	     name is not already present.  */
+	  switch (tp->ctt_type)
+	    {
+	    case CTF_K_STRUCT:
+	      hp = fp->ctf_structs;
+	      break;
+	    case CTF_K_UNION:
+	      hp = fp->ctf_unions;
+	      break;
+	    case CTF_K_ENUM:
+	      hp = fp->ctf_enums;
+	      break;
+	    default:
+	      hp = fp->ctf_structs;
+	    }
+
+	  if (ctf_hash_lookup_type (hp, fp, name) == 0)
+	    {
+	      err = ctf_hash_insert_type (hp, fp,
+					  LCTF_INDEX_TO_TYPE (fp, id, child),
+					  tp->ctt_name);
+	      if (err != 0 && err != ECTF_STRTAB)
+		return err;
+	    }
+	  break;
+
+	case CTF_K_POINTER:
+	  /* If the type referenced by the pointer is in this CTF container,
+	     then store the index of the pointer type in
+	     fp->ctf_ptrtab[ index of referenced type ].  */
+
+	  if (LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child
+	      && LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax)
+	    fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, tp->ctt_type)] = id;
+	 /*FALLTHRU*/
+
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+	  err = ctf_hash_insert_type (fp->ctf_names, fp,
+				      LCTF_INDEX_TO_TYPE (fp, id, child),
+				      tp->ctt_name);
+	  if (err != 0 && err != ECTF_STRTAB)
+	    return err;
+	  break;
+	}
+
+      *xp = (uint32_t) ((uintptr_t) tp - (uintptr_t) fp->ctf_buf);
+      tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes);
+    }
+
+  ctf_dprintf ("%lu total types processed\n", fp->ctf_typemax);
+  ctf_dprintf ("%u enum names hashed\n", ctf_hash_size (fp->ctf_enums));
+  ctf_dprintf ("%u struct names hashed (%d long)\n",
+	       ctf_hash_size (fp->ctf_structs), nlstructs);
+  ctf_dprintf ("%u union names hashed (%d long)\n",
+	       ctf_hash_size (fp->ctf_unions), nlunions);
+  ctf_dprintf ("%u base type names hashed\n", ctf_hash_size (fp->ctf_names));
+
+  /* Make an additional pass through the pointer table to find pointers that
+     point to anonymous typedef nodes.  If we find one, modify the pointer table
+     so that the pointer is also known to point to the node that is referenced
+     by the anonymous typedef node.  */
+
+  for (id = 1; id <= fp->ctf_typemax; id++)
+    {
+      if ((dst = fp->ctf_ptrtab[id]) != 0)
+	{
+	  tp = LCTF_INDEX_TO_TYPEPTR (fp, id);
+
+	  if (LCTF_INFO_KIND (fp, tp->ctt_info) == CTF_K_TYPEDEF &&
+	      strcmp (ctf_strptr (fp, tp->ctt_name), "") == 0 &&
+	      LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child &&
+	      LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax)
+	    fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, tp->ctt_type)] = dst;
+	}
+    }
+
+  return 0;
+}
+
+/* Endianness-flipping routines.
+
+   We flip everything, mindlessly, even 1-byte entities, so that future
+   expansions do not require changes to this code.  */
+
+/* < C11? define away static assertions.  */
+
+#if !defined (__STDC_VERSION__) || __STDC_VERSION__ < 201112L
+#define _Static_assert(cond, err)
+#endif
+
+/* Swap the endianness of something.  */
+
+#define swap_thing(x)							\
+  do {									\
+    _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0		\
+					&& sizeof (x) <= 8),		\
+		    "Invalid size, update endianness code");		\
+    switch (sizeof (x)) {						\
+    case 2: x = bswap_16 (x); break;					\
+    case 4: x = bswap_32 (x); break;					\
+    case 8: x = bswap_64 (x); break;					\
+    case 1: /* Nothing needs doing */					\
+      break;								\
+    }									\
+  } while (0);
+
+/* Flip the endianness of the CTF header.  */
+
+static void
+flip_header (ctf_header_t *cth)
+{
+  swap_thing (cth->cth_preamble.ctp_magic);
+  swap_thing (cth->cth_preamble.ctp_version);
+  swap_thing (cth->cth_preamble.ctp_flags);
+  swap_thing (cth->cth_parlabel);
+  swap_thing (cth->cth_parname);
+  swap_thing (cth->cth_objtoff);
+  swap_thing (cth->cth_funcoff);
+  swap_thing (cth->cth_varoff);
+  swap_thing (cth->cth_typeoff);
+  swap_thing (cth->cth_stroff);
+  swap_thing (cth->cth_strlen);
+}
+
+/* Flip the endianness of the label section, an array of ctf_lblent_t.  */
+
+static void
+flip_lbls (void *start, size_t len)
+{
+  ctf_lblent_t *lbl = start;
+
+  for (ssize_t i = len / sizeof (struct ctf_lblent); i > 0; lbl++, i--)
+    {
+      swap_thing (lbl->ctl_label);
+      swap_thing (lbl->ctl_type);
+    }
+}
+
+/* Flip the endianness of the data-object or function sections, an array of
+   uint32_t.  (The function section has more internal structure, but that
+   structure is an array of uint32_t, so can be treated as one big array for
+   byte-swapping.)  */
+
+static void
+flip_objts (void *start, size_t len)
+{
+  uint32_t *obj = start;
+
+  for (ssize_t i = len / sizeof (uint32_t); i > 0; obj++, i--)
+      swap_thing (*obj);
+}
+
+/* Flip the endianness of the variable section, an array of ctf_varent_t.  */
+
+static void
+flip_vars (void *start, size_t len)
+{
+  ctf_varent_t *var = start;
+
+  for (ssize_t i = len / sizeof (struct ctf_varent); i > 0; var++, i--)
+    {
+      swap_thing (var->ctv_name);
+      swap_thing (var->ctv_type);
+    }
+}
+
+/* Flip the endianness of the type section, a tagged array of ctf_type or
+   ctf_stype followed by variable data.  */
+
+static int
+flip_types (void *start, size_t len)
+{
+  ctf_type_t *t = start;
+
+  while ((uintptr_t) t < ((uintptr_t) start) + len)
+    {
+      swap_thing (t->ctt_name);
+      swap_thing (t->ctt_info);
+      swap_thing (t->ctt_size);
+
+      uint32_t kind = CTF_V2_INFO_KIND (t->ctt_info);
+      size_t size = t->ctt_size;
+      uint32_t vlen = CTF_V2_INFO_VLEN (t->ctt_info);
+      size_t vbytes = get_vbytes_v2 (kind, size, vlen);
+
+      if (_libctf_unlikely_ (size == CTF_LSIZE_SENT))
+	{
+	  swap_thing (t->ctt_lsizehi);
+	  swap_thing (t->ctt_lsizelo);
+	  size = CTF_TYPE_LSIZE (t);
+	  t = (ctf_type_t *) ((uintptr_t) t + sizeof (ctf_type_t));
+	}
+      else
+	t = (ctf_type_t *) ((uintptr_t) t + sizeof (ctf_stype_t));
+
+      switch (kind)
+	{
+	case CTF_K_FORWARD:
+	case CTF_K_UNKNOWN:
+	case CTF_K_POINTER:
+	case CTF_K_TYPEDEF:
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+	  /* These types have no vlen data to swap.  */
+	  assert (vbytes == 0);
+	  break;
+
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  {
+	    /* These types have a single uint32_t.  */
+
+	    uint32_t *item = (uint32_t *) t;
+
+	    swap_thing (*item);
+	    break;
+	  }
+
+	case CTF_K_FUNCTION:
+	  {
+	    /* This type has a bunch of uint32_ts.  */
+
+	    uint32_t *item = (uint32_t *) t;
+
+	    for (ssize_t i = vlen; i > 0; item++, i--)
+	      swap_thing (*item);
+	    break;
+	  }
+
+	case CTF_K_ARRAY:
+	  {
+	    /* This has a single ctf_array_t.  */
+
+	    ctf_array_t *a = (ctf_array_t *) t;
+
+	    assert (vbytes == sizeof (ctf_array_t));
+	    swap_thing (a->cta_contents);
+	    swap_thing (a->cta_index);
+	    swap_thing (a->cta_nelems);
+
+	    break;
+	  }
+
+	case CTF_K_SLICE:
+	  {
+	    /* This has a single ctf_slice_t.  */
+
+	    ctf_slice_t *s = (ctf_slice_t *) t;
+
+	    assert (vbytes == sizeof (ctf_slice_t));
+	    swap_thing (s->cts_type);
+	    swap_thing (s->cts_offset);
+	    swap_thing (s->cts_bits);
+
+	    break;
+	  }
+
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  {
+	    /* This has an array of ctf_member or ctf_lmember, depending on
+	       size.  We could consider it to be a simple array of uint32_t,
+	       but for safety's sake in case these structures ever acquire
+	       non-uint32_t members, do it member by member.  */
+
+	    if (_libctf_unlikely_ (size >= CTF_LSTRUCT_THRESH))
+	      {
+		ctf_lmember_t *lm = (ctf_lmember_t *) t;
+		for (ssize_t i = vlen; i > 0; i--, lm++)
+		  {
+		    swap_thing (lm->ctlm_name);
+		    swap_thing (lm->ctlm_offsethi);
+		    swap_thing (lm->ctlm_type);
+		    swap_thing (lm->ctlm_offsetlo);
+		  }
+	      }
+	    else
+	      {
+		ctf_member_t *m = (ctf_member_t *) t;
+		for (ssize_t i = vlen; i > 0; i--, m++)
+		  {
+		    swap_thing (m->ctm_name);
+		    swap_thing (m->ctm_offset);
+		    swap_thing (m->ctm_type);
+		  }
+	      }
+	    break;
+	  }
+
+	case CTF_K_ENUM:
+	  {
+	    /* This has an array of ctf_enum_t.  */
+
+	    ctf_enum_t *item = (ctf_enum_t *) t;
+
+	    for (ssize_t i = vlen; i > 0; item++, i--)
+	      {
+		swap_thing (item->cte_name);
+		swap_thing (item->cte_value);
+	      }
+	    break;
+	  }
+	default:
+	  ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n",
+		       kind);
+	  return ECTF_CORRUPT;
+	}
+
+      t = (ctf_type_t *) ((uintptr_t) t + vbytes);
+    }
+
+  return 0;
+}
+
+/* Flip the endianness of BASE, given the offsets in the (already endian-
+   converted) CTH.
+
+   All of this stuff happens before the header is fully initialized, so the
+   LCTF_*() macros cannot be used yet.  Since we do not try to endian-convert v1
+   data, this is no real loss.  */
+
+static int
+flip_ctf (ctf_header_t *cth, unsigned char *base)
+{
+  base += sizeof (ctf_header_t);
+
+  flip_lbls (base + cth->cth_lbloff, cth->cth_objtoff - cth->cth_lbloff);
+  flip_objts (base + cth->cth_objtoff, cth->cth_funcoff - cth->cth_objtoff);
+  flip_objts (base + cth->cth_funcoff, cth->cth_varoff - cth->cth_funcoff);
+  flip_vars (base + cth->cth_varoff, cth->cth_typeoff - cth->cth_varoff);
+  return flip_types (base + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff);
+}
+
+/* Open a CTF file, mocking up a suitable ctf_sect.  */
+ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
+			     const char *symsect, size_t symsect_size,
+			     size_t symsect_entsize,
+			     const char *strsect, size_t strsect_size,
+			     int *errp)
+{
+  ctf_sect_t skeleton;
+
+  ctf_sect_t ctf_sect, sym_sect, str_sect;
+  ctf_sect_t *ctfsectp = NULL;
+  ctf_sect_t *symsectp = NULL;
+  ctf_sect_t *strsectp = NULL;
+
+  skeleton.cts_name = _CTF_SECTION;
+  skeleton.cts_type = SHT_PROGBITS;
+  skeleton.cts_flags = 0;
+  skeleton.cts_entsize = 1;
+  skeleton.cts_offset = 0;
+
+  if (ctfsect)
+    {
+      memcpy (&ctf_sect, &skeleton, sizeof (struct ctf_sect));
+      ctf_sect.cts_data = ctfsect;
+      ctf_sect.cts_size = ctfsect_size;
+      ctfsectp = &ctf_sect;
+    }
+
+  if (symsect)
+    {
+      memcpy (&sym_sect, &skeleton, sizeof (struct ctf_sect));
+      sym_sect.cts_data = symsect;
+      sym_sect.cts_size = symsect_size;
+      sym_sect.cts_entsize = symsect_entsize;
+      symsectp = &sym_sect;
+    }
+
+  if (strsect)
+    {
+      memcpy (&str_sect, &skeleton, sizeof (struct ctf_sect));
+      str_sect.cts_data = strsect;
+      str_sect.cts_size = strsect_size;
+      strsectp = &str_sect;
+    }
+
+  return ctf_bufopen (ctfsectp, symsectp, strsectp, errp);
+}
+
+/* Decode the specified CTF buffer and optional symbol table and create a new
+   CTF container representing the symbolic debugging information.  This code
+   can be used directly by the debugger, or it can be used as the engine for
+   ctf_fdopen() or ctf_open(), below.  */
+
+ctf_file_t *
+ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
+	     const ctf_sect_t *strsect, int *errp)
+{
+  const ctf_preamble_t *pp;
+  ctf_header_t hp;
+  ctf_file_t *fp;
+  void *buf, *base;
+  size_t size, hdrsz;
+  int foreign_endian = 0;
+  int err;
+
+  if (ctfsect == NULL || ((symsect == NULL) != (strsect == NULL)))
+    return (ctf_set_open_errno (errp, EINVAL));
+
+  if (symsect != NULL && symsect->cts_entsize != sizeof (Elf32_Sym) &&
+      symsect->cts_entsize != sizeof (Elf64_Sym))
+    return (ctf_set_open_errno (errp, ECTF_SYMTAB));
+
+  if (symsect != NULL && symsect->cts_data == NULL)
+    return (ctf_set_open_errno (errp, ECTF_SYMBAD));
+
+  if (strsect != NULL && strsect->cts_data == NULL)
+    return (ctf_set_open_errno (errp, ECTF_STRBAD));
+
+  if (ctfsect->cts_size < sizeof (ctf_preamble_t))
+    return (ctf_set_open_errno (errp, ECTF_NOCTFBUF));
+
+  pp = (const ctf_preamble_t *) ctfsect->cts_data;
+
+  ctf_dprintf ("ctf_bufopen: magic=0x%x version=%u\n",
+	       pp->ctp_magic, pp->ctp_version);
+
+  /* Validate each part of the CTF header.
+
+     First, we validate the preamble (common to all versions).  At that point,
+     we know the endianness and specific header version, and can validate the
+     version-specific parts including section offsets and alignments.
+
+     We specifically do not support foreign-endian old versions.  */
+
+  if (_libctf_unlikely_ (pp->ctp_magic != CTF_MAGIC))
+    {
+      if (pp->ctp_magic == bswap_16 (CTF_MAGIC))
+	{
+	  if (pp->ctp_version != CTF_VERSION_3)
+	    return (ctf_set_open_errno (errp, ECTF_CTFVERS));
+	  foreign_endian = 1;
+	}
+      else
+	return (ctf_set_open_errno (errp, ECTF_NOCTFBUF));
+    }
+
+  if (_libctf_unlikely_ (pp->ctp_version != CTF_VERSION_3))
+    return (ctf_set_open_errno (errp, ECTF_CTFVERS));
+
+  if (ctfsect->cts_size < sizeof (ctf_header_t))
+    return (ctf_set_open_errno (errp, ECTF_NOCTFBUF));
+
+  memcpy (&hp, ctfsect->cts_data, sizeof (hp));
+
+  if (foreign_endian)
+    flip_header (&hp);
+
+  hdrsz = sizeof (ctf_header_t);
+
+  size = hp.cth_stroff + hp.cth_strlen;
+
+  ctf_dprintf ("ctf_bufopen: uncompressed size=%lu\n", (unsigned long) size);
+
+  if (hp.cth_lbloff > size || hp.cth_objtoff > size
+      || hp.cth_funcoff > size || hp.cth_typeoff > size || hp.cth_stroff > size)
+    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+
+  if (hp.cth_lbloff > hp.cth_objtoff
+      || hp.cth_objtoff > hp.cth_funcoff
+      || hp.cth_funcoff > hp.cth_typeoff
+      || hp.cth_funcoff > hp.cth_varoff
+      || hp.cth_varoff > hp.cth_typeoff || hp.cth_typeoff > hp.cth_stroff)
+    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+
+  if ((hp.cth_lbloff & 3) || (hp.cth_objtoff & 1)
+      || (hp.cth_funcoff & 1) || (hp.cth_varoff & 3) || (hp.cth_typeoff & 3))
+    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+
+  /* Once everything is determined to be valid, attempt to decompress the CTF
+     data buffer if it is compressed, or copy it into new storage if it is not
+     compressed but needs endian-flipping.  Otherwise we just put the data
+     section's buffer pointer into ctf_buf, below.  */
+
+
+  if (hp.cth_flags & CTF_F_COMPRESS)
+    {
+      size_t srclen, dstlen;
+      const void *src;
+      int rc = Z_OK;
+
+      if ((base = ctf_data_alloc (size + hdrsz)) == MAP_FAILED)
+	return (ctf_set_open_errno (errp, ECTF_ZALLOC));
+
+      memcpy (base, ctfsect->cts_data, hdrsz);
+      ((ctf_preamble_t *) base)->ctp_flags &= ~CTF_F_COMPRESS;
+      buf = (unsigned char *) base + hdrsz;
+
+      src = (unsigned char *) ctfsect->cts_data + hdrsz;
+      srclen = ctfsect->cts_size - hdrsz;
+      dstlen = size;
+
+      if ((rc = uncompress (buf, &dstlen, src, srclen)) != Z_OK)
+	{
+	  ctf_dprintf ("zlib inflate err: %s\n", zError (rc));
+	  ctf_data_free (base, size + hdrsz);
+	  return (ctf_set_open_errno (errp, ECTF_DECOMPRESS));
+	}
+
+      if (dstlen != size)
+	{
+	  ctf_dprintf ("zlib inflate short -- got %lu of %lu "
+		       "bytes\n", (unsigned long) dstlen, (unsigned long) size);
+	  ctf_data_free (base, size + hdrsz);
+	  return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+	}
+
+    }
+  else if (foreign_endian)
+    {
+      if ((base = ctf_data_alloc (size + hdrsz)) == MAP_FAILED)
+	return (ctf_set_open_errno (errp, ECTF_ZALLOC));
+    }
+  else
+    {
+      base = (void *) ctfsect->cts_data;
+      buf = (unsigned char *) base + hdrsz;
+    }
+
+  /* Once we have uncompressed and validated the CTF data buffer, we can
+     proceed with allocating a ctf_file_t and initializing it.
+
+     Nothing that depends on buf or base should be set directly in this function
+     before the init_types() call, because it may be reallocated during
+     transparent upgrade if this recension of libctf is so configured: see
+     ctf_set_base() and ctf_realloc_base().  */
+
+  if ((fp = ctf_alloc (sizeof (ctf_file_t))) == NULL)
+    return (ctf_set_open_errno (errp, ENOMEM));
+
+  memset (fp, 0, sizeof (ctf_file_t));
+  ctf_set_version (fp, &hp, hp.cth_version);
+
+  fp->ctf_parmax = CTF_MAX_PTYPE;
+
+  memcpy (&fp->ctf_data, ctfsect, sizeof (ctf_sect_t));
+
+  if (symsect != NULL)
+    {
+      memcpy (&fp->ctf_symtab, symsect, sizeof (ctf_sect_t));
+      memcpy (&fp->ctf_strtab, strsect, sizeof (ctf_sect_t));
+    }
+
+  if (fp->ctf_data.cts_name != NULL)
+    fp->ctf_data.cts_name = ctf_strdup (fp->ctf_data.cts_name);
+  if (fp->ctf_symtab.cts_name != NULL)
+    fp->ctf_symtab.cts_name = ctf_strdup (fp->ctf_symtab.cts_name);
+  if (fp->ctf_strtab.cts_name != NULL)
+    fp->ctf_strtab.cts_name = ctf_strdup (fp->ctf_strtab.cts_name);
+
+  if (fp->ctf_data.cts_name == NULL)
+    fp->ctf_data.cts_name = _CTF_NULLSTR;
+  if (fp->ctf_symtab.cts_name == NULL)
+    fp->ctf_symtab.cts_name = _CTF_NULLSTR;
+  if (fp->ctf_strtab.cts_name == NULL)
+    fp->ctf_strtab.cts_name = _CTF_NULLSTR;
+
+  if (strsect != NULL)
+    {
+      fp->ctf_str[CTF_STRTAB_1].cts_strs = strsect->cts_data;
+      fp->ctf_str[CTF_STRTAB_1].cts_len = strsect->cts_size;
+    }
+
+  if (foreign_endian &&
+      (err = flip_ctf (&hp, base)) != 0)
+    {
+      /* We can be certain that flip_ctf() will have endian-flipped everything
+         other than the types table when we return.  In particular the header
+         is fine, so set it, to allow freeing to use the usual code path.  */
+
+      (void) ctf_set_open_errno (errp, err);
+      ctf_set_base (fp, &hp, base);
+      goto bad;
+    }
+
+  ctf_set_base (fp, &hp, base);
+  fp->ctf_size = size + hdrsz;
+
+  if ((err = init_types (fp, &hp)) != 0)
+    {
+      (void) ctf_set_open_errno (errp, err);
+      goto bad;
+    }
+
+  /* The ctf region may have been reallocated by init_types(), but now
+     that is done, it will not move again, so we can protect it, as long
+     as it didn't come from the ctfsect, wihcih might have been allocated
+     with malloc().  */
+
+  if (fp->ctf_base != (void *) ctfsect->cts_data)
+    ctf_data_protect ((void *) fp->ctf_base, fp->ctf_size);
+
+  /* If we have a symbol table section, allocate and initialize
+     the symtab translation table, pointed to by ctf_sxlate.  */
+
+  if (symsect != NULL)
+    {
+      fp->ctf_nsyms = symsect->cts_size / symsect->cts_entsize;
+      fp->ctf_sxlate = ctf_alloc (fp->ctf_nsyms * sizeof (uint32_t));
+
+      if (fp->ctf_sxlate == NULL)
+	{
+	  (void) ctf_set_open_errno (errp, ENOMEM);
+	  goto bad;
+	}
+
+      if ((err = init_symtab (fp, &hp, symsect, strsect)) != 0)
+	{
+	  (void) ctf_set_open_errno (errp, err);
+	  goto bad;
+	}
+    }
+
+  /* Initialize the ctf_lookup_by_name top-level dictionary.  We keep an
+     array of type name prefixes and the corresponding ctf_hash to use.
+     NOTE: This code must be kept in sync with the code in ctf_update().  */
+  fp->ctf_lookups[0].ctl_prefix = "struct";
+  fp->ctf_lookups[0].ctl_len = strlen (fp->ctf_lookups[0].ctl_prefix);
+  fp->ctf_lookups[0].ctl_hash = fp->ctf_structs;
+  fp->ctf_lookups[1].ctl_prefix = "union";
+  fp->ctf_lookups[1].ctl_len = strlen (fp->ctf_lookups[1].ctl_prefix);
+  fp->ctf_lookups[1].ctl_hash = fp->ctf_unions;
+  fp->ctf_lookups[2].ctl_prefix = "enum";
+  fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix);
+  fp->ctf_lookups[2].ctl_hash = fp->ctf_enums;
+  fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR;
+  fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix);
+  fp->ctf_lookups[3].ctl_hash = fp->ctf_names;
+  fp->ctf_lookups[4].ctl_prefix = NULL;
+  fp->ctf_lookups[4].ctl_len = 0;
+  fp->ctf_lookups[4].ctl_hash = NULL;
+
+  if (symsect != NULL)
+    {
+      if (symsect->cts_entsize == sizeof (Elf64_Sym))
+	(void) ctf_setmodel (fp, CTF_MODEL_LP64);
+      else
+	(void) ctf_setmodel (fp, CTF_MODEL_ILP32);
+    }
+  else
+    (void) ctf_setmodel (fp, CTF_MODEL_NATIVE);
+
+  fp->ctf_refcnt = 1;
+  return fp;
+
+bad:
+  ctf_close (fp);
+  return NULL;
+}
+
+/* Close the specified CTF container and free associated data structures.  Note
+   that ctf_close() is a reference counted operation: if the specified file is
+   the parent of other active containers, its reference count will be greater
+   than one and it will be freed later when no active children exist.  */
+
+void
+ctf_close (ctf_file_t *fp)
+{
+  ctf_dtdef_t *dtd, *ntd;
+  ctf_dvdef_t *dvd, *nvd;
+
+  if (fp == NULL)
+    return;		   /* Allow ctf_close(NULL) to simplify caller code.  */
+
+  ctf_dprintf ("ctf_close(%p) refcnt=%u\n", (void *) fp, fp->ctf_refcnt);
+
+  if (fp->ctf_refcnt > 1)
+    {
+      fp->ctf_refcnt--;
+      return;
+    }
+
+  if (fp->ctf_dynparname != NULL)
+    ctf_free (fp->ctf_dynparname, strlen (fp->ctf_dynparname) + 1);
+
+  if (fp->ctf_parent != NULL)
+    ctf_close (fp->ctf_parent);
+
+  for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
+    {
+      ntd = ctf_list_next (dtd);
+      ctf_dtd_delete (fp, dtd);
+    }
+  ctf_dynhash_destroy (fp->ctf_dthash);
+  ctf_dynhash_destroy (fp->ctf_dtbyname);
+
+  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
+    {
+      nvd = ctf_list_next (dvd);
+      ctf_dvd_delete (fp, dvd);
+    }
+  ctf_dynhash_destroy (fp->ctf_dvhash);
+
+  ctf_free (fp->ctf_tmp_typeslice, fp->ctf_tmp_typeslicelen);
+
+  if (fp->ctf_flags & LCTF_MMAP)
+    {
+      if (fp->ctf_data.cts_data != NULL)
+	ctf_sect_munmap (&fp->ctf_data);
+      if (fp->ctf_symtab.cts_data != NULL)
+	ctf_sect_munmap (&fp->ctf_symtab);
+      if (fp->ctf_strtab.cts_data != NULL)
+	ctf_sect_munmap (&fp->ctf_strtab);
+    }
+
+  if (fp->ctf_data.cts_name != _CTF_NULLSTR && fp->ctf_data.cts_name != NULL)
+      ctf_free ((char *) fp->ctf_data.cts_name,
+		strlen (fp->ctf_data.cts_name) + 1);
+
+  if (fp->ctf_symtab.cts_name != _CTF_NULLSTR &&
+      fp->ctf_symtab.cts_name != NULL)
+      ctf_free ((char *) fp->ctf_symtab.cts_name,
+		strlen (fp->ctf_symtab.cts_name) + 1);
+
+  if (fp->ctf_strtab.cts_name != _CTF_NULLSTR &&
+      fp->ctf_strtab.cts_name != NULL)
+      ctf_free ((char *) fp->ctf_strtab.cts_name,
+		strlen (fp->ctf_strtab.cts_name) + 1);
+
+  ctf_free_base (fp, NULL, 0);
+
+  if (fp->ctf_sxlate != NULL)
+    ctf_free (fp->ctf_sxlate, sizeof (uint32_t) * fp->ctf_nsyms);
+
+  if (fp->ctf_txlate != NULL)
+      ctf_free (fp->ctf_txlate, sizeof (uint32_t) * (fp->ctf_typemax + 1));
+
+  if (fp->ctf_ptrtab != NULL)
+      ctf_free (fp->ctf_ptrtab, sizeof (uint32_t) * (fp->ctf_typemax + 1));
+
+  ctf_hash_destroy (fp->ctf_structs);
+  ctf_hash_destroy (fp->ctf_unions);
+  ctf_hash_destroy (fp->ctf_enums);
+  ctf_hash_destroy (fp->ctf_names);
+
+  ctf_free (fp, sizeof (ctf_file_t));
+}
+
+/* Return the ctfsect out of the core ctf_impl.  Useful for freeing the
+   ctfsect's data * after ctf_close(), which is why we return the actual
+   structure, not a pointer to it, since that is likely to become a pointer to
+   freed data before the return value is used under the expected use case of
+   ctf_getsect()/ ctf_close()/free().  */
+extern ctf_sect_t
+ctf_getdatasect (const ctf_file_t *fp)
+{
+  return fp->ctf_data;
+}
+
+/* Return the CTF handle for the parent CTF container, if one exists.
+   Otherwise return NULL to indicate this container has no imported parent.  */
+ctf_file_t *
+ctf_parent_file (ctf_file_t *fp)
+{
+  return fp->ctf_parent;
+}
+
+/* Return the name of the parent CTF container, if one exists.  Otherwise
+   return NULL to indicate this container is a root container.  */
+const char *
+ctf_parent_name (ctf_file_t *fp)
+{
+  return fp->ctf_parname;
+}
+
+/* Set the parent name.  It is an error to call this routine without calling
+   ctf_import() at some point.  */
+void
+ctf_parent_name_set (ctf_file_t *fp, const char *name)
+{
+  if (fp->ctf_dynparname != NULL)
+    ctf_free (fp->ctf_dynparname, strlen (fp->ctf_dynparname) + 1);
+
+  fp->ctf_dynparname = ctf_strdup (name);
+  fp->ctf_parname = fp->ctf_dynparname;
+}
+
+/* Import the types from the specified parent container by storing a pointer
+   to it in ctf_parent and incrementing its reference count.  Only one parent
+   is allowed: if a parent already exists, it is replaced by the new parent.  */
+int
+ctf_import (ctf_file_t *fp, ctf_file_t *pfp)
+{
+  if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
+    return (ctf_set_errno (fp, EINVAL));
+
+  if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
+    return (ctf_set_errno (fp, ECTF_DMODEL));
+
+  if (fp->ctf_parent != NULL)
+    ctf_close (fp->ctf_parent);
+
+  if (pfp != NULL)
+    {
+      fp->ctf_flags |= LCTF_CHILD;
+      pfp->ctf_refcnt++;
+
+      if (fp->ctf_parname == NULL)
+	ctf_parent_name_set (fp, "PARENT");
+    }
+  fp->ctf_parent = pfp;
+  return 0;
+}
+
+/* Set the data model constant for the CTF container.  */
+int
+ctf_setmodel (ctf_file_t *fp, int model)
+{
+  const ctf_dmodel_t *dp;
+
+  for (dp = _libctf_models; dp->ctd_name != NULL; dp++)
+    {
+      if (dp->ctd_code == model)
+	{
+	  fp->ctf_dmodel = dp;
+	  return 0;
+	}
+    }
+
+  return (ctf_set_errno (fp, EINVAL));
+}
+
+/* Return the data model constant for the CTF container.  */
+int
+ctf_getmodel (ctf_file_t *fp)
+{
+  return fp->ctf_dmodel->ctd_code;
+}
+
+void
+ctf_setspecific (ctf_file_t *fp, void *data)
+{
+  fp->ctf_specific = data;
+}
+
+void *
+ctf_getspecific (ctf_file_t *fp)
+{
+  return fp->ctf_specific;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 19/19] binutils: CTF support for objdump and readelf
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (7 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 10/19] libctf: ELF file opening Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` CTF format overview Nick Alcock
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

This introduces CTF support for objdump and readelf, with the same
syntax for both:

     --ctf=SECTION: display CTF in the given SECTION
     --ctf-symbols=SECTION: name of symbol table section (optional)
     --ctf-strings=SECTION: name of string table section (optional)
     --ctf-parent=SECTION: name of CTF section that is the parent of this section

Nearly all the work is done by the ctf_dump machinery in libctf: most of
the remaining work is option-processing and section-reading, and thus is
different for objdump and readelf: the minimal amount of similar code
remaining is, in my view, too small to share.

I am not particularly satisfied with the way resources are freed in
either of these (I was forced to do it at the top level, for lack of
anywhere else to free resources allocated during option processing), but
I can't see any better way to do it without introducing new
infrastructure for no other purpose.

There are essentially arbitrary ordering changes to the Makefile.in's
order of libtool-related stuff that I can't get rid of, but they have no
semantic effect.  (It is possible that some hunks of these changes could
be dropped, but that seems a bit risky to me.)

binutils/
	* objdump.c (ctf-api.h): New include.
	(dump_ctf_section_info): New variable.
	(dump_ctf_section_name): Likewise.
	(dump_ctf_symtab_name): Likewise.
	(dump_ctf_strtab_name): Likewise.
	(usage): Describe new options.
	(enum option_values): Add OPTION_CTF,
	OPTION_CTF_SYMBOLS, OPTION_CTF_STRINGS, and OPTION_CTF_PARENT.
	(main): Use them to add --ctf, --ctf-symbols, --ctf-strings, and
	--ctf-parent.
	(read_section_stabs): Add new parameter, entsize_ptr.
	(find_stabs_section): Adjust accordingly.
	(dump_ctf_indent_lines): New.
	(dump_ctf): New.
	(dump_bfd): Call it.  Free resources afterwards.
	* readelf.c (ctf-api.h): New include.
	(CTF_DUMP): New.
	(static bfd_boolean do_ctf): Likewise.
	(dump_ctf_parent_name): Likewise.
	(dump_ctf_symtab_name): Likewise.
	(dump_ctf_strtab_name): Likewise.
	(OPTION_CTF_DUMP): Likewise.
	(OPTION_CTF_PARENT): Likewise.
	(OPTION_CTF_SYMBOLS): Likewise.
	(OPTION_CTF_STRINGS): Likewise.
	(options): Add them.
	(usage): Likewise.
	(parse_args): Handle the new options, requesting CTF_DUMP.
	(process_section_contents): Handle CTF_DUMP.
	(shdr_to_ctf_sect): New.
	(dump_ctf_indent_lines): New.
	(dump_section_as_ctf): New.
	(main): Free resources.
	* Makefile.am (LIBCTF): New variable.
	(objdump_DEPENDENCIES): Use it.
	(readelf_DEPENDENCIES): Likewise.
	(objdump_LDADD): Likewise.
	(readelf_LDADD): Likewise.
	* aclocal.m4: Regenerated.
	* Makefile.in: Likewise.

	* doc/binutils.texi (objdump): Document the new options.
	(readelf): Likewise.
	* doc/ctf.options.texi: New.
	* doc/Makefile.in: Regenerated.
---
 binutils/Makefile.am          |  10 +-
 binutils/Makefile.in          |  18 +--
 binutils/aclocal.m4           |  10 +-
 binutils/doc/Makefile.in      |   9 +-
 binutils/doc/binutils.texi    |  12 ++
 binutils/doc/ctf.options.texi |  19 ++++
 binutils/objdump.c            | 156 ++++++++++++++++++++++++-
 binutils/readelf.c            | 206 ++++++++++++++++++++++++++++++++++
 8 files changed, 414 insertions(+), 26 deletions(-)
 create mode 100644 binutils/doc/ctf.options.texi

diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index 7d59d8c4b5..128494ca9e 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -161,6 +161,8 @@ BFDLIB = ../bfd/libbfd.la
 
 OPCODES = ../opcodes/libopcodes.la
 
+LIBCTF = ../libctf/libctf.a
+
 LIBIBERTY = ../libiberty/libiberty.a
 
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
@@ -211,7 +213,7 @@ installcheck-local:
 # which depends on libintl, since we don't know whether LIBINTL_DEP will be
 # non-empty until configure time.  Ugh!
 size_DEPENDENCIES =      $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-objdump_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(OBJDUMP_PRIVATE_OFILES)
+objdump_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES)
 nm_new_DEPENDENCIES =    $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 ar_DEPENDENCIES =        $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 strings_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -226,7 +228,7 @@ dlltool_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windres_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES =    $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-readelf_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY)
+readelf_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF)
 elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY)
 bfdtest1_DEPENDENCIES =  $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -241,7 +243,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS)
-readelf_LDADD   = $(LIBINTL) $(LIBIBERTY) $(ZLIB)
+readelf_LDADD   = $(LIBINTL) $(LIBCTF) $(LIBIBERTY) $(ZLIB)
 
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
@@ -252,7 +254,7 @@ nm_new_SOURCES = nm.c $(BULIBS)
 
 objdump_SOURCES = objdump.c dwarf.c prdbg.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS)
 EXTRA_objdump_SOURCES = od-xcoff.c
-objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
+objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
 
 objdump.@OBJEXT@:objdump.c
 if am__fastdepCC
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index f6cb22f95a..480385bd67 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -119,7 +119,10 @@ EXTRA_PROGRAMS = srconv$(EXEEXT) sysdump$(EXEEXT) coffdump$(EXEEXT) \
 	$(am__EXEEXT_4)
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/gettext-sister.m4 \
@@ -135,9 +138,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
-	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
-	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
 	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
@@ -647,6 +648,7 @@ BULIBS = bucomm.c version.c filemode.c
 ELFLIBS = elfcomm.c
 BFDLIB = ../bfd/libbfd.la
 OPCODES = ../opcodes/libopcodes.la
+LIBCTF = ../libctf/libctf.a
 LIBIBERTY = ../libiberty/libiberty.a
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
 EXPECT = expect
@@ -671,7 +673,7 @@ CC_FOR_TARGET = ` \
 # which depends on libintl, since we don't know whether LIBINTL_DEP will be
 # non-empty until configure time.  Ugh!
 size_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-objdump_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(OBJDUMP_PRIVATE_OFILES)
+objdump_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES)
 nm_new_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 ar_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 strings_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -686,7 +688,7 @@ dlltool_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windres_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-readelf_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
+readelf_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF)
 elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 bfdtest1_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -696,14 +698,14 @@ size_SOURCES = size.c $(BULIBS)
 objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS)
-readelf_LDADD = $(LIBINTL) $(LIBIBERTY) $(ZLIB)
+readelf_LDADD = $(LIBINTL) $(LIBCTF) $(LIBIBERTY) $(ZLIB)
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 nm_new_SOURCES = nm.c $(BULIBS)
 objdump_SOURCES = objdump.c dwarf.c prdbg.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS)
 EXTRA_objdump_SOURCES = od-xcoff.c
-objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
+objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
 cxxfilt_SOURCES = cxxfilt.c $(BULIBS)
 ar_SOURCES = arparse.y arlex.l ar.c not-ranlib.c arsup.c rename.c binemul.c \
 	emul_$(EMULATION).c $(BULIBS)
diff --git a/binutils/aclocal.m4 b/binutils/aclocal.m4
index 4fa32fffd8..1b1320fd1a 100644
--- a/binutils/aclocal.m4
+++ b/binutils/aclocal.m4
@@ -1185,6 +1185,11 @@ AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([../libtool.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
 m4_include([../bfd/acinclude.m4])
 m4_include([../bfd/warning.m4])
 m4_include([../config/acx.m4])
@@ -1203,8 +1208,3 @@ m4_include([../config/plugins.m4])
 m4_include([../config/po.m4])
 m4_include([../config/progtest.m4])
 m4_include([../config/zlib.m4])
-m4_include([../libtool.m4])
-m4_include([../ltoptions.m4])
-m4_include([../ltsugar.m4])
-m4_include([../ltversion.m4])
-m4_include([../lt~obsolete.m4])
diff --git a/binutils/doc/Makefile.in b/binutils/doc/Makefile.in
index a0777d8fcc..7fa622a364 100644
--- a/binutils/doc/Makefile.in
+++ b/binutils/doc/Makefile.in
@@ -108,7 +108,10 @@ host_triplet = @host@
 target_triplet = @target@
 subdir = doc
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/gettext-sister.m4 \
@@ -124,9 +127,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/plugins.m4 \
 	$(top_srcdir)/../config/po.m4 \
 	$(top_srcdir)/../config/progtest.m4 \
-	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \
-	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
-	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/../config/zlib.m4 \
 	$(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 01f1e5f56d..e66dc4dbb1 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2104,6 +2104,7 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{-s}|@option{--full-contents}]
         [@option{-W[lLiaprmfFsoRtUuTgAckK]}|
          @option{--dwarf}[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links,=follow-links]]
+        [@option{--ctf=}@var{section}]
         [@option{-G}|@option{--stabs}]
         [@option{-t}|@option{--syms}]
         [@option{-T}|@option{--dynamic-syms}]
@@ -2116,6 +2117,9 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{--adjust-vma=}@var{offset}]
         [@option{--dwarf-depth=@var{n}}]
         [@option{--dwarf-start=@var{n}}]
+        [@option{--ctf-parent=}@var{section}]
+        [@option{--ctf-symbols=}@var{section}]
+        [@option{--ctf-strings=}@var{section}]
         [@option{--no-recurse-limit}|@option{--recurse-limit}]
         [@option{--special-syms}]
         [@option{--prefix=}@var{prefix}]
@@ -2623,6 +2627,8 @@ instructions.
 @item --dwarf-check
 Enable additional checks for consistency of Dwarf information.
 
+@include ctf.options.texi
+
 @item -G
 @itemx --stabs
 @cindex stab
@@ -4622,6 +4628,10 @@ readelf [@option{-a}|@option{--all}]
          @option{--debug-dump}[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links,=follow-links]]
         [@option{--dwarf-depth=@var{n}}]
         [@option{--dwarf-start=@var{n}}]
+        [@option{--ctf=}@var{section}]
+        [@option{--ctf-parent=}@var{section}]
+        [@option{--ctf-symbols=}@var{section}]
+        [@option{--ctf-strings=}@var{section}]
         [@option{-I}|@option{--histogram}]
         [@option{-v}|@option{--version}]
         [@option{-W}|@option{--wide}]
@@ -4802,6 +4812,8 @@ command to @command{ar}, but without using the BFD library.  @xref{ar}.
 @itemx --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index,=addr,=cu_index,=links,=follow-links]
 @include debug.options.texi
 
+@include ctf.options.texi
+
 @item -I
 @itemx --histogram
 Display a histogram of bucket list lengths when displaying the contents
diff --git a/binutils/doc/ctf.options.texi b/binutils/doc/ctf.options.texi
new file mode 100644
index 0000000000..d9e49e4b7e
--- /dev/null
+++ b/binutils/doc/ctf.options.texi
@@ -0,0 +1,19 @@
+@c This file contains the entry for the --ctf, --ctf-parent, --ctf-symbols, -and
+@c --ctf-strings options that are common to both readelf and objdump.
+
+@item --ctf=@var{section}
+@cindex CTF
+@cindex Compact Type Format
+
+Display the contents of the specified CTF section.  CTF sections themselves
+contain many subsections, all of which are displayed in order.
+
+@item --ctf-parent=@var{section}
+@item --ctf-symbols=@var{section}
+@item --ctf-strings=@var{section}
+
+Specify the names of other sections from which the CTF file can inherit
+types, strings, and symbols.
+
+If either of @option{--ctf-symbols} or @option{--ctf-strings} is specified, the
+other must be specified as well.
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 872539068c..adb029729a 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -56,6 +56,7 @@
 #include "bucomm.h"
 #include "elfcomm.h"
 #include "dwarf.h"
+#include "ctf-api.h"
 #include "getopt.h"
 #include "safe-ctype.h"
 #include "dis-asm.h"
@@ -98,6 +99,11 @@ static bfd_boolean with_source_code;	/* -S */
 static int show_raw_insn;		/* --show-raw-insn */
 static int dump_dwarf_section_info;	/* --dwarf */
 static int dump_stab_section_info;	/* --stabs */
+static int dump_ctf_section_info;       /* --ctf */
+static char *dump_ctf_section_name;
+static char *dump_ctf_symtab_name;	/* --ctf-symbols */
+static char *dump_ctf_strtab_name;	/* --ctf-strings */
+static char *dump_ctf_parent_name;	/* --ctf-parent */
 static int do_demangle;			/* -C, --demangle */
 static bfd_boolean disassemble;		/* -d */
 static bfd_boolean disassemble_all;	/* -D */
@@ -225,6 +231,7 @@ usage (FILE *stream, int status)
           =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,\n\
           =addr,=cu_index,=links,=follow-links]\n\
                            Display DWARF info in the file\n\
+  --ctf=SECTION            Display CTF info from SECTION\n\
   -t, --syms               Display the contents of the symbol table(s)\n\
   -T, --dynamic-syms       Display the contents of the dynamic symbol table\n\
   -r, --reloc              Display the relocation entries in the file\n\
@@ -273,7 +280,10 @@ usage (FILE *stream, int status)
       --dwarf-start=N        Display DIEs starting with N, at the same depth\n\
                              or deeper\n\
       --dwarf-check          Make additional dwarf internal consistency checks.\
-      \n\n"));
+      \n\
+      --ctf-parent=SECTION     Use SECTION as the CTF parent\n\
+      --ctf-symbols=SECTION    Use SECTION as the CTF external symbol table\n\
+      --ctf-strings=SECTION    Use SECTION as the CTF external string table\n\n"));
       list_supported_targets (program_name, stream);
       list_supported_architectures (program_name, stream);
 
@@ -308,7 +318,11 @@ enum option_values
     OPTION_DWARF_START,
     OPTION_RECURSE_LIMIT,
     OPTION_NO_RECURSE_LIMIT,
-    OPTION_INLINES
+    OPTION_INLINES,
+    OPTION_CTF,
+    OPTION_CTF_SYMBOLS,
+    OPTION_CTF_STRINGS,
+    OPTION_CTF_PARENT
   };
 
 static struct option long_options[]=
@@ -351,6 +365,10 @@ static struct option long_options[]=
   {"special-syms", no_argument, &dump_special_syms, 1},
   {"include", required_argument, NULL, 'I'},
   {"dwarf", optional_argument, NULL, OPTION_DWARF},
+  {"ctf", required_argument, NULL, OPTION_CTF},
+  {"ctf-symbols", required_argument, NULL, OPTION_CTF_SYMBOLS},
+  {"ctf-strings", required_argument, NULL, OPTION_CTF_STRINGS},
+  {"ctf-parent", required_argument, NULL, OPTION_CTF_PARENT},
   {"stabs", no_argument, NULL, 'G'},
   {"start-address", required_argument, NULL, OPTION_START_ADDRESS},
   {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS},
@@ -2960,7 +2978,8 @@ dump_dwarf (bfd *abfd)
    it.  Return NULL on failure.   */
 
 static bfd_byte *
-read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr)
+read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr,
+		    bfd_size_type *entsize_ptr)
 {
   asection *stabsect;
   bfd_byte *contents;
@@ -2984,6 +3003,8 @@ read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr)
     }
 
   *size_ptr = bfd_section_size (abfd, stabsect);
+  if (entsize_ptr)
+    *entsize_ptr = stabsect->entsize;
 
   return contents;
 }
@@ -3107,11 +3128,11 @@ find_stabs_section (bfd *abfd, asection *section, void *names)
     {
       if (strtab == NULL)
 	strtab = read_section_stabs (abfd, sought->string_section_name,
-				     &stabstr_size);
+				     &stabstr_size, NULL);
 
       if (strtab)
 	{
-	  stabs = read_section_stabs (abfd, section->name, &stab_size);
+	  stabs = read_section_stabs (abfd, section->name, &stab_size, NULL);
 	  if (stabs)
 	    print_section_stabs (abfd, section->name, &sought->string_offset);
 	}
@@ -3173,6 +3194,110 @@ dump_bfd_header (bfd *abfd)
   bfd_printf_vma (abfd, abfd->start_address);
   printf ("\n");
 }
+\f
+
+/* Formatting callback function passed to ctf_dump.  Returns either the pointer
+   it is passed, or a pointer to newly-allocated storage, in which case
+   dump_ctf() will free it when it no longer needs it.  */
+
+static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
+				    char *s, void *arg)
+{
+  char *spaces = arg;
+  char *new_s;
+
+  if (asprintf (&new_s, "%s%s", spaces, s) < 0)
+    return s;
+  return new_s;
+}
+
+/* Dump the CTF debugging information.  */
+
+static void
+dump_ctf (bfd *abfd, const char *sect_name, const char *symtab_name,
+	  const char *strtab_name, const char *parent_name)
+{
+  bfd_byte *ctfdata, *symdata = NULL, *strdata = NULL, *parentdata = NULL;
+  bfd_size_type ctfsize, symsize, symentsize, strsize, parentsize;
+  ctf_file_t *ctf;
+  ctf_file_t *parent = NULL;
+  const char *things[] = {"Labels", "Data objects", "Function objects",
+			  "Variables", "Types", "Strings", ""};
+  const char **thing;
+  int err;
+  size_t i;
+
+  if ((ctfdata = read_section_stabs (abfd, sect_name, &ctfsize, NULL)) == NULL)
+      bfd_fatal (bfd_get_filename (abfd));
+
+  if (symtab_name
+      && (symdata = read_section_stabs (abfd, symtab_name, &symsize,
+					&symentsize)) == NULL)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  if (strtab_name
+      && (strdata = read_section_stabs (abfd, strtab_name, &strsize,
+					NULL)) == NULL)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  if (parent_name
+      && (parentdata = read_section_stabs (abfd, parent_name, &parentsize,
+					   NULL)) == NULL)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  /* Load the CTF file and dump it.  */
+
+  if ((ctf = ctf_simple_open ((void *) ctfdata, ctfsize,
+			      (void *) symdata, symsize, symentsize,
+			      (void *) strdata, strsize, &err)) == NULL)
+    {
+      non_fatal (_("CTF open failure: %s\n"), ctf_errmsg (err));
+      bfd_fatal (bfd_get_filename (abfd));
+    }
+
+  if (parentdata)
+    {
+      if ((parent = ctf_simple_open ((void *) parentdata, parentsize,
+				     (void *) symdata, symsize, symentsize,
+				     (void *) strdata, strsize, &err)) == NULL)
+	{
+	  non_fatal (_("CTF open failure: %s\n"), ctf_errmsg (err));
+	  bfd_fatal (bfd_get_filename (abfd));
+	}
+
+      ctf_import (ctf, parent);
+    }
+
+  printf (_("Contents of CTF section %s:\n"), sanitize_string (sect_name));
+
+  for (i = 1, thing = things; *thing[0]; thing++, i++)
+    {
+      ctf_dump_state_t *s = NULL;
+      char *item;
+
+      printf ("\n  %s:\n", *thing);
+      while ((item = ctf_dump (ctf, &s, i, dump_ctf_indent_lines,
+			       (void *) "    ")) != NULL)
+	{
+	  printf ("%s\n", item);
+	  free (item);
+	}
+
+      if (ctf_errno (ctf))
+	{
+	  non_fatal (_("Iteration failed: %s, %s\n"), *thing,
+		   ctf_errmsg (ctf_errno (ctf)));
+	  break;
+	}
+    }
+
+  ctf_close (ctf);
+  ctf_close (parent);
+  free (parentdata);
+  free (symdata);
+  free (strdata);
+  free (ctfdata);
+}
 
 \f
 static void
@@ -3812,6 +3937,9 @@ dump_bfd (bfd *abfd)
     dump_symbols (abfd, TRUE);
   if (dump_dwarf_section_info)
     dump_dwarf (abfd);
+  if (dump_ctf_section_info)
+    dump_ctf (abfd, dump_ctf_section_name, dump_ctf_symtab_name,
+	      dump_ctf_strtab_name, dump_ctf_parent_name);
   if (dump_stab_section_info)
     dump_stabs (abfd);
   if (dump_reloc_info && ! disassemble)
@@ -4248,6 +4376,20 @@ main (int argc, char **argv)
 	case OPTION_DWARF_CHECK:
 	  dwarf_check = TRUE;
 	  break;
+        case OPTION_CTF:
+          dump_ctf_section_info = TRUE;
+          dump_ctf_section_name = xstrdup (optarg);
+          seenflag = TRUE;
+          break;
+	case OPTION_CTF_SYMBOLS:
+	  dump_ctf_symtab_name = xstrdup (optarg);
+	  break;
+	case OPTION_CTF_STRINGS:
+	  dump_ctf_strtab_name = xstrdup (optarg);
+	  break;
+	case OPTION_CTF_PARENT:
+	  dump_ctf_parent_name = xstrdup (optarg);
+	  break;
 	case 'G':
 	  dump_stab_section_info = TRUE;
 	  seenflag = TRUE;
@@ -4307,6 +4449,10 @@ main (int argc, char **argv)
     }
 
   free_only_list ();
+  free (dump_ctf_section_name);
+  free (dump_ctf_symtab_name);
+  free (dump_ctf_strtab_name);
+  free (dump_ctf_parent_name);
 
   END_PROGRESS (program_name);
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 77acc6a7b4..2a35e2c4c8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -60,6 +60,7 @@
 #include "bucomm.h"
 #include "elfcomm.h"
 #include "dwarf.h"
+#include "ctf-api.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
@@ -182,6 +183,7 @@ typedef struct elf_section_list
 #define DEBUG_DUMP	(1 << 2)	/* The -w command line switch.  */
 #define STRING_DUMP     (1 << 3)	/* The -p command line switch.  */
 #define RELOC_DUMP      (1 << 4)	/* The -R command line switch.  */
+#define CTF_DUMP        (1 << 5)        /* The --ctf command line switch.  */
 
 typedef unsigned char dump_type;
 
@@ -248,12 +250,17 @@ static bfd_boolean do_dump = FALSE;
 static bfd_boolean do_version = FALSE;
 static bfd_boolean do_histogram = FALSE;
 static bfd_boolean do_debugging = FALSE;
+static bfd_boolean do_ctf = FALSE;
 static bfd_boolean do_arch = FALSE;
 static bfd_boolean do_notes = FALSE;
 static bfd_boolean do_archive_index = FALSE;
 static bfd_boolean is_32bit_elf = FALSE;
 static bfd_boolean decompress_dumps = FALSE;
 
+static char *dump_ctf_parent_name;
+static char *dump_ctf_symtab_name;
+static char *dump_ctf_strtab_name;
+
 struct group_list
 {
   struct group_list *  next;
@@ -4371,6 +4378,10 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
 #define OPTION_DWARF_DEPTH	514
 #define OPTION_DWARF_START	515
 #define OPTION_DWARF_CHECK	516
+#define OPTION_CTF_DUMP		517
+#define OPTION_CTF_PARENT	518
+#define OPTION_CTF_SYMBOLS	519
+#define OPTION_CTF_STRINGS	520
 
 static struct option options[] =
 {
@@ -4409,6 +4420,12 @@ static struct option options[] =
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
 
+  {"ctf",              required_argument, 0, OPTION_CTF_DUMP},
+
+  {"ctf-symbols",      required_argument, 0, OPTION_CTF_SYMBOLS},
+  {"ctf-strings",      required_argument, 0, OPTION_CTF_STRINGS},
+  {"ctf-parent",       required_argument, 0, OPTION_CTF_PARENT},
+
   {"version",	       no_argument, 0, 'v'},
   {"wide",	       no_argument, 0, 'W'},
   {"help",	       no_argument, 0, 'H'},
@@ -4458,6 +4475,15 @@ usage (FILE * stream)
   --dwarf-depth=N        Do not display DIEs at depth N or greater\n\
   --dwarf-start=N        Display DIEs starting with N, at the same depth\n\
                          or deeper\n"));
+  fprintf (stream, _("\
+  --ctf=<number|name>    Display CTF info from section <number|name>\n\
+  --ctf-parent=<number|name>\n\
+                         Use section <number|name> as the CTF parent\n\n\
+  --ctf-symbols=<number|name>\n\
+                         Use section <number|name> as the CTF external symtab\n\n\
+  --ctf-strings=<number|name>\n\
+                         Use section <number|name> as the CTF external strtab\n\n"));
+
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
   -i --instruction-dump=<number|name>\n\
@@ -4685,6 +4711,19 @@ parse_args (Filedata * filedata, int argc, char ** argv)
 	case OPTION_DWARF_CHECK:
 	  dwarf_check = TRUE;
 	  break;
+	case OPTION_CTF_DUMP:
+	  do_ctf = TRUE;
+	  request_dump (filedata, CTF_DUMP);
+	  break;
+	case OPTION_CTF_SYMBOLS:
+	  dump_ctf_symtab_name = strdup (optarg);
+	  break;
+	case OPTION_CTF_STRINGS:
+	  dump_ctf_strtab_name = strdup (optarg);
+	  break;
+	case OPTION_CTF_PARENT:
+	  dump_ctf_parent_name = strdup (optarg);
+	  break;
 	case OPTION_DYN_SYMS:
 	  do_dyn_syms = TRUE;
 	  break;
@@ -13706,6 +13745,163 @@ dump_section_as_bytes (Elf_Internal_Shdr *  section,
   return TRUE;
 }
 
+static ctf_sect_t *
+shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
+{
+  buf->cts_name = SECTION_NAME(shdr);
+  buf->cts_type = shdr->sh_type;
+  buf->cts_flags = shdr->sh_flags;
+  buf->cts_size = shdr->sh_size;
+  buf->cts_entsize = shdr->sh_entsize;
+  buf->cts_offset = (off64_t) shdr->sh_offset;
+
+  return buf;
+}
+
+/* Formatting callback function passed to ctf_dump.  Returns either the pointer
+   it is passed, or a pointer to newly-allocated storage, in which case
+   dump_ctf() will free it when it no longer needs it.  */
+
+static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
+				    char *s, void *arg)
+{
+  char *spaces = arg;
+  char *new_s;
+
+  if (asprintf (&new_s, "%s%s", spaces, s) < 0)
+    return s;
+  return new_s;
+}
+
+static bfd_boolean
+dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
+{
+  Elf_Internal_Shdr *  parent_sec = NULL;
+  Elf_Internal_Shdr *  symtab_sec = NULL;
+  Elf_Internal_Shdr *  strtab_sec = NULL;
+  void *      	       data = NULL;
+  void *      	       symdata = NULL;
+  void *      	       strdata = NULL;
+  void *      	       parentdata = NULL;
+  ctf_sect_t           ctfsect, symsect, strsect, parentsect;
+  ctf_sect_t *         symsectp = NULL;
+  ctf_sect_t *         strsectp = NULL;
+  ctf_file_t *         ctf = NULL;
+  ctf_file_t *         parent = NULL;
+
+  const char *things[] = {"Labels", "Data objects", "Function objects",
+			  "Variables", "Types", "Strings", ""};
+  const char **thing;
+  int err;
+  bfd_boolean ret = FALSE;
+  size_t i;
+
+  shdr_to_ctf_sect (&ctfsect, section, filedata);
+  data = get_section_contents (section, filedata);
+  ctfsect.cts_data = data;
+
+  if (dump_ctf_symtab_name)
+    {
+      if ((symtab_sec = find_section (filedata, dump_ctf_symtab_name)) == NULL)
+	{
+	  error (_("No symbol section named %s\n"), dump_ctf_symtab_name);
+	  goto fail;
+	}
+      if ((symdata = (void *) get_data (NULL, filedata,
+					symtab_sec->sh_offset, 1,
+					symtab_sec->sh_size,
+					_("symbols"))) == NULL)
+	goto fail;
+      symsectp = shdr_to_ctf_sect (&symsect, symtab_sec, filedata);
+      symsect.cts_data = symdata;
+    }
+  if (dump_ctf_strtab_name)
+    {
+      if ((strtab_sec = find_section (filedata, dump_ctf_strtab_name)) == NULL)
+	{
+	  error (_("No string table section named %s\n"),
+		 dump_ctf_strtab_name);
+	  goto fail;
+	}
+      if ((strdata = (void *) get_data (NULL, filedata,
+					strtab_sec->sh_offset, 1,
+					strtab_sec->sh_size,
+					_("strings"))) == NULL)
+	goto fail;
+      strsectp = shdr_to_ctf_sect (&strsect, strtab_sec, filedata);
+      strsect.cts_data = strdata;
+    }
+  if (dump_ctf_parent_name)
+    {
+      if ((parent_sec = find_section (filedata, dump_ctf_parent_name)) == NULL)
+	{
+	  error (_("No CTF parent section named %s\n"), dump_ctf_parent_name);
+	  goto fail;
+	}
+      if ((parentdata = (void *) get_data (NULL, filedata,
+					   parent_sec->sh_offset, 1,
+					   parent_sec->sh_size,
+					   _("CTF parent"))) == NULL)
+	goto fail;
+      shdr_to_ctf_sect (&parentsect, parent_sec, filedata);
+      parentsect.cts_data = parentdata;
+    }
+
+  /* Load the CTF file and dump it.  */
+
+  if ((ctf = ctf_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
+    {
+      error (_("CTF open failure: %s\n"), ctf_errmsg (err));
+      goto fail;
+    }
+
+  if (parentdata)
+    {
+      if ((parent = ctf_bufopen (&parentsect, symsectp, strsectp, &err)) == NULL)
+	{
+	  error (_("CTF open failure: %s\n"), ctf_errmsg (err));
+	  goto fail;
+	}
+
+      ctf_import (ctf, parent);
+    }
+
+  ret = TRUE;
+
+  printf (_("\nDump of CTF section '%s':\n"),
+	  printable_section_name (filedata, section));
+
+  for (i = 1, thing = things; *thing[0]; thing++, i++)
+    {
+      ctf_dump_state_t *s = NULL;
+      char *item;
+
+      printf ("\n  %s:\n", *thing);
+      while ((item = ctf_dump (ctf, &s, i, dump_ctf_indent_lines,
+			       (void *) "    ")) != NULL)
+	{
+	  printf ("%s\n", item);
+	  free (item);
+	}
+
+      if (ctf_errno (ctf))
+	{
+	  error (_("Iteration failed: %s, %s\n"), *thing,
+		   ctf_errmsg (ctf_errno (ctf)));
+	  ret = FALSE;
+	}
+    }
+
+ fail:
+  ctf_close (ctf);
+  ctf_close (parent);
+  free (parentdata);
+  free (data);
+  free (symdata);
+  free (strdata);
+  return ret;
+}
+
 static bfd_boolean
 load_specific_debug_section (enum dwarf_section_display_enum  debug,
 			     const Elf_Internal_Shdr *        sec,
@@ -14043,6 +14239,12 @@ process_section_contents (Filedata * filedata)
 	  if (! display_debug_section (i, section, filedata))
 	    res = FALSE;
 	}
+
+      if (dump & CTF_DUMP)
+	{
+	  if (! dump_section_as_ctf (section, filedata))
+	    res = FALSE;
+	}
     }
 
   /* Check to see if the user requested a
@@ -19777,5 +19979,9 @@ main (int argc, char ** argv)
   if (cmdline.dump_sects != NULL)
     free (cmdline.dump_sects);
 
+  free (dump_ctf_symtab_name);
+  free (dump_ctf_strtab_name);
+  free (dump_ctf_parent_name);
+
   return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 05/19] libctf: error handling
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
  2019-04-30 22:57 ` [PATCH 02/19] include: new header ctf-api.h Nick Alcock
  2019-04-30 22:57 ` [PATCH 15/19] libctf: mmappable archives Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-02 16:10   ` Nick Clifton
  2019-04-30 22:57 ` [PATCH 13/19] libctf: type copying Nick Alcock
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

CTF functions return zero on success or an extended errno value which
can be translated into a string via the functions in this commit.

The errno numbers start at -CTF_BASE.

libctf/
	* ctf-error.c: New file.

include/
	* ctf-api.h (ctf_errno): New declaration.
	(ctf_errmsg): Likewise.
---
 include/ctf-api.h  |  2 +
 libctf/ctf-error.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)
 create mode 100644 libctf/ctf-error.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index e2f5dc7571..646e848c84 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -122,6 +122,8 @@ enum
 #define	CTF_ADD_NONROOT	0	/* Type only visible in nested scope.  */
 #define	CTF_ADD_ROOT	1	/* Type visible at top-level scope.  */
 
+extern int ctf_errno (ctf_file_t *);
+extern const char *ctf_errmsg (int);
 
 #ifdef	__cplusplus
 }
diff --git a/libctf/ctf-error.c b/libctf/ctf-error.c
new file mode 100644
index 0000000000..ea3e113145
--- /dev/null
+++ b/libctf/ctf-error.c
@@ -0,0 +1,93 @@
+/* Error table.
+   Copyright (C) 2003-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+
+static const char *const _ctf_errlist[] = {
+  "File is not in CTF or ELF format",		     /* ECTF_FMT */
+  "File uses more recent ELF version than libctf",   /* ECTF_ELFVERS */
+  "File uses more recent CTF version than libctf",   /* ECTF_CTFVERS */
+  "File is a different endian-ness than libctf",     /* ECTF_ENDIAN */
+  "Symbol table uses invalid entry size",	     /* ECTF_SYMTAB */
+  "Symbol table data buffer is not valid",	     /* ECTF_SYMBAD */
+  "String table data buffer is not valid",	     /* ECTF_STRBAD */
+  "File data structure corruption detected",	     /* ECTF_CORRUPT */
+  "File does not contain CTF data",		     /* ECTF_NOCTFDATA */
+  "Buffer does not contain CTF data",		     /* ECTF_NOCTFBUF */
+  "Symbol table information is not available",	     /* ECTF_NOSYMTAB */
+  "Type information is in parent and unavailable",   /* ECTF_NOPARENT */
+  "Cannot import types with different data model",   /* ECTF_DMODEL */
+  "Failed to mmap a needed data section",	     /* ECTF_MMAP */
+  "Failed to allocate (de)compression buffer",	     /* ECTF_ZALLOC */
+  "Failed to decompress CTF data",		     /* ECTF_DECOMPRESS */
+  "External string table is not available",	     /* ECTF_STRTAB */
+  "String name offset is corrupt",		     /* ECTF_BADNAME */
+  "Invalid type identifier",			     /* ECTF_BADID */
+  "Type is not a struct or union",		     /* ECTF_NOTSOU */
+  "Type is not an enum",			     /* ECTF_NOTENUM */
+  "Type is not a struct, union, or enum",	     /* ECTF_NOTSUE */
+  "Type is not an integer, float, or enum",	     /* ECTF_NOTINTFP */
+  "Type is not an array",			     /* ECTF_NOTARRAY */
+  "Type does not reference another type",	     /* ECTF_NOTREF */
+  "Input buffer is too small for type name",	     /* ECTF_NAMELEN */
+  "No type information available for that name",     /* ECTF_NOTYPE */
+  "Syntax error in type name",			     /* ECTF_SYNTAX */
+  "Symbol table entry is not a function",	     /* ECTF_NOTFUNC */
+  "No function information available for symbol",    /* ECTF_NOFUNCDAT */
+  "Symbol table entry is not a data object",	     /* ECTF_NOTDATA */
+  "No type information available for symbol",	     /* ECTF_NOTYPEDAT */
+  "No label information available for that name",    /* ECTF_NOLABEL */
+  "File does not contain any labels",		     /* ECTF_NOLABELDATA */
+  "Feature not supported",			     /* ECTF_NOTSUP */
+  "Invalid enum element name",			     /* ECTF_NOENUMNAM */
+  "Invalid member name",			     /* ECTF_NOMEMBNAM */
+  "CTF container is read-only",			     /* ECTF_RDONLY */
+  "Limit on number of dynamic type members reached", /* ECTF_DTFULL */
+  "Limit on number of dynamic types reached",	     /* ECTF_FULL */
+  "Duplicate member or variable name",		     /* ECTF_DUPLICATE */
+  "Conflicting type is already defined",	     /* ECTF_CONFLICT */
+  "Attempt to roll back past a ctf_update",	     /* ECTF_OVERROLLBACK */
+  "Failed to compress CTF data",		     /* ECTF_COMPRESS */
+  "Failed to create CTF archive",		     /* ECTF_ARCREATE */
+  "Name not found in CTF archive",		     /* ECTF_ARNNAME */
+  "Overflow of type bitness or offset in slice",     /* ECTF_SLICEOVERFLOW */
+  "Unknown section number in dump",		     /* ECTF_DUMPSECTUNKNOWN */
+  "Section changed in middle of dump"		     /* ECTF_DUMPSECTCHANGED */
+};
+
+static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);
+
+const char *
+ctf_errmsg (int error)
+{
+  const char *str;
+
+  if (error >= ECTF_BASE && (error - ECTF_BASE) < _ctf_nerr)
+    str = _ctf_errlist[error - ECTF_BASE];
+  else
+    str = ctf_strerror (error);
+
+  return (str ? str : "Unknown error");
+}
+
+int
+ctf_errno (ctf_file_t * fp)
+{
+  return fp->ctf_errno;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 14/19] libctf: library version enforcement
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (12 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 04/19] libctf: low-level list manipulation and helper utilities Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 12/19] libctf: lookups by name and symbol Nick Alcock
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

This old Solaris standard allows callers to specify that they are
expecting one particular API and/or CTF file format from the library.

It is basically vestigial and I would be amenable to dropping it.

libctf/
	* ctf-lib.c (ctf_version): New.

include/
	* ctf-api.h (ctf_version): New.
---
 include/ctf-api.h |  1 +
 libctf/ctf-lib.c  | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 0adecfee7e..3fcb1d2d6c 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -233,6 +233,7 @@ extern void *ctf_getspecific (ctf_file_t *);
 
 extern int ctf_errno (ctf_file_t *);
 extern const char *ctf_errmsg (int);
+extern int ctf_version (int);
 
 extern int ctf_func_info (ctf_file_t *, unsigned long, ctf_funcinfo_t *);
 extern int ctf_func_args (ctf_file_t *, unsigned long, uint32_t, ctf_id_t *);
diff --git a/libctf/ctf-lib.c b/libctf/ctf-lib.c
index e60d2c985b..3a52539755 100644
--- a/libctf/ctf-lib.c
+++ b/libctf/ctf-lib.c
@@ -478,3 +478,29 @@ ctf_write (ctf_file_t *fp, int fd)
 
   return 0;
 }
+
+/* Set the CTF library client version to the specified version.  If version is
+   zero, we just return the default library version number.  */
+int
+ctf_version (int version)
+{
+  if (version < 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (version > 0)
+    {
+      /*  Dynamic version switching is not presently supported. */
+      if (version != CTF_VERSION)
+	{
+	  errno = ENOTSUP;
+	  return -1;
+	}
+      ctf_dprintf ("ctf_version: client using version %d\n", version);
+      _libctf_version = version;
+    }
+
+  return _libctf_version;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 13/19] libctf: type copying
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (2 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 05/19] libctf: error handling Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-04-30 22:57 ` [PATCH 01/19] include: new header ctf.h: file format description Nick Alcock
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

ctf_add_type() allows you to copy types, and all the types they depend
on, from one container to another (writable) container. This lets a
program maintaining multiple distinct containers (not in a parent-child
relationship) introduce types that depend on types in one container in
another writable one, by copying the necessary types.

libctf/
	* ctf-create.c (enumcmp): New.
	(enumadd): Likewise.
	(membcmp): Likewise.
	(membadd): Likewise.
	(ctf_add_type): Likewise.
---
 libctf/ctf-create.c | 485 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 485 insertions(+)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index cde4c52666..a5b8073587 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1450,3 +1450,488 @@ ctf_add_variable (ctf_file_t *fp, const char *name, ctf_id_t ref)
   fp->ctf_flags |= LCTF_DIRTY;
   return 0;
 }
+
+static int
+enumcmp (const char *name, int value, void *arg)
+{
+  ctf_bundle_t *ctb = arg;
+  int bvalue;
+
+  if (ctf_enum_value (ctb->ctb_file, ctb->ctb_type, name, &bvalue) == CTF_ERR)
+    {
+      ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
+      return 1;
+    }
+  if (value != bvalue)
+    {
+      ctf_dprintf ("Conflict due to value change: %i versus %i\n",
+		   value, bvalue);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+enumadd (const char *name, int value, void *arg)
+{
+  ctf_bundle_t *ctb = arg;
+
+  return (ctf_add_enumerator (ctb->ctb_file, ctb->ctb_type,
+			      name, value) == CTF_ERR);
+}
+
+static int
+membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset,
+	 void *arg)
+{
+  ctf_bundle_t *ctb = arg;
+  ctf_membinfo_t ctm;
+
+  if (ctf_member_info (ctb->ctb_file, ctb->ctb_type, name, &ctm) == CTF_ERR)
+    {
+      ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
+      return 1;
+    }
+  if (ctm.ctm_offset != offset)
+    {
+      ctf_dprintf ("Conflict due to member %s offset change: "
+		   "%lx versus %lx\n", name, ctm.ctm_offset, offset);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+membadd (const char *name, ctf_id_t type, unsigned long offset, void *arg)
+{
+  ctf_bundle_t *ctb = arg;
+  ctf_dmdef_t *dmd;
+  char *s = NULL;
+
+  if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
+    return (ctf_set_errno (ctb->ctb_file, EAGAIN));
+
+  if (name != NULL && (s = ctf_strdup (name)) == NULL)
+    {
+      ctf_free (dmd, sizeof (ctf_dmdef_t));
+      return (ctf_set_errno (ctb->ctb_file, EAGAIN));
+    }
+
+  /* For now, dmd_type is copied as the src_fp's type; it is reset to an
+    equivalent dst_fp type by a final loop in ctf_add_type(), below.  */
+  dmd->dmd_name = s;
+  dmd->dmd_type = type;
+  dmd->dmd_offset = offset;
+  dmd->dmd_value = -1;
+
+  ctf_list_append (&ctb->ctb_dtd->dtd_u.dtu_members, dmd);
+
+  if (s != NULL)
+    ctb->ctb_file->ctf_dtvstrlen += strlen (s) + 1;
+
+  ctb->ctb_file->ctf_flags |= LCTF_DIRTY;
+  return 0;
+}
+
+/* The ctf_add_type routine is used to copy a type from a source CTF container
+   to a dynamic destination container.  This routine operates recursively by
+   following the source type's links and embedded member types.  If the
+   destination container already contains a named type which has the same
+   attributes, then we succeed and return this type but no changes occur.  */
+ctf_id_t
+ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
+{
+  ctf_id_t dst_type = CTF_ERR;
+  uint32_t dst_kind = CTF_K_UNKNOWN;
+  ctf_id_t tmp;
+
+  const char *name;
+  uint32_t kind, flag, vlen;
+
+  const ctf_type_t *src_tp, *dst_tp;
+  ctf_bundle_t src, dst;
+  ctf_encoding_t src_en, dst_en;
+  ctf_arinfo_t src_ar, dst_ar;
+
+  ctf_dtdef_t *dtd;
+  ctf_funcinfo_t ctc;
+  ssize_t size;
+
+  ctf_hash_t *hp;
+
+  if (!(dst_fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (dst_fp, ECTF_RDONLY));
+
+  if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
+    return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+
+  name = ctf_strptr (src_fp, src_tp->ctt_name);
+  kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
+  flag = LCTF_INFO_ISROOT (src_fp, src_tp->ctt_info);
+  vlen = LCTF_INFO_VLEN (src_fp, src_tp->ctt_info);
+
+  switch (kind)
+    {
+    case CTF_K_STRUCT:
+      hp = dst_fp->ctf_structs;
+      break;
+    case CTF_K_UNION:
+      hp = dst_fp->ctf_unions;
+      break;
+    case CTF_K_ENUM:
+      hp = dst_fp->ctf_enums;
+      break;
+    default:
+      hp = dst_fp->ctf_names;
+      break;
+    }
+
+  /* If the source type has a name and is a root type (visible at the
+     top-level scope), lookup the name in the destination container and
+     verify that it is of the same kind before we do anything else.  */
+
+  if ((flag & CTF_ADD_ROOT) && name[0] != '\0'
+      && (tmp = ctf_hash_lookup_type (hp, dst_fp, name)) != 0)
+    {
+      dst_type = tmp;
+      dst_kind = ctf_type_kind_unsliced (dst_fp, dst_type);
+    }
+
+  /* If an identically named dst_type exists, fail with ECTF_CONFLICT
+     unless dst_type is a forward declaration and src_type is a struct,
+     union, or enum (i.e. the definition of the previous forward decl).  */
+
+  if (dst_type != CTF_ERR && dst_kind != kind
+      && (dst_kind != CTF_K_FORWARD
+	  || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
+	      && kind != CTF_K_UNION)))
+    {
+      ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
+		   "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
+      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+    }
+
+  /* We take special action for an integer, float, or slice since it is
+     described not only by its name but also its encoding.  For integers,
+     bit-fields exploit this degeneracy.  */
+
+  if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
+    {
+      if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
+	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+
+      if (dst_type != CTF_ERR)
+	{
+	  ctf_file_t *fp = dst_fp;
+
+	  if ((dst_tp = ctf_lookup_by_id (&fp, dst_type)) == NULL)
+	    return CTF_ERR;
+
+	  if (LCTF_INFO_ISROOT (fp, dst_tp->ctt_info) & CTF_ADD_ROOT)
+	    {
+	      /* The type that we found in the hash is also root-visible.  If
+		 the two types match then use the existing one; otherwise,
+		 declare a conflict.  Note: slices are not certain to match
+		 even if there is no conflict: we must check the contained type
+		 too.  */
+
+	      if (ctf_type_encoding (dst_fp, dst_type, &dst_en) != 0)
+		return CTF_ERR;			/* errno set for us.  */
+
+	      if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
+		{
+		  if (kind != CTF_K_SLICE)
+		    return dst_type;
+		}
+	      else
+		  {
+		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		  }
+	    }
+	  else
+	    {
+	      /* We found a non-root-visible type in the hash.  We reset
+	         dst_type to ensure that we continue to look for a possible
+	         conflict in the pending list.  */
+
+	      dst_type = CTF_ERR;
+	    }
+	}
+    }
+
+  /* If the non-empty name was not found in the appropriate hash, search
+     the list of pending dynamic definitions that are not yet committed.
+     If a matching name and kind are found, assume this is the type that
+     we are looking for.  This is necessary to permit ctf_add_type() to
+     operate recursively on entities such as a struct that contains a
+     pointer member that refers to the same struct type.  */
+
+  if (dst_type == CTF_ERR && name[0] != '\0')
+    {
+      for (dtd = ctf_list_prev (&dst_fp->ctf_dtdefs); dtd != NULL
+	     && LCTF_TYPE_TO_INDEX (src_fp, dtd->dtd_type) > dst_fp->ctf_dtoldid;
+	   dtd = ctf_list_prev (dtd))
+	{
+	  if (LCTF_INFO_KIND (src_fp, dtd->dtd_data.ctt_info) == kind
+	      && dtd->dtd_name != NULL && strcmp (dtd->dtd_name, name) == 0)
+	    {
+	      int sroot;	/* Is the src root-visible?  */
+	      int droot;	/* Is the dst root-visible?  */
+	      int match;	/* Do the encodings match?  */
+
+	      if (kind != CTF_K_INTEGER && kind != CTF_K_FLOAT && kind != CTF_K_SLICE)
+		return dtd->dtd_type;
+
+	      sroot = (flag & CTF_ADD_ROOT);
+	      droot = (LCTF_INFO_ISROOT (dst_fp,
+					 dtd->dtd_data.
+					 ctt_info) & CTF_ADD_ROOT);
+
+	      match = (memcmp (&src_en, &dtd->dtd_u.dtu_enc,
+			       sizeof (ctf_encoding_t)) == 0);
+
+	      /* If the types share the same encoding then return the id of the
+		 first unless one type is root-visible and the other is not; in
+		 that case the new type must get a new id if a match is never
+		 found.  Note: slices are not certain to match even if there is
+		 no conflict: we must check the contained type too. */
+
+	      if (match && sroot == droot)
+		{
+		  if (kind != CTF_K_SLICE)
+		    return dtd->dtd_type;
+		}
+	      else if (!match && sroot && droot)
+		{
+		  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+		}
+	    }
+	}
+    }
+
+  src.ctb_file = src_fp;
+  src.ctb_type = src_type;
+  src.ctb_dtd = NULL;
+
+  dst.ctb_file = dst_fp;
+  dst.ctb_type = dst_type;
+  dst.ctb_dtd = NULL;
+
+  /* Now perform kind-specific processing.  If dst_type is CTF_ERR, then
+     we add a new type with the same properties as src_type to dst_fp.
+     If dst_type is not CTF_ERR, then we verify that dst_type has the
+     same attributes as src_type.  We recurse for embedded references.  */
+  switch (kind)
+    {
+    case CTF_K_INTEGER:
+      /*  If we found a match we will have either returned it or declared a
+	  conflict.  */
+      dst_type = ctf_add_integer (dst_fp, flag, name, &src_en);
+      break;
+
+    case CTF_K_FLOAT:
+      /* If we found a match we will have either returned it or declared a
+       conflict.  */
+      dst_type = ctf_add_float (dst_fp, flag, name, &src_en);
+      break;
+
+    case CTF_K_SLICE:
+      /* We have checked for conflicting encodings: now try to add the
+	 contained type.  */
+      src_type = ctf_type_reference (src_fp, src_type);
+      dst_type = ctf_add_type (dst_fp, src_fp, src_type);
+
+      if (src_type == CTF_ERR)
+	return CTF_ERR;				/* errno is set for us.  */
+
+      dst_type = ctf_add_slice (dst_fp, flag, src_type, &src_en);
+      break;
+
+    case CTF_K_POINTER:
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+      src_type = ctf_type_reference (src_fp, src_type);
+      src_type = ctf_add_type (dst_fp, src_fp, src_type);
+
+      if (src_type == CTF_ERR)
+	return CTF_ERR;				/* errno is set for us.  */
+
+      dst_type = ctf_add_reftype (dst_fp, flag, src_type, kind);
+      break;
+
+    case CTF_K_ARRAY:
+      if (ctf_array_info (src_fp, src_type, &src_ar) == CTF_ERR)
+	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
+
+      src_ar.ctr_contents =
+	ctf_add_type (dst_fp, src_fp, src_ar.ctr_contents);
+      src_ar.ctr_index = ctf_add_type (dst_fp, src_fp, src_ar.ctr_index);
+      src_ar.ctr_nelems = src_ar.ctr_nelems;
+
+      if (src_ar.ctr_contents == CTF_ERR || src_ar.ctr_index == CTF_ERR)
+	return CTF_ERR;				/* errno is set for us.  */
+
+      if (dst_type != CTF_ERR)
+	{
+	  if (ctf_array_info (dst_fp, dst_type, &dst_ar) != 0)
+	    return CTF_ERR;			/* errno is set for us.  */
+
+	  if (memcmp (&src_ar, &dst_ar, sizeof (ctf_arinfo_t)))
+	    {
+	      ctf_dprintf ("Conflict for type %s against ID %lx: "
+			   "array info differs, old %lx/%lx/%x; "
+			   "new: %lx/%lx/%x\n", name, dst_type,
+			   src_ar.ctr_contents, src_ar.ctr_index,
+			   src_ar.ctr_nelems, dst_ar.ctr_contents,
+			   dst_ar.ctr_index, dst_ar.ctr_nelems);
+	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	    }
+	}
+      else
+	dst_type = ctf_add_array (dst_fp, flag, &src_ar);
+      break;
+
+    case CTF_K_FUNCTION:
+      ctc.ctc_return = ctf_add_type (dst_fp, src_fp, src_tp->ctt_type);
+      ctc.ctc_argc = 0;
+      ctc.ctc_flags = 0;
+
+      if (ctc.ctc_return == CTF_ERR)
+	return CTF_ERR;				/* errno is set for us.  */
+
+      dst_type = ctf_add_function (dst_fp, flag, &ctc, NULL);
+      break;
+
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      {
+	ctf_dmdef_t *dmd;
+	int errs = 0;
+
+	/* Technically to match a struct or union we need to check both
+	   ways (src members vs. dst, dst members vs. src) but we make
+	   this more optimal by only checking src vs. dst and comparing
+	   the total size of the structure (which we must do anyway)
+	   which covers the possibility of dst members not in src.
+	   This optimization can be defeated for unions, but is so
+	   pathological as to render it irrelevant for our purposes.  */
+
+	if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD)
+	  {
+	    if (ctf_type_size (src_fp, src_type) !=
+		ctf_type_size (dst_fp, dst_type))
+	      {
+		ctf_dprintf ("Conflict for type %s against ID %lx: "
+			     "union size differs, old %li, new %li\n",
+			     name, dst_type, ctf_type_size (src_fp, src_type),
+			     ctf_type_size (dst_fp, dst_type));
+		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      }
+
+	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
+	      {
+		ctf_dprintf ("Conflict for type %s against ID %lx: "
+			     "members differ, see above\n", name, dst_type);
+		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	      }
+
+	    break;
+	  }
+
+	/* Unlike the other cases, copying structs and unions is done
+	   manually so as to avoid repeated lookups in ctf_add_member
+	   and to ensure the exact same member offsets as in src_type.  */
+
+	dst_type = ctf_add_generic (dst_fp, flag, name, &dtd);
+	if (dst_type == CTF_ERR)
+	  return CTF_ERR;			/* errno is set for us.  */
+
+	dst.ctb_type = dst_type;
+	dst.ctb_dtd = dtd;
+
+	if (ctf_member_iter (src_fp, src_type, membadd, &dst) != 0)
+	  errs++;	       /* Increment errs and fail at bottom of case.  */
+
+	if ((size = ctf_type_size (src_fp, src_type)) > CTF_MAX_SIZE)
+	  {
+	    dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+	    dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+	    dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+	  }
+	else
+	  dtd->dtd_data.ctt_size = (uint32_t) size;
+
+	dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, vlen);
+
+	/* Make a final pass through the members changing each dmd_type (a
+	   src_fp type) to an equivalent type in dst_fp.  We pass through all
+	   members, leaving any that fail set to CTF_ERR.  */
+	for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+	     dmd != NULL; dmd = ctf_list_next (dmd))
+	  {
+	    if ((dmd->dmd_type = ctf_add_type (dst_fp, src_fp,
+					       dmd->dmd_type)) == CTF_ERR)
+	      errs++;
+	  }
+
+	if (errs)
+	  return CTF_ERR;			/* errno is set for us.  */
+	break;
+      }
+
+    case CTF_K_ENUM:
+      if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD)
+	{
+	  if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
+	      || ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
+	    {
+	      ctf_dprintf ("Conflict for enum %s against ID %lx: "
+			   "members differ, see above\n", name, dst_type);
+	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+	    }
+	}
+      else
+	{
+	  dst_type = ctf_add_enum (dst_fp, flag, name);
+	  if ((dst.ctb_type = dst_type) == CTF_ERR
+	      || ctf_enum_iter (src_fp, src_type, enumadd, &dst))
+	    return CTF_ERR;			/* errno is set for us */
+	}
+      break;
+
+    case CTF_K_FORWARD:
+      if (dst_type == CTF_ERR)
+	{
+	  dst_type = ctf_add_forward (dst_fp, flag,
+				      name, CTF_K_STRUCT); /* Assume STRUCT. */
+	}
+      break;
+
+    case CTF_K_TYPEDEF:
+      src_type = ctf_type_reference (src_fp, src_type);
+      src_type = ctf_add_type (dst_fp, src_fp, src_type);
+
+      if (src_type == CTF_ERR)
+	return CTF_ERR;				/* errno is set for us.  */
+
+      /* If dst_type is not CTF_ERR at this point, we should check if
+	 ctf_type_reference(dst_fp, dst_type) != src_type and if so fail with
+	 ECTF_CONFLICT.  However, this causes problems with bitness typedefs
+	 that vary based on things like if 32-bit then pid_t is int otherwise
+	 long.  We therefore omit this check and assume that if the identically
+	 named typedef already exists in dst_fp, it is correct or
+	 equivalent.  */
+
+      if (dst_type == CTF_ERR)
+	{
+	  dst_type = ctf_add_typedef (dst_fp, flag, name, src_type);
+	}
+      break;
+
+    default:
+      return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
+    }
+
+  return dst_type;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 01/19] include: new header ctf.h: file format description
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (3 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 13/19] libctf: type copying Nick Alcock
@ 2019-04-30 22:57 ` Nick Alcock
  2019-05-01 16:57   ` Nick Clifton
  2019-04-30 22:57 ` [PATCH 09/19] libctf: opening Nick Alcock
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:57 UTC (permalink / raw)
  To: binutils

The data structures and macros in this header can be used, if desired,
to access or create CTF files directly, without going through libctf,
though this should rarely be necessary in practice.

libctf relies on this header as its description of the CTF file format.

include/
	* ctf.h: New file.
---
 include/ctf.h | 427 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 427 insertions(+)
 create mode 100644 include/ctf.h

diff --git a/include/ctf.h b/include/ctf.h
new file mode 100644
index 0000000000..92dafd5972
--- /dev/null
+++ b/include/ctf.h
@@ -0,0 +1,427 @@
+/* CTF format description.
+   Copyright (C) 2004-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_CTF_H
+#define	_CTF_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* CTF - Compact ANSI-C Type Format
+
+   This file format can be used to compactly represent the information needed
+   by a debugger to interpret the ANSI-C types used by a given program.
+   Traditionally, this kind of information is generated by the compiler when
+   invoked with the -g flag and is stored in "stabs" strings or in the more
+   modern DWARF format.  CTF provides a representation of only the information
+   that is relevant to debugging a complex, optimized C program such as the
+   operating system kernel in a form that is significantly more compact than
+   the equivalent stabs or DWARF representation.  The format is data-model
+   independent, so consumers do not need different code depending on whether
+   they are 32-bit or 64-bit programs; libctf automatically compensates for
+   endianness variations.  CTF assumes that a standard ELF symbol table is
+   available for use in the debugger, and uses the structure and data of the
+   symbol table to avoid storing redundant information.  The CTF data may be
+   compressed on disk or in memory, indicated by a bit in the header.  CTF may
+   be interpreted in a raw disk file, or it may be stored in an ELF section,
+   typically named .ctf.  Data structures are aligned so that a raw CTF file or
+   CTF ELF section may be manipulated using mmap(2).
+
+   The CTF file or section itself has the following structure:
+
+   +--------+--------+---------+----------+----------+-------+--------+
+   |  file  |  type  |  data   | function | variable | data  | string |
+   | header | labels | objects |   info   |   info   | types | table  |
+   +--------+--------+---------+----------+----------+-------+--------+
+
+   The file header stores a magic number and version information, encoding
+   flags, and the byte offset of each of the sections relative to the end of the
+   header itself.  If the CTF data has been uniquified against another set of
+   CTF data, a reference to that data also appears in the the header.  This
+   reference is the name of the label corresponding to the types uniquified
+   against.
+
+   Following the header is a list of labels, used to group the types included in
+   the data types section.  Each label is accompanied by a type ID i.  A given
+   label refers to the group of types whose IDs are in the range [0, i].
+
+   Data object and function records are stored in the same order as they appear
+   in the corresponding symbol table, except that symbols marked SHN_UNDEF are
+   not stored and symbols that have no type data are padded out with zeroes.
+   For each data object, the type ID (a small integer) is recorded.  For each
+   function, the type ID of the return type and argument types is recorded.
+
+   Variable records (as distinct from data objects) provide a modicum of support
+   for non-ELF systems, mapping a variable name to a CTF type ID.  The variable
+   names are sorted into ASCIIbetical order, permitting binary searching.
+
+   The data types section is a list of variable size records that represent each
+   type, in order by their ID.  The types themselves form a directed graph,
+   where each node may contain one or more outgoing edges to other type nodes,
+   denoted by their ID.
+
+   Strings are recorded as a string table ID (0 or 1) and a byte offset into the
+   string table.  String table 0 is the internal CTF string table.  String table
+   1 is the external string table, which is the string table associated with the
+   ELF symbol table for this object.  CTF does not record any strings that are
+   already in the symbol table, and the CTF string table does not contain any
+   duplicated strings.
+
+   If the CTF data has been merged with another parent CTF object, some outgoing
+   edges may refer to type nodes that exist in another CTF object.  The debugger
+   and libctf library are responsible for connecting the appropriate objects
+   together so that the full set of types can be explored and manipulated.
+
+   This connection is done purely using the ctf_import() function.  There is no
+   notation anywhere in the child CTF file indicating which parent it is
+   connected to: it is the debugger's responsibility to track this.  */
+
+#define CTF_MAX_TYPE	0xfffffffe	/* Max type identifier value.  */
+#define CTF_MAX_PTYPE	0x7fffffff	/* Max parent type identifier value.  */
+#define CTF_MAX_NAME 0x7fffffff		/* Max offset into a string table.  */
+#define CTF_MAX_VLEN	0xffffff /* Max struct, union, enum members or args.  */
+
+/* See ctf_type_t */
+#define CTF_MAX_SIZE	0xfffffffe	/* Max size of a v2 type in bytes. */
+#define CTF_LSIZE_SENT	0xffffffff	/* Sentinel for v2 ctt_size.  */
+
+
+  /* Start of actual data structure definitions.
+
+     Every field in these structures must have corresponding code in the
+     endianness-swapping machinery in libctf/ctf-open.c.  */
+
+typedef struct ctf_preamble
+{
+  unsigned short ctp_magic;	/* Magic number (CTF_MAGIC).  */
+  unsigned char ctp_version;	/* Data format version number (CTF_VERSION).  */
+  unsigned char ctp_flags;	/* Flags (see below).  */
+} ctf_preamble_t;
+
+typedef struct ctf_header
+{
+  ctf_preamble_t cth_preamble;
+  uint32_t cth_parlabel;	/* Ref to name of parent lbl uniq'd against.  */
+  uint32_t cth_parname;		/* Ref to basename of parent.  */
+  uint32_t cth_lbloff;		/* Offset of label section.  */
+  uint32_t cth_objtoff;		/* Offset of object section.  */
+  uint32_t cth_funcoff;		/* Offset of function section.  */
+  uint32_t cth_varoff;		/* Offset of variable section.  */
+  uint32_t cth_typeoff;		/* Offset of type section.  */
+  uint32_t cth_stroff;		/* Offset of string section.  */
+  uint32_t cth_strlen;		/* Length of string section in bytes.  */
+} ctf_header_t;
+
+#define cth_magic   cth_preamble.ctp_magic
+#define cth_version cth_preamble.ctp_version
+#define cth_flags   cth_preamble.ctp_flags
+
+#define CTF_MAGIC	0xdff2	/* Magic number identifying header.  */
+
+/* Data format version number.  */
+
+
+#define CTF_VERSION_3 4
+#define CTF_VERSION CTF_VERSION_3 /* Current version.  */
+
+#define CTF_F_COMPRESS	0x1	/* Data buffer is compressed by libctf.  */
+
+typedef struct ctf_lblent
+{
+  uint32_t ctl_label;		/* Ref to name of label.  */
+  uint32_t ctl_type;		/* Last type associated with this label.  */
+} ctf_lblent_t;
+
+typedef struct ctf_varent
+{
+  uint32_t ctv_name;		/* Reference to name in string table.  */
+  uint32_t ctv_type;		/* Index of type of this variable.  */
+} ctf_varent_t;
+
+/* In format v2, type sizes, measured in bytes, come in two flavours.  Nearly
+   all of them fit into a (UINT_MAX - 1), and thus can be stored in the ctt_size
+   member of a ctf_stype_t.  The maximum value for these sizes is CTF_MAX_SIZE.
+   Types larger than this must be stored in the ctf_lsize member of a
+   ctf_type_t.  Use of this member is indicated by the presence of
+   CTF_LSIZE_SENT in ctt_size.  */
+
+typedef struct ctf_stype
+{
+  uint32_t ctt_name;		/* Reference to name in string table.  */
+  uint32_t ctt_info;		/* Encoded kind, variant length (see below).  */
+#ifndef __GNUC__
+  union
+  {
+    uint32_t _size;		/* Size of entire type in bytes.  */
+    uint32_t _type;		/* Reference to another type.  */
+  } _u;
+#else
+  __extension__
+  union
+  {
+    uint32_t ctt_size;		/* Size of entire type in bytes.  */
+    uint32_t ctt_type;		/* Reference to another type.  */
+  };
+#endif
+} ctf_stype_t;
+
+typedef struct ctf_type
+{
+  uint32_t ctt_name;		/* Reference to name in string table.  */
+  uint32_t ctt_info;		/* Encoded kind, variant length (see below).  */
+#ifndef __GNUC__
+union
+  {
+    uint32_t _size;		/* Always CTF_LSIZE_SENT.  */
+    uint32_t _type;		/* Do not use.  */
+  } _u;
+#else
+  __extension__
+  union
+  {
+    uint32_t ctt_size;		/* Always CTF_LSIZE_SENT.  */
+    uint32_t ctt_type;		/* Do not use.  */
+  };
+#endif
+  uint32_t ctt_lsizehi;		/* High 32 bits of type size in bytes.  */
+  uint32_t ctt_lsizelo;		/* Low 32 bits of type size in bytes.  */
+} ctf_type_t;
+
+#ifndef __GNUC__
+#define ctt_size _u._size	/* For fundamental types that have a size.  */
+#define ctt_type _u._type	/* For types that reference another type.  */
+#endif
+
+/* The following macros and inline functions compose and decompose values for
+   ctt_info and ctt_name, as well as other structures that contain name
+   references.  Use outside libdtrace-ctf itself is explicitly for access to CTF
+   files directly: types returned from the library will always appear to be
+   CTF_V2.
+
+   v1: (transparently upgraded to v2 at open time: may be compiled out of the
+   library)
+               ------------------------
+   ctt_info:   | kind | isroot | vlen |
+               ------------------------
+               15   11    10    9     0
+
+   v2:
+               ------------------------
+   ctt_info:   | kind | isroot | vlen |
+               ------------------------
+               31    26    25  24     0
+
+   CTF_V1 and V2 _INFO_VLEN have the same interface:
+
+   kind = CTF_*_INFO_KIND(c.ctt_info);     <-- CTF_K_* value (see below)
+   vlen = CTF_*_INFO_VLEN(fp, c.ctt_info); <-- length of variable data list
+
+   stid = CTF_NAME_STID(c.ctt_name);     <-- string table id number (0 or 1)
+   offset = CTF_NAME_OFFSET(c.ctt_name); <-- string table byte offset
+
+   c.ctt_info = CTF_TYPE_INFO(kind, vlen);
+   c.ctt_name = CTF_TYPE_NAME(stid, offset);  */
+
+
+#define CTF_V2_INFO_KIND(info)		(((info) & 0xfc000000) >> 26)
+#define CTF_V2_INFO_ISROOT(info)	(((info) & 0x2000000) >> 25)
+#define CTF_V2_INFO_VLEN(info)		(((info) & CTF_MAX_VLEN))
+
+#define CTF_NAME_STID(name)		((name) >> 31)
+#define CTF_NAME_OFFSET(name)		((name) & CTF_MAX_NAME)
+
+/* V2 only. */
+#define CTF_TYPE_INFO(kind, isroot, vlen) \
+	(((kind) << 26) | (((isroot) ? 1 : 0) << 25) | ((vlen) & CTF_MAX_VLEN))
+
+#define CTF_TYPE_NAME(stid, offset) \
+	(((stid) << 31) | ((offset) & CTF_MAX_NAME))
+
+/* The next set of macros are for public consumption only.  Not used internally,
+   since the relevant type boundary is dependent upon the version of the file at
+   *opening* time, not the version after transparent upgrade.  Use
+   ctf_type_isparent() / ctf_type_ischild() for that.  */
+
+#define CTF_V2_TYPE_ISPARENT(fp, id)	((id) <= CTF_MAX_PTYPE)
+#define CTF_V2_TYPE_ISCHILD(fp, id)	((id) > CTF_MAX_PTYPE)
+#define CTF_V2_TYPE_TO_INDEX(id)	((id) & CTF_MAX_PTYPE)
+#define CTF_V2_INDEX_TO_TYPE(id, child) ((child) ? ((id) | (CTF_MAX_PTYPE+1)) : (id))
+
+
+/* Valid for both V1 and V2. */
+#define CTF_TYPE_LSIZE(cttp) \
+	(((uint64_t)(cttp)->ctt_lsizehi) << 32 | (cttp)->ctt_lsizelo)
+#define CTF_SIZE_TO_LSIZE_HI(size)	((uint32_t)((uint64_t)(size) >> 32))
+#define CTF_SIZE_TO_LSIZE_LO(size)	((uint32_t)(size))
+
+#define CTF_STRTAB_0	0	/* String table id 0 (in-CTF).  */
+#define CTF_STRTAB_1	1	/* String table id 1 (ELF strtab).  */
+
+/* Values for CTF_TYPE_KIND().  If the kind has an associated data list,
+   CTF_INFO_VLEN() will extract the number of elements in the list, and
+   the type of each element is shown in the comments below. */
+
+#define CTF_K_UNKNOWN	0	/* Unknown type (used for padding).  */
+#define CTF_K_INTEGER	1	/* Variant data is CTF_INT_DATA (see below).  */
+#define CTF_K_FLOAT	2	/* Variant data is CTF_FP_DATA (see below).  */
+#define CTF_K_POINTER	3	/* ctt_type is referenced type.  */
+#define CTF_K_ARRAY	4	/* Variant data is single ctf_array_t.  */
+#define CTF_K_FUNCTION	5	/* ctt_type is return type, variant data is
+				   list of argument types (unsigned short's for v1,
+				   uint32_t's for v2).  */
+#define CTF_K_STRUCT	6	/* Variant data is list of ctf_member_t's.  */
+#define CTF_K_UNION	7	/* Variant data is list of ctf_member_t's.  */
+#define CTF_K_ENUM	8	/* Variant data is list of ctf_enum_t's.  */
+#define CTF_K_FORWARD	9	/* No additional data; ctt_name is tag.  */
+#define CTF_K_TYPEDEF	10	/* ctt_type is referenced type.  */
+#define CTF_K_VOLATILE	11	/* ctt_type is base type.  */
+#define CTF_K_CONST	12	/* ctt_type is base type.  */
+#define CTF_K_RESTRICT	13	/* ctt_type is base type.  */
+#define CTF_K_SLICE	14	/* Variant data is a ctf_slice_t.  */
+
+#define CTF_K_MAX	63	/* Maximum possible (V2) CTF_K_* value.  */
+
+/* Values for ctt_type when kind is CTF_K_INTEGER.  The flags, offset in bits,
+   and size in bits are encoded as a single word using the following macros.
+   (However, you can also encode the offset and bitness in a slice.)  */
+
+#define CTF_INT_ENCODING(data) (((data) & 0xff000000) >> 24)
+#define CTF_INT_OFFSET(data)   (((data) & 0x00ff0000) >> 16)
+#define CTF_INT_BITS(data)     (((data) & 0x0000ffff))
+
+#define CTF_INT_DATA(encoding, offset, bits) \
+       (((encoding) << 24) | ((offset) << 16) | (bits))
+
+#define CTF_INT_SIGNED	0x01	/* Integer is signed (otherwise unsigned).  */
+#define CTF_INT_CHAR	0x02	/* Character display format.  */
+#define CTF_INT_BOOL	0x04	/* Boolean display format.  */
+#define CTF_INT_VARARGS	0x08	/* Varargs display format.  */
+
+/* Use CTF_CHAR to produce a char that agrees with the system's native
+   char signedness.  */
+#if CHAR_MIN == 0
+# define CTF_CHAR (CTF_INT_CHAR)
+#else
+# define CTF_CHAR (CTF_INT_CHAR | CTF_INT_SIGNED)
+#endif
+
+/* Values for ctt_type when kind is CTF_K_FLOAT.  The encoding, offset in bits,
+   and size in bits are encoded as a single word using the following macros.
+   (However, you can also encode the offset and bitness in a slice.)  */
+
+#define CTF_FP_ENCODING(data)  (((data) & 0xff000000) >> 24)
+#define CTF_FP_OFFSET(data)    (((data) & 0x00ff0000) >> 16)
+#define CTF_FP_BITS(data)      (((data) & 0x0000ffff))
+
+#define CTF_FP_DATA(encoding, offset, bits) \
+       (((encoding) << 24) | ((offset) << 16) | (bits))
+
+/* Variant data when kind is CTF_K_FLOAT is an encoding in the top eight bits.  */
+#define CTF_FP_ENCODING(data)	(((data) & 0xff000000) >> 24)
+
+#define CTF_FP_SINGLE	1	/* IEEE 32-bit float encoding.  */
+#define CTF_FP_DOUBLE	2	/* IEEE 64-bit float encoding.  */
+#define CTF_FP_CPLX	3	/* Complex encoding.  */
+#define CTF_FP_DCPLX	4	/* Double complex encoding.  */
+#define CTF_FP_LDCPLX	5	/* Long double complex encoding.  */
+#define CTF_FP_LDOUBLE	6	/* Long double encoding.  */
+#define CTF_FP_INTRVL	7	/* Interval (2x32-bit) encoding.  */
+#define CTF_FP_DINTRVL	8	/* Double interval (2x64-bit) encoding.  */
+#define CTF_FP_LDINTRVL	9	/* Long double interval (2x128-bit) encoding.  */
+#define CTF_FP_IMAGRY	10	/* Imaginary (32-bit) encoding.  */
+#define CTF_FP_DIMAGRY	11	/* Long imaginary (64-bit) encoding.  */
+#define CTF_FP_LDIMAGRY	12	/* Long double imaginary (128-bit) encoding.  */
+
+#define CTF_FP_MAX	12	/* Maximum possible CTF_FP_* value */
+
+/* A slice increases the offset and reduces the bitness of the referenced
+   ctt_type, which must be a type which has an encoding (fp, int, or enum).  We
+   also store the referenced type in here, because it is easier to keep the
+   ctt_size correct for the slice than to shuffle the size into here and keep
+   the ctt_type where it is for other types.  */
+
+typedef struct ctf_slice
+{
+  uint32_t cts_type;
+  unsigned char cts_offset;
+  unsigned char cts_bits;
+} ctf_slice_t;
+
+typedef struct ctf_array_v1
+{
+  unsigned short cta_contents;	/* Reference to type of array contents.  */
+  unsigned short cta_index;	/* Reference to type of array index.  */
+  uint32_t cta_nelems;		/* Number of elements.  */
+} ctf_array_v1_t;
+
+typedef struct ctf_array
+{
+  uint32_t cta_contents;	/* Reference to type of array contents.  */
+  uint32_t cta_index;		/* Reference to type of array index.  */
+  uint32_t cta_nelems;		/* Number of elements.  */
+} ctf_array_t;
+
+/* Most structure members have bit offsets that can be expressed using a short.
+   Some don't.  ctf_member_t is used for structs which cannot contain any of
+   these large offsets, whereas ctf_lmember_t is used in the latter case.  If
+   any member of a given struct has an offset that cannot be expressed using a
+   uint32_t, all members will be stored as type ctf_lmember_t.  This is expected
+   to be very rare (but nonetheless possible).  */
+
+#define CTF_LSTRUCT_THRESH	536870912
+
+
+typedef struct ctf_member_v2
+{
+  uint32_t ctm_name;		/* Reference to name in string table.  */
+  uint32_t ctm_offset;		/* Offset of this member in bits.  */
+  uint32_t ctm_type;		/* Reference to type of member.  */
+} ctf_member_t;
+
+typedef struct ctf_lmember_v2
+{
+  uint32_t ctlm_name;		/* Reference to name in string table.  */
+  uint32_t ctlm_offsethi;	/* High 32 bits of member offset in bits.  */
+  uint32_t ctlm_type;		/* Reference to type of member.  */
+  uint32_t ctlm_offsetlo;	/* Low 32 bits of member offset in bits.  */
+} ctf_lmember_t;
+
+#define	CTF_LMEM_OFFSET(ctlmp) \
+	(((uint64_t)(ctlmp)->ctlm_offsethi) << 32 | (ctlmp)->ctlm_offsetlo)
+#define	CTF_OFFSET_TO_LMEMHI(offset)	((uint32_t)((uint64_t)(offset) >> 32))
+#define	CTF_OFFSET_TO_LMEMLO(offset)	((uint32_t)(offset))
+
+typedef struct ctf_enum
+{
+  uint32_t cte_name;		/* Reference to name in string table.  */
+  int cte_value;		/* Value associated with this name.  */
+} ctf_enum_t;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _CTF_H */
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 18/19] libctf: build system
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (15 preceding siblings ...)
  2019-04-30 22:57 ` [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers Nick Alcock
@ 2019-04-30 22:58 ` Nick Alcock
  2019-05-01  0:13 ` [PATCH 17/19] libctf: debug dumping Nick Alcock
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-04-30 22:58 UTC (permalink / raw)
  To: binutils

This ties libctf into the build system, and makes binutils depend on it
(used by the next commits).

	* Makefile.def (host_modules): Add libctf.
	* Makefile.def (dependencies): Likewise.
	libctf depends on zlib and libiberty.
	* Makefile.in: Regenerated.
	* configure.ac (host_libs): Add libctf.
	* configure: Regenerated.

libctf/
	* Makefile.am: New.
	* Makefile.in: Regenerated.
	* config.h.in: Likewise.
	* aclocal.m4: Likewise.
	* configure: Likewise.
---
 Makefile.def        |    5 +
 Makefile.in         |  984 +++++-
 configure           |    2 +-
 configure.ac        |    2 +-
 libctf/Makefile.am  |   31 +
 libctf/Makefile.in  |  767 +++++
 libctf/aclocal.m4   | 1233 ++++++++
 libctf/config.h.in  |   98 +
 libctf/configure    | 7120 +++++++++++++++++++++++++++++++++++++++++++
 libctf/configure.ac |   59 +
 10 files changed, 10294 insertions(+), 7 deletions(-)
 create mode 100644 libctf/Makefile.am
 create mode 100644 libctf/Makefile.in
 create mode 100644 libctf/aclocal.m4
 create mode 100644 libctf/config.h.in
 create mode 100755 libctf/configure
 create mode 100644 libctf/configure.ac

diff --git a/Makefile.def b/Makefile.def
index 75063b6d12..23e3923483 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -128,6 +128,8 @@ host_modules= { module= lto-plugin; bootstrap=true;
 		extra_make_flags='@extra_linker_plugin_flags@'; };
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
 host_modules= { module= gotools; };
+host_modules= { module= libctf; no_install=true; no_check=true;
+		bootstrap=true; };
 
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
@@ -426,6 +428,7 @@ dependencies = { module=all-binutils; on=all-build-flex; };
 dependencies = { module=all-binutils; on=all-build-bison; };
 dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
+dependencies = { module=all-binutils; on=all-libctf; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
@@ -516,6 +519,8 @@ dependencies = { module=all-sim; on=configure-gdb; };
 dependencies = { module=all-fastjar; on=all-zlib; };
 dependencies = { module=all-fastjar; on=all-build-texinfo; };
 dependencies = { module=all-fastjar; on=all-libiberty; };
+dependencies = { module=all-libctf; on=all-libiberty; hard=true; };
+dependencies = { module=all-libctf; on=all-zlib; };
 
 // Warning, these are not well tested.
 dependencies = { module=all-bison; on=all-intl; };
diff --git a/Makefile.in b/Makefile.in
index 7814fe745f..c0e2b695bd 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -951,7 +951,8 @@ configure-host:  \
     maybe-configure-gnattools \
     maybe-configure-lto-plugin \
     maybe-configure-libcc1 \
-    maybe-configure-gotools
+    maybe-configure-gotools \
+    maybe-configure-libctf
 .PHONY: configure-target
 configure-target:  \
     maybe-configure-target-libstdc++-v3 \
@@ -1106,6 +1107,9 @@ all-host: maybe-all-lto-plugin
 @endif lto-plugin-no-bootstrap
 all-host: maybe-all-libcc1
 all-host: maybe-all-gotools
+@if libctf-no-bootstrap
+all-host: maybe-all-libctf
+@endif libctf-no-bootstrap
 
 .PHONY: all-target
 
@@ -1208,6 +1212,7 @@ info-host: maybe-info-gnattools
 info-host: maybe-info-lto-plugin
 info-host: maybe-info-libcc1
 info-host: maybe-info-gotools
+info-host: maybe-info-libctf
 
 .PHONY: info-target
 
@@ -1293,6 +1298,7 @@ dvi-host: maybe-dvi-gnattools
 dvi-host: maybe-dvi-lto-plugin
 dvi-host: maybe-dvi-libcc1
 dvi-host: maybe-dvi-gotools
+dvi-host: maybe-dvi-libctf
 
 .PHONY: dvi-target
 
@@ -1378,6 +1384,7 @@ pdf-host: maybe-pdf-gnattools
 pdf-host: maybe-pdf-lto-plugin
 pdf-host: maybe-pdf-libcc1
 pdf-host: maybe-pdf-gotools
+pdf-host: maybe-pdf-libctf
 
 .PHONY: pdf-target
 
@@ -1463,6 +1470,7 @@ html-host: maybe-html-gnattools
 html-host: maybe-html-lto-plugin
 html-host: maybe-html-libcc1
 html-host: maybe-html-gotools
+html-host: maybe-html-libctf
 
 .PHONY: html-target
 
@@ -1548,6 +1556,7 @@ TAGS-host: maybe-TAGS-gnattools
 TAGS-host: maybe-TAGS-lto-plugin
 TAGS-host: maybe-TAGS-libcc1
 TAGS-host: maybe-TAGS-gotools
+TAGS-host: maybe-TAGS-libctf
 
 .PHONY: TAGS-target
 
@@ -1633,6 +1642,7 @@ install-info-host: maybe-install-info-gnattools
 install-info-host: maybe-install-info-lto-plugin
 install-info-host: maybe-install-info-libcc1
 install-info-host: maybe-install-info-gotools
+install-info-host: maybe-install-info-libctf
 
 .PHONY: install-info-target
 
@@ -1718,6 +1728,7 @@ install-pdf-host: maybe-install-pdf-gnattools
 install-pdf-host: maybe-install-pdf-lto-plugin
 install-pdf-host: maybe-install-pdf-libcc1
 install-pdf-host: maybe-install-pdf-gotools
+install-pdf-host: maybe-install-pdf-libctf
 
 .PHONY: install-pdf-target
 
@@ -1803,6 +1814,7 @@ install-html-host: maybe-install-html-gnattools
 install-html-host: maybe-install-html-lto-plugin
 install-html-host: maybe-install-html-libcc1
 install-html-host: maybe-install-html-gotools
+install-html-host: maybe-install-html-libctf
 
 .PHONY: install-html-target
 
@@ -1888,6 +1900,7 @@ installcheck-host: maybe-installcheck-gnattools
 installcheck-host: maybe-installcheck-lto-plugin
 installcheck-host: maybe-installcheck-libcc1
 installcheck-host: maybe-installcheck-gotools
+installcheck-host: maybe-installcheck-libctf
 
 .PHONY: installcheck-target
 
@@ -1973,6 +1986,7 @@ mostlyclean-host: maybe-mostlyclean-gnattools
 mostlyclean-host: maybe-mostlyclean-lto-plugin
 mostlyclean-host: maybe-mostlyclean-libcc1
 mostlyclean-host: maybe-mostlyclean-gotools
+mostlyclean-host: maybe-mostlyclean-libctf
 
 .PHONY: mostlyclean-target
 
@@ -2058,6 +2072,7 @@ clean-host: maybe-clean-gnattools
 clean-host: maybe-clean-lto-plugin
 clean-host: maybe-clean-libcc1
 clean-host: maybe-clean-gotools
+clean-host: maybe-clean-libctf
 
 .PHONY: clean-target
 
@@ -2143,6 +2158,7 @@ distclean-host: maybe-distclean-gnattools
 distclean-host: maybe-distclean-lto-plugin
 distclean-host: maybe-distclean-libcc1
 distclean-host: maybe-distclean-gotools
+distclean-host: maybe-distclean-libctf
 
 .PHONY: distclean-target
 
@@ -2228,6 +2244,7 @@ maintainer-clean-host: maybe-maintainer-clean-gnattools
 maintainer-clean-host: maybe-maintainer-clean-lto-plugin
 maintainer-clean-host: maybe-maintainer-clean-libcc1
 maintainer-clean-host: maybe-maintainer-clean-gotools
+maintainer-clean-host: maybe-maintainer-clean-libctf
 
 .PHONY: maintainer-clean-target
 
@@ -2368,7 +2385,8 @@ check-host:  \
     maybe-check-gnattools \
     maybe-check-lto-plugin \
     maybe-check-libcc1 \
-    maybe-check-gotools
+    maybe-check-gotools \
+    maybe-check-libctf
 
 .PHONY: check-target
 check-target:  \
@@ -2500,7 +2518,8 @@ install-host-nogcc:  \
     maybe-install-gnattools \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
-    maybe-install-gotools
+    maybe-install-gotools \
+    maybe-install-libctf
 
 .PHONY: install-host
 install-host:  \
@@ -2549,7 +2568,8 @@ install-host:  \
     maybe-install-gnattools \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
-    maybe-install-gotools
+    maybe-install-gotools \
+    maybe-install-libctf
 
 .PHONY: install-target
 install-target:  \
@@ -2654,7 +2674,8 @@ install-strip-host:  \
     maybe-install-strip-gnattools \
     maybe-install-strip-lto-plugin \
     maybe-install-strip-libcc1 \
-    maybe-install-strip-gotools
+    maybe-install-strip-gotools \
+    maybe-install-strip-libctf
 
 .PHONY: install-strip-target
 install-strip-target:  \
@@ -32847,6 +32868,868 @@ maintainer-clean-gotools:
 
 
 
+.PHONY: configure-libctf maybe-configure-libctf
+maybe-configure-libctf:
+@if gcc-bootstrap
+configure-libctf: stage_current
+@endif gcc-bootstrap
+@if libctf
+maybe-configure-libctf: configure-libctf
+configure-libctf: 
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	$(HOST_EXPORTS)  \
+	echo Configuring in $(HOST_SUBDIR)/libctf; \
+	cd "$(HOST_SUBDIR)/libctf" || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) \
+	  $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias}  \
+	  || exit 1
+@endif libctf
+
+
+
+.PHONY: configure-stage1-libctf maybe-configure-stage1-libctf
+maybe-configure-stage1-libctf:
+@if libctf-bootstrap
+maybe-configure-stage1-libctf: configure-stage1-libctf
+configure-stage1-libctf:
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	CFLAGS="$(STAGE1_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE1_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(LIBCFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 1 in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	   \
+	  $(STAGE1_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+.PHONY: configure-stage2-libctf maybe-configure-stage2-libctf
+maybe-configure-stage2-libctf:
+@if libctf-bootstrap
+maybe-configure-stage2-libctf: configure-stage2-libctf
+configure-stage2-libctf:
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE2_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE2_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE2_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 2 in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE2_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+.PHONY: configure-stage3-libctf maybe-configure-stage3-libctf
+maybe-configure-stage3-libctf:
+@if libctf-bootstrap
+maybe-configure-stage3-libctf: configure-stage3-libctf
+configure-stage3-libctf:
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE3_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE3_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE3_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 3 in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE3_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+.PHONY: configure-stage4-libctf maybe-configure-stage4-libctf
+maybe-configure-stage4-libctf:
+@if libctf-bootstrap
+maybe-configure-stage4-libctf: configure-stage4-libctf
+configure-stage4-libctf:
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE4_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE4_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE4_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 4 in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE4_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+.PHONY: configure-stageprofile-libctf maybe-configure-stageprofile-libctf
+maybe-configure-stageprofile-libctf:
+@if libctf-bootstrap
+maybe-configure-stageprofile-libctf: configure-stageprofile-libctf
+configure-stageprofile-libctf:
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEprofile_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEprofile_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEprofile_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage profile in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEprofile_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+.PHONY: configure-stagefeedback-libctf maybe-configure-stagefeedback-libctf
+maybe-configure-stagefeedback-libctf:
+@if libctf-bootstrap
+maybe-configure-stagefeedback-libctf: configure-stagefeedback-libctf
+configure-stagefeedback-libctf:
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctf/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEfeedback_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEfeedback_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEfeedback_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage feedback in $(HOST_SUBDIR)/libctf; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctf; \
+	cd $(HOST_SUBDIR)/libctf || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctf/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctf; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEfeedback_CONFIGURE_FLAGS)
+@endif libctf-bootstrap
+
+
+
+
+
+.PHONY: all-libctf maybe-all-libctf
+maybe-all-libctf:
+@if gcc-bootstrap
+all-libctf: stage_current
+@endif gcc-bootstrap
+@if libctf
+TARGET-libctf=all
+maybe-all-libctf: all-libctf
+all-libctf: configure-libctf
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS)  \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS)  \
+		$(TARGET-libctf))
+@endif libctf
+
+
+
+.PHONY: all-stage1-libctf maybe-all-stage1-libctf
+.PHONY: clean-stage1-libctf maybe-clean-stage1-libctf
+maybe-all-stage1-libctf:
+maybe-clean-stage1-libctf:
+@if libctf-bootstrap
+maybe-all-stage1-libctf: all-stage1-libctf
+all-stage1: all-stage1-libctf
+TARGET-stage1-libctf = $(TARGET-libctf)
+all-stage1-libctf: configure-stage1-libctf
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	$(HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE1_CFLAGS)" \
+		CXXFLAGS="$(STAGE1_CXXFLAGS)" \
+		LIBCFLAGS="$(LIBCFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS)  \
+		$(STAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE1_TFLAGS)"  \
+		$(TARGET-stage1-libctf)
+
+maybe-clean-stage1-libctf: clean-stage1-libctf
+clean-stage1: clean-stage1-libctf
+clean-stage1-libctf:
+	@if [ $(current_stage) = stage1 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage1-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stage1-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS)  \
+	$(STAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+.PHONY: all-stage2-libctf maybe-all-stage2-libctf
+.PHONY: clean-stage2-libctf maybe-clean-stage2-libctf
+maybe-all-stage2-libctf:
+maybe-clean-stage2-libctf:
+@if libctf-bootstrap
+maybe-all-stage2-libctf: all-stage2-libctf
+all-stage2: all-stage2-libctf
+TARGET-stage2-libctf = $(TARGET-libctf)
+all-stage2-libctf: configure-stage2-libctf
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE2_CFLAGS)" \
+		CXXFLAGS="$(STAGE2_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE2_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE2_TFLAGS)"  \
+		$(TARGET-stage2-libctf)
+
+maybe-clean-stage2-libctf: clean-stage2-libctf
+clean-stage2: clean-stage2-libctf
+clean-stage2-libctf:
+	@if [ $(current_stage) = stage2 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage2-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stage2-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+.PHONY: all-stage3-libctf maybe-all-stage3-libctf
+.PHONY: clean-stage3-libctf maybe-clean-stage3-libctf
+maybe-all-stage3-libctf:
+maybe-clean-stage3-libctf:
+@if libctf-bootstrap
+maybe-all-stage3-libctf: all-stage3-libctf
+all-stage3: all-stage3-libctf
+TARGET-stage3-libctf = $(TARGET-libctf)
+all-stage3-libctf: configure-stage3-libctf
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE3_CFLAGS)" \
+		CXXFLAGS="$(STAGE3_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE3_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE3_TFLAGS)"  \
+		$(TARGET-stage3-libctf)
+
+maybe-clean-stage3-libctf: clean-stage3-libctf
+clean-stage3: clean-stage3-libctf
+clean-stage3-libctf:
+	@if [ $(current_stage) = stage3 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage3-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stage3-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+.PHONY: all-stage4-libctf maybe-all-stage4-libctf
+.PHONY: clean-stage4-libctf maybe-clean-stage4-libctf
+maybe-all-stage4-libctf:
+maybe-clean-stage4-libctf:
+@if libctf-bootstrap
+maybe-all-stage4-libctf: all-stage4-libctf
+all-stage4: all-stage4-libctf
+TARGET-stage4-libctf = $(TARGET-libctf)
+all-stage4-libctf: configure-stage4-libctf
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE4_CFLAGS)" \
+		CXXFLAGS="$(STAGE4_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE4_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE4_TFLAGS)"  \
+		$(TARGET-stage4-libctf)
+
+maybe-clean-stage4-libctf: clean-stage4-libctf
+clean-stage4: clean-stage4-libctf
+clean-stage4-libctf:
+	@if [ $(current_stage) = stage4 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage4-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stage4-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+.PHONY: all-stageprofile-libctf maybe-all-stageprofile-libctf
+.PHONY: clean-stageprofile-libctf maybe-clean-stageprofile-libctf
+maybe-all-stageprofile-libctf:
+maybe-clean-stageprofile-libctf:
+@if libctf-bootstrap
+maybe-all-stageprofile-libctf: all-stageprofile-libctf
+all-stageprofile: all-stageprofile-libctf
+TARGET-stageprofile-libctf = $(TARGET-libctf)
+all-stageprofile-libctf: configure-stageprofile-libctf
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEprofile_CFLAGS)" \
+		CXXFLAGS="$(STAGEprofile_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEprofile_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEprofile_TFLAGS)"  \
+		$(TARGET-stageprofile-libctf)
+
+maybe-clean-stageprofile-libctf: clean-stageprofile-libctf
+clean-stageprofile: clean-stageprofile-libctf
+clean-stageprofile-libctf:
+	@if [ $(current_stage) = stageprofile ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageprofile-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stageprofile-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+.PHONY: all-stagefeedback-libctf maybe-all-stagefeedback-libctf
+.PHONY: clean-stagefeedback-libctf maybe-clean-stagefeedback-libctf
+maybe-all-stagefeedback-libctf:
+maybe-clean-stagefeedback-libctf:
+@if libctf-bootstrap
+maybe-all-stagefeedback-libctf: all-stagefeedback-libctf
+all-stagefeedback: all-stagefeedback-libctf
+TARGET-stagefeedback-libctf = $(TARGET-libctf)
+all-stagefeedback-libctf: configure-stagefeedback-libctf
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctf && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEfeedback_CFLAGS)" \
+		CXXFLAGS="$(STAGEfeedback_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEfeedback_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEfeedback_TFLAGS)"  \
+		$(TARGET-stagefeedback-libctf)
+
+maybe-clean-stagefeedback-libctf: clean-stagefeedback-libctf
+clean-stagefeedback: clean-stagefeedback-libctf
+clean-stagefeedback-libctf:
+	@if [ $(current_stage) = stagefeedback ]; then \
+	  [ -f $(HOST_SUBDIR)/libctf/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stagefeedback-libctf/Makefile ] || exit 0; \
+	  $(MAKE) stagefeedback-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctf && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctf-bootstrap
+
+
+
+
+
+.PHONY: check-libctf maybe-check-libctf
+maybe-check-libctf:
+@if libctf
+maybe-check-libctf: check-libctf
+
+check-libctf:
+
+@endif libctf
+
+.PHONY: install-libctf maybe-install-libctf
+maybe-install-libctf:
+@if libctf
+maybe-install-libctf: install-libctf
+
+install-libctf:
+
+@endif libctf
+
+.PHONY: install-strip-libctf maybe-install-strip-libctf
+maybe-install-strip-libctf:
+@if libctf
+maybe-install-strip-libctf: install-strip-libctf
+
+install-strip-libctf:
+
+@endif libctf
+
+# Other targets (info, dvi, pdf, etc.)
+
+.PHONY: maybe-info-libctf info-libctf
+maybe-info-libctf:
+@if libctf
+maybe-info-libctf: info-libctf
+
+info-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing info in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          info) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-dvi-libctf dvi-libctf
+maybe-dvi-libctf:
+@if libctf
+maybe-dvi-libctf: dvi-libctf
+
+dvi-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing dvi in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          dvi) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-pdf-libctf pdf-libctf
+maybe-pdf-libctf:
+@if libctf
+maybe-pdf-libctf: pdf-libctf
+
+pdf-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing pdf in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          pdf) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-html-libctf html-libctf
+maybe-html-libctf:
+@if libctf
+maybe-html-libctf: html-libctf
+
+html-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing html in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          html) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-TAGS-libctf TAGS-libctf
+maybe-TAGS-libctf:
+@if libctf
+maybe-TAGS-libctf: TAGS-libctf
+
+TAGS-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing TAGS in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          TAGS) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-install-info-libctf install-info-libctf
+maybe-install-info-libctf:
+@if libctf
+maybe-install-info-libctf: install-info-libctf
+
+install-info-libctf: \
+    configure-libctf \
+    info-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-info in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-info) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-install-pdf-libctf install-pdf-libctf
+maybe-install-pdf-libctf:
+@if libctf
+maybe-install-pdf-libctf: install-pdf-libctf
+
+install-pdf-libctf: \
+    configure-libctf \
+    pdf-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-pdf in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-pdf) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-install-html-libctf install-html-libctf
+maybe-install-html-libctf:
+@if libctf
+maybe-install-html-libctf: install-html-libctf
+
+install-html-libctf: \
+    configure-libctf \
+    html-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-html in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-html) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-installcheck-libctf installcheck-libctf
+maybe-installcheck-libctf:
+@if libctf
+maybe-installcheck-libctf: installcheck-libctf
+
+installcheck-libctf: \
+    configure-libctf 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing installcheck in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          installcheck) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-mostlyclean-libctf mostlyclean-libctf
+maybe-mostlyclean-libctf:
+@if libctf
+maybe-mostlyclean-libctf: mostlyclean-libctf
+
+mostlyclean-libctf: 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing mostlyclean in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          mostlyclean) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-clean-libctf clean-libctf
+maybe-clean-libctf:
+@if libctf
+maybe-clean-libctf: clean-libctf
+
+clean-libctf: 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing clean in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          clean) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-distclean-libctf distclean-libctf
+maybe-distclean-libctf:
+@if libctf
+maybe-distclean-libctf: distclean-libctf
+
+distclean-libctf: 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing distclean in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          distclean) \
+	  || exit 1
+
+@endif libctf
+
+.PHONY: maybe-maintainer-clean-libctf maintainer-clean-libctf
+maybe-maintainer-clean-libctf:
+@if libctf
+maybe-maintainer-clean-libctf: maintainer-clean-libctf
+
+maintainer-clean-libctf: 
+	@[ -f ./libctf/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing maintainer-clean in libctf"; \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          maintainer-clean) \
+	  || exit 1
+
+@endif libctf
+
+
+
 # ---------------------------------------
 # Modules which run on the target machine
 # ---------------------------------------
@@ -47179,6 +48062,11 @@ stage1-start::
 	  mkdir stage1-lto-plugin; \
 	mv stage1-lto-plugin lto-plugin
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stage1-libctf ] || \
+	  mkdir stage1-libctf; \
+	mv stage1-libctf libctf
+@endif libctf
 	@[ -d stage1-$(TARGET_SUBDIR) ] || \
 	  mkdir stage1-$(TARGET_SUBDIR); \
 	mv stage1-$(TARGET_SUBDIR) $(TARGET_SUBDIR)
@@ -47294,6 +48182,11 @@ stage1-end::
 	  cd $(HOST_SUBDIR); mv lto-plugin stage1-lto-plugin; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stage1-libctf; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); \
 	fi
@@ -47474,6 +48367,12 @@ stage2-start::
 	mv stage2-lto-plugin lto-plugin; \
 	mv stage1-lto-plugin prev-lto-plugin || test -f stage1-lean 
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stage2-libctf ] || \
+	  mkdir stage2-libctf; \
+	mv stage2-libctf libctf; \
+	mv stage1-libctf prev-libctf || test -f stage1-lean 
+@endif libctf
 	@[ -d stage2-$(TARGET_SUBDIR) ] || \
 	  mkdir stage2-$(TARGET_SUBDIR); \
 	mv stage2-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -47612,6 +48511,12 @@ stage2-end::
 	  mv prev-lto-plugin stage1-lto-plugin; : ; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stage2-libctf; \
+	  mv prev-libctf stage1-libctf; : ; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -47816,6 +48721,12 @@ stage3-start::
 	mv stage3-lto-plugin lto-plugin; \
 	mv stage2-lto-plugin prev-lto-plugin || test -f stage2-lean 
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stage3-libctf ] || \
+	  mkdir stage3-libctf; \
+	mv stage3-libctf libctf; \
+	mv stage2-libctf prev-libctf || test -f stage2-lean 
+@endif libctf
 	@[ -d stage3-$(TARGET_SUBDIR) ] || \
 	  mkdir stage3-$(TARGET_SUBDIR); \
 	mv stage3-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -47954,6 +48865,12 @@ stage3-end::
 	  mv prev-lto-plugin stage2-lto-plugin; : ; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stage3-libctf; \
+	  mv prev-libctf stage2-libctf; : ; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); : ; \
@@ -48214,6 +49131,12 @@ stage4-start::
 	mv stage4-lto-plugin lto-plugin; \
 	mv stage3-lto-plugin prev-lto-plugin || test -f stage3-lean 
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stage4-libctf ] || \
+	  mkdir stage4-libctf; \
+	mv stage4-libctf libctf; \
+	mv stage3-libctf prev-libctf || test -f stage3-lean 
+@endif libctf
 	@[ -d stage4-$(TARGET_SUBDIR) ] || \
 	  mkdir stage4-$(TARGET_SUBDIR); \
 	mv stage4-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -48352,6 +49275,12 @@ stage4-end::
 	  mv prev-lto-plugin stage3-lto-plugin; : ; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stage4-libctf; \
+	  mv prev-libctf stage3-libctf; : ; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage4-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); : ; \
@@ -48600,6 +49529,12 @@ stageprofile-start::
 	mv stageprofile-lto-plugin lto-plugin; \
 	mv stage1-lto-plugin prev-lto-plugin || test -f stage1-lean 
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stageprofile-libctf ] || \
+	  mkdir stageprofile-libctf; \
+	mv stageprofile-libctf libctf; \
+	mv stage1-libctf prev-libctf || test -f stage1-lean 
+@endif libctf
 	@[ -d stageprofile-$(TARGET_SUBDIR) ] || \
 	  mkdir stageprofile-$(TARGET_SUBDIR); \
 	mv stageprofile-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -48738,6 +49673,12 @@ stageprofile-end::
 	  mv prev-lto-plugin stage1-lto-plugin; : ; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stageprofile-libctf; \
+	  mv prev-libctf stage1-libctf; : ; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -48919,6 +49860,12 @@ stagefeedback-start::
 	mv stagefeedback-lto-plugin lto-plugin; \
 	mv stageprofile-lto-plugin prev-lto-plugin || test -f stageprofile-lean 
 @endif lto-plugin
+@if libctf
+	@cd $(HOST_SUBDIR); [ -d stagefeedback-libctf ] || \
+	  mkdir stagefeedback-libctf; \
+	mv stagefeedback-libctf libctf; \
+	mv stageprofile-libctf prev-libctf || test -f stageprofile-lean 
+@endif libctf
 	@[ -d stagefeedback-$(TARGET_SUBDIR) ] || \
 	  mkdir stagefeedback-$(TARGET_SUBDIR); \
 	mv stagefeedback-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -49057,6 +50004,12 @@ stagefeedback-end::
 	  mv prev-lto-plugin stageprofile-lto-plugin; : ; \
 	fi
 @endif lto-plugin
+@if libctf
+	@if test -d $(HOST_SUBDIR)/libctf; then \
+	  cd $(HOST_SUBDIR); mv libctf stagefeedback-libctf; \
+	  mv prev-libctf stageprofile-libctf; : ; \
+	fi
+@endif libctf
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stagefeedback-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); : ; \
@@ -49737,6 +50690,13 @@ all-stage3-binutils: maybe-all-stage3-gas
 all-stage4-binutils: maybe-all-stage4-gas
 all-stageprofile-binutils: maybe-all-stageprofile-gas
 all-stagefeedback-binutils: maybe-all-stagefeedback-gas
+all-binutils: maybe-all-libctf
+all-stage1-binutils: maybe-all-stage1-libctf
+all-stage2-binutils: maybe-all-stage2-libctf
+all-stage3-binutils: maybe-all-stage3-libctf
+all-stage4-binutils: maybe-all-stage4-libctf
+all-stageprofile-binutils: maybe-all-stageprofile-libctf
+all-stagefeedback-binutils: maybe-all-stagefeedback-libctf
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
 install-opcodes: maybe-install-bfd
@@ -49949,6 +50909,20 @@ install-strip-sid: maybe-install-strip-tk
 all-sim: maybe-all-readline
 all-sim: maybe-configure-gdb
 all-fastjar: maybe-all-build-texinfo
+all-libctf: all-libiberty
+all-stage1-libctf: all-stage1-libiberty
+all-stage2-libctf: all-stage2-libiberty
+all-stage3-libctf: all-stage3-libiberty
+all-stage4-libctf: all-stage4-libiberty
+all-stageprofile-libctf: all-stageprofile-libiberty
+all-stagefeedback-libctf: all-stagefeedback-libiberty
+all-libctf: maybe-all-zlib
+all-stage1-libctf: maybe-all-stage1-zlib
+all-stage2-libctf: maybe-all-stage2-zlib
+all-stage3-libctf: maybe-all-stage3-zlib
+all-stage4-libctf: maybe-all-stage4-zlib
+all-stageprofile-libctf: maybe-all-stageprofile-zlib
+all-stagefeedback-libctf: maybe-all-stagefeedback-zlib
 all-bison: maybe-all-build-texinfo
 all-flex: maybe-all-build-bison
 all-flex: maybe-all-m4
diff --git a/configure b/configure
index 3747645961..3e95ce50ff 100755
--- a/configure
+++ b/configure
@@ -2769,7 +2769,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/configure.ac b/configure.ac
index 46501c2882..c84263c516 100644
--- a/configure.ac
+++ b/configure.ac
@@ -131,7 +131,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
new file mode 100644
index 0000000000..867330befd
--- /dev/null
+++ b/libctf/Makefile.am
@@ -0,0 +1,31 @@
+## Process this file with automake to produce Makefile.in.
+#
+#   Copyright (C) 2019 Free Software Foundation, Inc.
+#
+# This file 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+ACLOCAL_AMFLAGS = -I .. -I ../config
+
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/../include -I$(top_srcdir)/libctf
+AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+
+noinst_LIBRARIES = libctf.a
+
+libctf_a_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
+		   ctf-hash.c ctf-labels.c ctf-lib.c ctf-lookup.c \
+		   ctf-open.c ctf-subr.c ctf-types.c ctf-util.c
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
new file mode 100644
index 0000000000..0e3beda158
--- /dev/null
+++ b/libctf/Makefile.in
@@ -0,0 +1,767 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+#   Copyright (C) 2019 Free Software Foundation, Inc.
+#
+# This file 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo "  AR      " $@;
+am__v_AR_1 = 
+libctf_a_AR = $(AR) $(ARFLAGS)
+libctf_a_LIBADD =
+am_libctf_a_OBJECTS = ctf-archive.$(OBJEXT) ctf-dump.$(OBJEXT) \
+	ctf-create.$(OBJEXT) ctf-decl.$(OBJEXT) ctf-error.$(OBJEXT) \
+	ctf-hash.$(OBJEXT) ctf-labels.$(OBJEXT) ctf-lib.$(OBJEXT) \
+	ctf-lookup.$(OBJEXT) ctf-open.$(OBJEXT) ctf-subr.$(OBJEXT) \
+	ctf-types.$(OBJEXT) ctf-util.$(OBJEXT)
+libctf_a_OBJECTS = $(am_libctf_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libctf_a_SOURCES)
+DIST_SOURCES = $(libctf_a_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+AM_RECURSIVE_TARGETS = cscope
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
+	$(top_srcdir)/../depcomp $(top_srcdir)/../install-sh \
+	$(top_srcdir)/../missing $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_libctf_warn_cflags = @ac_libctf_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+ACLOCAL_AMFLAGS = -I .. -I ../config
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/../include -I$(top_srcdir)/libctf
+AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+noinst_LIBRARIES = libctf.a
+libctf_a_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
+		   ctf-hash.c ctf-labels.c ctf-lib.c ctf-lookup.c \
+		   ctf-open.c ctf-subr.c ctf-types.c ctf-util.c
+
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libctf.a: $(libctf_a_OBJECTS) $(libctf_a_DEPENDENCIES) $(EXTRA_libctf_a_DEPENDENCIES) 
+	$(AM_V_at)-rm -f libctf.a
+	$(AM_V_AR)$(libctf_a_AR) libctf.a $(libctf_a_OBJECTS) $(libctf_a_LIBADD)
+	$(AM_V_at)$(RANLIB) libctf.a
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-create.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-decl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-labels.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-lib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-lookup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-subr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-types.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-util.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) config.h
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
+	clean-cscope clean-generic clean-noinstLIBRARIES cscope \
+	cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+	dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libctf/aclocal.m4 b/libctf/aclocal.m4
new file mode 100644
index 0000000000..d792e62dfb
--- /dev/null
+++ b/libctf/aclocal.m4
@@ -0,0 +1,1233 @@
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [AC_LANG_PUSH([C])
+   am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well.  Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+       [enable], [m4_define([am_maintainer_other], [disable])],
+       [disable], [m4_define([am_maintainer_other], [enable])],
+       [m4_define([am_maintainer_other], [enable])
+        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+  AC_ARG_ENABLE([maintainer-mode],
+    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+      am_maintainer_other[ make rules and dependencies not useful
+      (and sometimes confusing) to the casual installer])],
+    [USE_MAINTAINER_MODE=$enableval],
+    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../config/depstand.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/override.m4])
+m4_include([../config/warnings.m4])
diff --git a/libctf/config.h.in b/libctf/config.h.in
new file mode 100644
index 0000000000..ee77645205
--- /dev/null
+++ b/libctf/config.h.in
@@ -0,0 +1,98 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/libctf/configure b/libctf/configure
new file mode 100755
index 0000000000..c6f177decd
--- /dev/null
+++ b/libctf/configure
@@ -0,0 +1,7120 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for libctf library 1.2.0-pre.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='libctf library'
+PACKAGE_TARNAME='libctf-library'
+PACKAGE_VERSION='1.2.0-pre'
+PACKAGE_STRING='libctf library 1.2.0-pre'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="ctf-impl.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+ac_libctf_warn_cflags
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+WERROR
+WARN_PEDANTIC
+c_warn
+warn
+ac_ct_AR
+AR
+RANLIB
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_dependency_tracking
+enable_silent_rules
+enable_largefile
+enable_werror_always
+enable_maintainer_mode
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures libctf library 1.2.0-pre to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/libctf-library]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of libctf library 1.2.0-pre:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --disable-largefile     omit support for large files
+  --enable-werror-always  enable -Werror despite compiler version
+  --enable-maintainer-mode
+                          enable make rules and dependencies not useful (and
+                          sometimes confusing) to the casual installer
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+libctf library configure 1.2.0-pre
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by libctf library $as_me 1.2.0-pre, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+  ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+  if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+  fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#         define __EXTENSIONS__ 1
+          $ac_includes_default
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_safe_to_define___extensions__=yes
+else
+  ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+  $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+  $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+am__api_version='1.15'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libctf-library'
+ VERSION='1.2.0-pre'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+
+# Checks for programs.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar lib "link -lib"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar lib "link -lib"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+   am_cv_ar_interface=ar
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+        { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+  ;;
+esac
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+	 # IRIX 6.2 and later do not support large files by default,
+	 # so use the C compiler's -n32 option if that helps.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 CC="$CC -n32"
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  fi
+
+
+fi
+
+
+MISSING=`cd $ac_aux_dir && ${PWDCMD-pwd}`/missing
+for ac_prog in aclocal
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ACLOCAL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ACLOCAL"; then
+  ac_cv_prog_ACLOCAL="$ACLOCAL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ACLOCAL="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ACLOCAL=$ac_cv_prog_ACLOCAL
+if test -n "$ACLOCAL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ACLOCAL" >&5
+$as_echo "$ACLOCAL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ACLOCAL" && break
+done
+test -n "$ACLOCAL" || ACLOCAL="$MISSING aclocal"
+
+for ac_prog in autoconf
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AUTOCONF+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AUTOCONF"; then
+  ac_cv_prog_AUTOCONF="$AUTOCONF" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AUTOCONF="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AUTOCONF=$ac_cv_prog_AUTOCONF
+if test -n "$AUTOCONF"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5
+$as_echo "$AUTOCONF" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AUTOCONF" && break
+done
+test -n "$AUTOCONF" || AUTOCONF="$MISSING autoconf"
+
+for ac_prog in autoheader
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AUTOHEADER+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AUTOHEADER"; then
+  ac_cv_prog_AUTOHEADER="$AUTOHEADER" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AUTOHEADER="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AUTOHEADER=$ac_cv_prog_AUTOHEADER
+if test -n "$AUTOHEADER"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOHEADER" >&5
+$as_echo "$AUTOHEADER" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AUTOHEADER" && break
+done
+test -n "$AUTOHEADER" || AUTOHEADER="$MISSING autoheader"
+
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+warn=
+save_CFLAGS="$CFLAGS"
+for real_option in -W -Wall -Wno-narrowing -Wwrite-strings \
+			  -Wmissing-format-attribute; do
+  # Do the check with the no- prefix removed since gcc silently
+  # accepts any -Wno-* option on purpose
+  case $real_option in
+    -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;;
+    *) option=$real_option ;;
+  esac
+  as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh`
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5
+$as_echo_n "checking whether $CC supports $option... " >&6; }
+if eval \${$as_acx_Woption+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS="$option"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_acx_Woption=yes"
+else
+  eval "$as_acx_Woption=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$$as_acx_Woption
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then :
+  warn="$warn${warn:+ }$real_option"
+fi
+  done
+CFLAGS="$save_CFLAGS"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+c_warn=
+save_CFLAGS="$CFLAGS"
+for real_option in -Wstrict-prototypes -Wmissing-prototypes \
+			  -Wold-style-definition; do
+  # Do the check with the no- prefix removed since gcc silently
+  # accepts any -Wno-* option on purpose
+  case $real_option in
+    -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;;
+    *) option=$real_option ;;
+  esac
+  as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh`
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5
+$as_echo_n "checking whether $CC supports $option... " >&6; }
+if eval \${$as_acx_Woption+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS="$option"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_acx_Woption=yes"
+else
+  eval "$as_acx_Woption=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$$as_acx_Woption
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then :
+  c_warn="$c_warn${c_warn:+ }$real_option"
+fi
+  done
+CFLAGS="$save_CFLAGS"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+WARN_PEDANTIC=
+# Do the check with the no- prefix removed from the warning options
+# since gcc silently accepts any -Wno-* option on purpose
+if test "$GCC" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -pedantic -Wlong-long" >&5
+$as_echo_n "checking whether $CC supports -pedantic -Wlong-long... " >&6; }
+if ${acx_cv_prog_cc_pedantic__Wlong_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_CFLAGS="$CFLAGS"
+CFLAGS="-pedantic -Wlong-long"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  acx_cv_prog_cc_pedantic__Wlong_long=yes
+else
+  acx_cv_prog_cc_pedantic__Wlong_long=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$save_CFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_prog_cc_pedantic__Wlong_long" >&5
+$as_echo "$acx_cv_prog_cc_pedantic__Wlong_long" >&6; }
+if test $acx_cv_prog_cc_pedantic__Wlong_long = yes; then :
+  WARN_PEDANTIC="$WARN_PEDANTIC${WARN_PEDANTIC:+ }-pedantic -Wno-long-long"
+fi
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Only enable with --enable-werror-always until existing warnings are
+# corrected.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+WERROR=
+# Check whether --enable-werror-always was given.
+if test "${enable_werror_always+set}" = set; then :
+  enableval=$enable_werror_always;
+else
+  enable_werror_always=no
+fi
+
+if test $enable_werror_always = yes; then :
+  WERROR="$WERROR${WERROR:+ }-Werror"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+    # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+   if test $USE_MAINTAINER_MODE = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
+
+  MAINT=$MAINTAINER_MODE_TRUE
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_libctf_warn_cflags=
+save_CFLAGS="$CFLAGS"
+for real_option in -Wall; do
+  # Do the check with the no- prefix removed since gcc silently
+  # accepts any -Wno-* option on purpose
+  case $real_option in
+    -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;;
+    *) option=$real_option ;;
+  esac
+  as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh`
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5
+$as_echo_n "checking whether $CC supports $option... " >&6; }
+if eval \${$as_acx_Woption+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS="$option"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_acx_Woption=yes"
+else
+  eval "$as_acx_Woption=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$$as_acx_Woption
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then :
+  ac_libctf_warn_cflags="$ac_libctf_warn_cflags${ac_libctf_warn_cflags:+ }$real_option"
+fi
+  done
+CFLAGS="$save_CFLAGS"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_config_files="$ac_config_files Makefile"
+
+ac_config_headers="$ac_config_headers config.h"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by libctf library $as_me 1.2.0-pre, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+libctf library config.status 1.2.0-pre
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C)  Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/libctf/configure.ac b/libctf/configure.ac
new file mode 100644
index 0000000000..e1afc76ac6
--- /dev/null
+++ b/libctf/configure.ac
@@ -0,0 +1,59 @@
+dnl                                            -*- Autoconf -*-
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl   Copyright (C) 2019 Free Software Foundation, Inc.
+dnl
+dnl This file is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; see the file COPYING.  If not see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_PREREQ(2.64)
+AC_INIT([libctf library], 1.2.0-pre)
+AC_CONFIG_SRCDIR(ctf-impl.h)
+AC_CONFIG_MACRO_DIR(../config)
+AC_USE_SYSTEM_EXTENSIONS
+AM_INIT_AUTOMAKE
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_RANLIB
+AM_PROG_AR
+
+AC_SYS_LARGEFILE
+
+MISSING=`cd $ac_aux_dir && ${PWDCMD-pwd}`/missing
+AC_CHECK_PROGS([ACLOCAL], [aclocal], [$MISSING aclocal])
+AC_CHECK_PROGS([AUTOCONF], [autoconf], [$MISSING autoconf])
+AC_CHECK_PROGS([AUTOHEADER], [autoheader], [$MISSING autoheader])
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wno-narrowing -Wwrite-strings \
+			  -Wmissing-format-attribute], [warn])
+ACX_PROG_CC_WARNING_OPTS([-Wstrict-prototypes -Wmissing-prototypes \
+			  -Wold-style-definition], [c_warn])
+ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
+
+# Only enable with --enable-werror-always until existing warnings are
+# corrected.
+ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
+
+AM_MAINTAINER_MODE
+ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libctf_warn_cflags])
+
+AC_CONFIG_FILES(Makefile)
+AC_CONFIG_HEADERS(config.h)
+AC_OUTPUT
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 17/19] libctf: debug dumping
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (16 preceding siblings ...)
  2019-04-30 22:58 ` [PATCH 18/19] libctf: build system Nick Alcock
@ 2019-05-01  0:13 ` Nick Alcock
  2019-05-01  0:19 ` [PATCH 16/19] libctf: labels Nick Alcock
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-01  0:13 UTC (permalink / raw)
  To: binutils

This introduces ctf_dump(), an iterator which returns a series of
strings, each representing a debugging dump of one item from a given
section in the CTF file.  The items may be multiline: a callback is
provided to allow the caller to decorate each line as they desire before
the line is returned.

This is all very new code (last week!) and needs review, though all
existing dumpers for CTF have now been rewritten in terms of it, as well
as new ones added to binutils in later commits in this series, and it
seems to work.

libctf/
	* ctf-dump.c: New.

include/
	* ctf-api.h (ctf_dump_decorate_f): New.
	(ctf_dump_state_t): new.
	(ctf_dump): New.
---
 include/ctf-api.h |   9 +
 libctf/ctf-dump.c | 595 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 604 insertions(+)
 create mode 100644 libctf/ctf-dump.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 7cf3f9a3de..d0e62086b5 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -213,6 +213,11 @@ typedef int ctf_label_f (const char *name, const ctf_lblinfo_t *info,
 typedef int ctf_archive_member_f (ctf_file_t *fp, const char *name, void *arg);
 typedef int ctf_archive_raw_member_f (const char *name, const void *content,
 				      size_t len, void *arg);
+typedef char *ctf_dump_decorate_f (ctf_sect_names_t sect,
+				   char *line, void *arg);
+
+typedef struct ctf_dump_state ctf_dump_state_t;
+
 extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t,
 				   size_t, const char *, size_t, int *);
 extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *,
@@ -290,6 +295,10 @@ extern int ctf_archive_iter (const ctf_archive_t *, ctf_archive_member_f *,
 			     void *);
 extern int ctf_archive_raw_iter (const ctf_archive_t *,
 				 ctf_archive_raw_member_f *, void *);
+extern char *ctf_dump (ctf_file_t *, ctf_dump_state_t **state,
+		       ctf_sect_names_t sect, ctf_dump_decorate_f *,
+		       void *arg);
+
 extern ctf_id_t ctf_add_array (ctf_file_t *, uint32_t,
 			       const ctf_arinfo_t *);
 extern ctf_id_t ctf_add_const (ctf_file_t *, uint32_t, ctf_id_t);
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
new file mode 100644
index 0000000000..b45a28b2de
--- /dev/null
+++ b/libctf/ctf-dump.c
@@ -0,0 +1,595 @@
+/* Textual dumping of CTF data.
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+/* One item to be dumped, in string form.  */
+
+typedef struct ctf_dump_item
+{
+  ctf_list_t cdi_list;
+  char *cdi_item;
+} ctf_dump_item_t;
+
+/* Cross-call state for dumping.  Basically just enough to track the section in
+   use and a list of return strings.  */
+
+struct ctf_dump_state
+{
+  ctf_sect_names_t cds_sect;
+  ctf_file_t *cds_fp;
+  ctf_dump_item_t *cds_current;
+  ctf_list_t cds_items;
+};
+
+/* Cross-call state for ctf_dump_member. */
+
+typedef struct ctf_dump_membstate
+{
+  char **cdm_str;
+  ctf_file_t *cdm_fp;
+} ctf_dump_membstate_t;
+
+static int
+ctf_dump_append (ctf_dump_state_t *state, char *str)
+{
+  ctf_dump_item_t *cdi;
+
+  if ((cdi = ctf_alloc (sizeof (struct ctf_dump_item))) == NULL)
+    return (ctf_set_errno (state->cds_fp, ENOMEM));
+
+  cdi->cdi_item = str;
+  ctf_list_append (&state->cds_items, cdi);
+  return 0;
+}
+
+static void
+ctf_dump_free (ctf_dump_state_t *state)
+{
+  ctf_dump_item_t *cdi, *next_cdi;
+
+  if (state == NULL)
+    return;
+
+  for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
+       cdi = next_cdi)
+    {
+      free (cdi->cdi_item);
+      next_cdi = ctf_list_next (cdi);
+      ctf_free (cdi, sizeof (struct ctf_dump_item));
+    }
+}
+
+/* Slices need special handling to distinguish them from their referenced
+   type.  */
+
+static int
+ctf_is_slice (ctf_file_t *fp, ctf_id_t id, ctf_encoding_t *enc)
+{
+  int kind = ctf_type_kind (fp, id);
+
+  return (((kind == CTF_K_INTEGER) || (kind == CTF_K_ENUM)
+	   || (kind == CTF_K_FLOAT))
+	  && ctf_type_reference (fp, id) != CTF_ERR
+	  && ctf_type_encoding (fp, id, enc) != CTF_ERR);
+}
+
+/* Return a dump for a single type, without member info: but do show the
+   type's references.  */
+
+static char *
+ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id)
+{
+  ctf_id_t new_id;
+  char *str = NULL, *bit = NULL, *buf = NULL;
+
+  new_id = id;
+  do
+    {
+      ctf_encoding_t enc;
+
+      id = new_id;
+      buf = ctf_type_aname (fp, id);
+      if (!buf)
+	goto oom;
+
+      /* Slices get a different print representation.  */
+
+      if (ctf_is_slice (fp, id, &enc))
+	{
+	  ctf_type_encoding (fp, id, &enc);
+	  if (asprintf (&bit, " %lx: [slice 0x%x:0x%x]",
+			id, enc.cte_offset, enc.cte_bits) < 0)
+	    goto oom;
+	}
+      else
+	{
+	  if (asprintf (&bit, " %lx: %s (size %lx)", id, buf[0] == '\0' ?
+			"(nameless)" : buf, ctf_type_size (fp, id)) < 0)
+	    goto oom;
+	}
+      free (buf);
+      buf = NULL;
+      str = ctf_str_append (str, bit);
+      free (bit);
+      bit = NULL;
+
+      new_id = ctf_type_reference (fp, id);
+      if (new_id != CTF_ERR)
+	str = ctf_str_append (str, " ->");
+    } while (new_id != CTF_ERR);
+
+  if (ctf_errno (fp) != ECTF_NOTREF)
+    {
+      free (str);
+      return NULL;
+    }
+
+  return str;
+
+ oom:
+  free (buf);
+  free (str);
+  free (bit);
+  ctf_set_errno (fp, ENOMEM);
+  return NULL;
+}
+
+/* Dump a single label into the cds_items.  */
+
+static int
+ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
+		void *arg)
+{
+  char *str;
+  char *typestr;
+  ctf_dump_state_t *state = arg;
+
+  if (asprintf (&str, "%s -> ", name) < 0)
+    return (ctf_set_errno (state->cds_fp, ENOMEM));
+
+  if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type)) == NULL)
+    {
+      free (str);
+      return CTF_ERR;			/* errno is set for us.  */
+    }
+
+  str = ctf_str_append (str, typestr);
+  free (typestr);
+
+  ctf_dump_append (state, str);
+  return 0;
+}
+
+/* Dump all the object entries into the cds_items.  (There is no iterator for
+   this section, so we just do it in a loop, and this function handles all of
+   them, rather than only one.  */
+
+static int
+ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
+{
+  size_t i;
+
+  for (i = 0; i < fp->ctf_nsyms; i++)
+    {
+      char *str;
+      char *typestr;
+      const char *sym_name;
+      ctf_id_t type;
+
+      if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) < 0)
+	switch (ctf_errno (state->cds_fp))
+	  {
+	    /* Most errors are just an indication that this symbol is not a data
+	       symbol, but this one indicates that we were called wrong, on a
+	       CTF file with no associated symbol table.  */
+	  case ECTF_NOSYMTAB:
+	    return CTF_ERR;
+	  case ECTF_NOTDATA:
+	  case ECTF_NOTYPEDAT:
+	    continue;
+	  }
+
+      /* Variable name.  */
+      sym_name = ctf_lookup_symbol_name (fp, i);
+      if (sym_name[0] == '\0')
+	{
+	  if (asprintf (&str, "%lx -> ", i) < 0)
+	    return (ctf_set_errno (fp, ENOMEM));
+	}
+      else
+	{
+	  if (asprintf (&str, "%s (%lx) -> ", sym_name, i) < 0)
+	    return (ctf_set_errno (fp, ENOMEM));
+	}
+
+      /* Variable type.  */
+      if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
+	{
+	  free (str);
+	  return CTF_ERR;		/* errno is set for us.  */
+	}
+
+      str = ctf_str_append (str, typestr);
+      free (typestr);
+
+      ctf_dump_append (state, str);
+    }
+  return 0;
+}
+
+/* Dump all the function entries into the cds_items.  (As above, there is no
+   iterator for this section.)  */
+
+static int
+ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
+{
+  size_t i;
+
+  for (i = 0; i < fp->ctf_nsyms; i++)
+    {
+      char *str ;
+      char *bit;
+      const char *sym_name;
+      ctf_funcinfo_t fi;
+      ctf_id_t type;
+      size_t j;
+      ctf_id_t *args;
+
+      if ((type = ctf_func_info (state->cds_fp, i, &fi)) < 0)
+	switch (ctf_errno (state->cds_fp))
+	  {
+	    /* Most errors are just an indication that this symbol is not a data
+	       symbol, but this one indicates that we were called wrong, on a
+	       CTF file with no associated symbol table.  */
+	  case ECTF_NOSYMTAB:
+	    return CTF_ERR;
+	  case ECTF_NOTDATA:
+	  case ECTF_NOTYPEDAT:
+	    continue;
+	  }
+      if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
+	return (ctf_set_errno (fp, ENOMEM));
+
+      /* Return type.  */
+      if ((str = ctf_type_aname (state->cds_fp, type)) == NULL)
+	goto err;
+
+      str = ctf_str_append (str, " ");
+      free (bit);
+
+      /* Function name.  */
+
+      sym_name = ctf_lookup_symbol_name (fp, i);
+      if (sym_name[0] == '\0')
+	{
+	  if (asprintf (&bit, "%lx ", i) < 0)
+	    goto oom;
+	}
+      else
+	{
+	  if (asprintf (&bit, "%s (%lx) ", sym_name, i) < 0)
+	    goto oom;
+	}
+      str = ctf_str_append (str, bit);
+      str = ctf_str_append (str, " (");
+
+      /* Function arguments.  */
+
+      if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0)
+	goto err;
+
+      for (j = 0; j < fi.ctc_argc; j++)
+	{
+	  if ((bit = ctf_type_aname (state->cds_fp, args[j])) == NULL)
+	    goto err;
+	  str = ctf_str_append (str, bit);
+	  if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG))
+	    str = ctf_str_append (str, ", ");
+	  free (bit);
+	}
+
+      if (fi.ctc_flags & CTF_FUNC_VARARG)
+	str = ctf_str_append (str, "...");
+      str = ctf_str_append (str, ")");
+
+      free (args);
+      ctf_dump_append (state, str);
+      continue;
+
+    oom:
+      free (args);
+      free (str);
+      return (ctf_set_errno (fp, ENOMEM));
+    err:
+      free (args);
+      free (str);
+      return CTF_ERR;		/* errno is set for us.  */
+    }
+  return 0;
+}
+
+/* Dump a single variable into the cds_items.  */
+static int
+ctf_dump_var (const char *name, ctf_id_t type, void *arg)
+{
+  char *str;
+  char *typestr;
+  ctf_dump_state_t *state = arg;
+
+  if (asprintf (&str, "%s -> ", name) < 0)
+    return (ctf_set_errno (state->cds_fp, ENOMEM));
+
+  if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
+    {
+      free (str);
+      return CTF_ERR;			/* errno is set for us.  */
+    }
+
+  str = ctf_str_append (str, typestr);
+  free (typestr);
+
+  ctf_dump_append (state, str);
+  return 0;
+}
+
+/* Dump a single member into the string in the membstate.  */
+static int
+ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
+		  int depth, void *arg)
+{
+  ctf_dump_membstate_t *state = arg;
+  char *typestr = NULL;
+  char *bit = NULL;
+  ctf_encoding_t ep;
+  ssize_t i;
+
+  for (i = 0; i < depth; i++)
+    *state->cdm_str = ctf_str_append (*state->cdm_str, "    ");
+
+  if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
+    goto oom;
+
+  if (asprintf (&bit, "    [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
+		offset, id, ctf_type_kind (state->cdm_fp, id), typestr, name,
+		ctf_type_align (state->cdm_fp, id)) < 0)
+    goto oom;
+  *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
+  free (typestr);
+  free (bit);
+  typestr = NULL;
+  bit = NULL;
+
+  if ((ctf_type_kind (state->cdm_fp, id) == CTF_K_INTEGER)
+      || (ctf_type_kind (state->cdm_fp, id) == CTF_K_FLOAT)
+      || (ctf_is_slice (state->cdm_fp, id, &ep) == CTF_K_ENUM))
+    {
+      ctf_type_encoding (state->cdm_fp, id, &ep);
+      if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
+		    ep.cte_offset, ep.cte_bits) < 0)
+	goto oom;
+      *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
+      free (bit);
+      bit = NULL;
+    }
+
+  *state->cdm_str = ctf_str_append (*state->cdm_str, ")\n");
+  return 0;
+
+ oom:
+  free (typestr);
+  free (bit);
+  return (ctf_set_errno (state->cdm_fp, ENOMEM));
+}
+
+/* Dump a single type into the cds_items.  */
+
+static int
+ctf_dump_type (ctf_id_t id, void *arg)
+{
+  char *str;
+  ctf_dump_state_t *state = arg;
+  ctf_dump_membstate_t membstate = { &str, state->cds_fp };
+  size_t len;
+
+  if ((str = ctf_dump_format_type (state->cds_fp, id)) == NULL)
+    goto err;
+
+  str = ctf_str_append (str, "\n");
+  if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
+    goto err;
+
+  /* Trim off the last linefeed added by ctf_dump_member().  */
+  len = strlen (str);
+  if (str[len-1] == '\n')
+    str[len-1] = '\0';
+
+  ctf_dump_append (state, str);
+  return 0;
+
+ err:
+  free (str);
+  return CTF_ERR;			/* errno is set for us.  */
+}
+
+/* Dump the string table into the cds_items.  */
+
+static int
+ctf_dump_str (ctf_file_t *fp, ctf_dump_state_t *state)
+{
+  const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
+
+  for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
+	 fp->ctf_str[CTF_STRTAB_0].cts_len;)
+    {
+      char *str;
+      if (asprintf (&str, "%lx: %s", s - fp->ctf_str[CTF_STRTAB_0].cts_strs,
+		    s) < 0)
+	return (ctf_set_errno (fp, ENOMEM));
+      ctf_dump_append (state, str);
+      s += strlen (s) + 1;
+    }
+
+  return 0;
+}
+
+/* Dump a particular section of a CTF file, in textual form.  Call with a
+   pointer to a NULL STATE: each call emits a dynamically allocated string
+   containing a description of one entity in the specified section, in order.
+   Only the first call (with a NULL state) may vary SECT.  Once the CTF section
+   has been entirely dumped, the call returns NULL and frees and annuls the
+   STATE, ready for another section to be dumped.  The returned textual content
+   may span multiple lines: between each call the FUNC is called with one
+   textual line at a time, and should return a suitably decorated line (it can
+   allocate a new one and return it if it likes).  */
+
+char *
+ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
+	  ctf_dump_decorate_f *func, void *arg)
+{
+  char *str;
+  char *line;
+  ctf_dump_state_t *state = NULL;
+
+  if (*statep == NULL)
+    {
+      /* Data collection.  Transforming a call-at-a-time iterator into a
+	 return-at-a-time iterator in a language without call/cc is annoying. It
+	 is easiest to simply collect everything at once and then return it bit
+	 by bit.  The first call will take (much) longer than otherwise, but the
+	 amortized time needed is the same.  */
+
+      if ((*statep = ctf_alloc (sizeof (struct ctf_dump_state))) == NULL)
+	{
+	  ctf_set_errno (fp, ENOMEM);
+	  goto end;
+	}
+      state = *statep;
+
+      memset (state, 0, sizeof (struct ctf_dump_state));
+      state->cds_fp = fp;
+      state->cds_sect = sect;
+
+      switch (sect)
+	{
+	case CTF_SECT_HEADER:
+	  /* Nothing doable (yet): entire header is discarded after read-phase.  */
+	  str = strdup ("");
+	  break;
+	case CTF_SECT_LABEL:
+	  if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
+	    {
+	      if (ctf_errno (fp) != ECTF_NOLABELDATA)
+		goto end;		/* errno is set for us.  */
+	      ctf_set_errno (fp, 0);
+	    }
+	  break;
+	case CTF_SECT_OBJT:
+	  if (ctf_dump_objts (fp, state) < 0)
+	    goto end;			/* errno is set for us.  */
+	  break;
+	case CTF_SECT_FUNC:
+	  if (ctf_dump_funcs (fp, state) < 0)
+	    goto end;			/* errno is set for us.  */
+	  break;
+	case CTF_SECT_VAR:
+	  if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
+	    goto end;			/* errno is set for us.  */
+	  break;
+	case CTF_SECT_TYPE:
+	  if (ctf_type_iter (fp, ctf_dump_type, state) < 0)
+	    goto end;			/* errno is set for us.  */
+	  break;
+	case CTF_SECT_STR:
+	  ctf_dump_str (fp, state);
+	  break;
+	default:
+	  ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
+	  goto end;
+	}
+    }
+  else
+    {
+      state = *statep;
+
+      if (state->cds_sect != sect)
+	{
+	  ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
+	  goto end;
+	}
+    }
+
+  if (state->cds_current == NULL)
+    state->cds_current = ctf_list_next (&state->cds_items);
+  else
+    state->cds_current = ctf_list_next (state->cds_current);
+
+  if (state->cds_current == NULL)
+    goto end;
+
+  /* Hookery.  There is some extra complexity to preserve linefeeds within each
+     item while removing linefeeds at the end.  */
+  if (func)
+    {
+      size_t len;
+
+      str = NULL;
+      for (line = state->cds_current->cdi_item; line && *line; )
+	{
+	  char *nline = line;
+	  char *ret;
+
+	  nline = strchr (line, '\n');
+	  if (nline)
+	    nline[0] = '\0';
+
+	  ret = func (sect, line, arg);
+	  str = ctf_str_append (str, ret);
+	  str = ctf_str_append (str, "\n");
+	  if (ret != line)
+	    free (ret);
+
+	  if (nline)
+	    {
+	      nline[0] = '\n';
+	      nline++;
+	    }
+
+	  line = nline;
+	}
+
+      len = strlen (str);
+
+      if (str[len-1] == '\n')
+	str[len-1] = '\0';
+    }
+  else
+    str = strdup (state->cds_current->cdi_item);
+
+  ctf_set_errno (fp, 0);
+  return str;
+
+ end:
+  ctf_dump_free (state);
+  ctf_free (state, sizeof (struct ctf_dump_state));
+  ctf_set_errno (fp, 0);
+  *statep = NULL;
+  return NULL;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 16/19] libctf: labels
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (17 preceding siblings ...)
  2019-05-01  0:13 ` [PATCH 17/19] libctf: debug dumping Nick Alcock
@ 2019-05-01  0:19 ` Nick Alcock
  2019-05-01  1:57 ` [PATCH 07/19] libctf: implementation definitions related to file creation Nick Alcock
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-01  0:19 UTC (permalink / raw)
  To: binutils

This facility allows you to associate regions of type IDs with *labels*,
a labelled tiling of the type ID space. You can use these to define
CTF containers with distinct parents for distinct ranges of the ID
space, or to assist with parallelization of CTF processing, or for any
other purpose you can think of.

Notably absent from here (though declared in the API header) is any way
to define new labels: this will probably be introduced soon, as part of
the linker deduplication work.  (One existed in the past, but was deeply
tied to the Solaris CTF file generator and had to be torn out.)

I would be happy to drop this entire commit for now as half-baked, but
it's an ancient interface and so to some degree shows what the original
designers of CTF thought you could do with it.

libctf/
	* ctf-labels.c: New.
include/
	* ctf-api.h (ctf_label_f): New.
	(ctf_label_set): New.
	(ctf_label_get): New.
	(ctf_label_topmost): New.
	(ctf_label_info): New.
	(ctf_label_iter): New.
---
 include/ctf-api.h   |   9 +++
 libctf/ctf-labels.c | 138 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)
 create mode 100644 libctf/ctf-labels.c

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 8687fa9004..7cf3f9a3de 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -208,6 +208,8 @@ typedef int ctf_member_f (const char *name, ctf_id_t membtype,
 typedef int ctf_enum_f (const char *name, int val, void *arg);
 typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg);
 typedef int ctf_type_f (ctf_id_t type, void *arg);
+typedef int ctf_label_f (const char *name, const ctf_lblinfo_t *info,
+			 void *arg);
 typedef int ctf_archive_member_f (ctf_file_t *fp, const char *name, void *arg);
 typedef int ctf_archive_raw_member_f (const char *name, const void *content,
 				      size_t len, void *arg);
@@ -273,9 +275,16 @@ extern int ctf_array_info (ctf_file_t *, ctf_id_t, ctf_arinfo_t *);
 extern const char *ctf_enum_name (ctf_file_t *, ctf_id_t, int);
 extern int ctf_enum_value (ctf_file_t *, ctf_id_t, const char *, int *);
 
+extern void ctf_label_set (ctf_file_t *, const char *);
+extern const char *ctf_label_get (ctf_file_t *);
+
+extern const char *ctf_label_topmost (ctf_file_t *);
+extern int ctf_label_info (ctf_file_t *, const char *, ctf_lblinfo_t *);
+
 extern int ctf_member_iter (ctf_file_t *, ctf_id_t, ctf_member_f *, void *);
 extern int ctf_enum_iter (ctf_file_t *, ctf_id_t, ctf_enum_f *, void *);
 extern int ctf_type_iter (ctf_file_t *, ctf_type_f *, void *);
+extern int ctf_label_iter (ctf_file_t *, ctf_label_f *, void *);
 extern int ctf_variable_iter (ctf_file_t *, ctf_variable_f *, void *);
 extern int ctf_archive_iter (const ctf_archive_t *, ctf_archive_member_f *,
 			     void *);
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
new file mode 100644
index 0000000000..c76207c966
--- /dev/null
+++ b/libctf/ctf-labels.c
@@ -0,0 +1,138 @@
+/* Labelled ranges of type IDs.
+   Copyright (C) 2002-2018 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+static int
+extract_label_info (ctf_file_t *fp, const ctf_lblent_t **ctl,
+		    uint32_t *num_labels)
+{
+  const ctf_header_t *h;
+
+  h = (const ctf_header_t *) fp->ctf_data.cts_data;
+
+  *ctl = (const ctf_lblent_t *) (fp->ctf_buf + h->cth_lbloff);
+  *num_labels = (h->cth_objtoff - h->cth_lbloff) / sizeof (ctf_lblent_t);
+
+  return 0;
+}
+
+/* Returns the topmost label, or NULL if any errors are encountered.  */
+
+const char *
+ctf_label_topmost (ctf_file_t *fp)
+{
+  const ctf_lblent_t *ctlp = NULL;
+  const char *s;
+  uint32_t num_labels = 0;
+
+  if (extract_label_info (fp, &ctlp, &num_labels) == CTF_ERR)
+    return NULL;				/* errno is set for us.  */
+
+  if (num_labels == 0)
+    {
+      (void) ctf_set_errno (fp, ECTF_NOLABELDATA);
+      return NULL;
+    }
+
+  if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL)
+    (void) ctf_set_errno (fp, ECTF_CORRUPT);
+
+  return s;
+}
+
+/* Iterate over all labels.  We pass the label string and the lblinfo_t struct
+   to the specified callback function.  */
+int
+ctf_label_iter (ctf_file_t *fp, ctf_label_f *func, void *arg)
+{
+  const ctf_lblent_t *ctlp = NULL;
+  uint32_t i;
+  uint32_t num_labels = 0;
+  ctf_lblinfo_t linfo;
+  const char *lname;
+  int rc;
+
+  if (extract_label_info (fp, &ctlp, &num_labels) == CTF_ERR)
+    return CTF_ERR;		/* errno is set for us.  */
+
+  if (num_labels == 0)
+    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+
+  for (i = 0; i < num_labels; i++, ctlp++)
+    {
+      if ((lname = ctf_strraw (fp, ctlp->ctl_label)) == NULL)
+	{
+	  ctf_dprintf ("failed to decode label %u with "
+		       "type %u\n", ctlp->ctl_label, ctlp->ctl_type);
+	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	}
+
+      linfo.ctb_type = ctlp->ctl_type;
+      if ((rc = func (lname, &linfo, arg)) != 0)
+	return rc;
+    }
+
+  return 0;
+}
+
+typedef struct linfo_cb_arg
+{
+  const char *lca_name;		/* Label we want to retrieve info for.  */
+  ctf_lblinfo_t *lca_info;	/* Where to store the info about the label.  */
+} linfo_cb_arg_t;
+
+static int
+label_info_cb (const char *lname, const ctf_lblinfo_t *linfo, void *arg)
+{
+  /* If lname matches the label we are looking for, copy the
+    lblinfo_t struct for the caller.  */
+
+  if (strcmp (lname, ((linfo_cb_arg_t *) arg)->lca_name) == 0)
+    {
+      /* * Allow caller not to allocate storage to test if label exists.  */
+
+      if (((linfo_cb_arg_t *) arg)->lca_info != NULL)
+	memcpy (((linfo_cb_arg_t *) arg)->lca_info, linfo,
+	       sizeof (ctf_lblinfo_t));
+      return 1;		/* Indicate we found a match.  */
+    }
+
+  return 0;
+}
+
+/* Retrieve information about the label with name "lname". */
+int
+ctf_label_info (ctf_file_t *fp, const char *lname, ctf_lblinfo_t *linfo)
+{
+  linfo_cb_arg_t cb_arg;
+  int rc;
+
+  cb_arg.lca_name = lname;
+  cb_arg.lca_info = linfo;
+
+  if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) == CTF_ERR)
+    return rc;
+
+  if (rc != 1)
+    return (ctf_set_errno (fp, ECTF_NOLABEL));
+
+  return 0;
+}
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH 07/19] libctf: implementation definitions related to file creation
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (18 preceding siblings ...)
  2019-05-01  0:19 ` [PATCH 16/19] libctf: labels Nick Alcock
@ 2019-05-01  1:57 ` Nick Alcock
  2019-05-01 16:02 ` [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Clifton
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-01  1:57 UTC (permalink / raw)
  To: binutils

We now enter a series of commits that are sufficiently tangled that
avoiding forward definitions is almost impossible: no attempt is made to
make individual commits compilable (which is why the build system does
not reference any of them yet): the only important thing is that they
should form something like conceptual groups.

But first, some definitions, including the core ctf_file_t itself.  Uses
of these definitions will be introduced in later commits.

libctf/
	* ctf-impl.h: New definitions and declarations for type creation
	and lookup.
---
 libctf/ctf-impl.h | 217 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 217 insertions(+)

diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 32f4bfeaef..0d33cdb01e 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -64,12 +64,210 @@ extern "C"
 typedef struct ctf_fixed_hash ctf_hash_t; /* Private to ctf-hash.c.  */
 typedef struct ctf_dynhash ctf_dynhash_t; /* Private to ctf-hash.c.  */
 
+typedef struct ctf_strs
+{
+  const char *cts_strs;		/* Base address of string table.  */
+  size_t cts_len;		/* Size of string table in bytes.  */
+} ctf_strs_t;
+
+typedef struct ctf_dmodel
+{
+  const char *ctd_name;		/* Data model name.  */
+  int ctd_code;			/* Data model code.  */
+  size_t ctd_pointer;		/* Size of void * in bytes.  */
+  size_t ctd_char;		/* Size of char in bytes.  */
+  size_t ctd_short;		/* Size of short in bytes.  */
+  size_t ctd_int;		/* Size of int in bytes.  */
+  size_t ctd_long;		/* Size of long in bytes.  */
+} ctf_dmodel_t;
+
+typedef struct ctf_lookup
+{
+  const char *ctl_prefix;	/* String prefix for this lookup.  */
+  size_t ctl_len;		/* Length of prefix string in bytes.  */
+  ctf_hash_t *ctl_hash;		/* Pointer to hash table for lookup.  */
+} ctf_lookup_t;
+
+typedef struct ctf_fileops
+{
+  uint32_t (*ctfo_get_kind) (uint32_t);
+  uint32_t (*ctfo_get_root) (uint32_t);
+  uint32_t (*ctfo_get_vlen) (uint32_t);
+  ssize_t (*ctfo_get_ctt_size) (const ctf_file_t *, const ctf_type_t *,
+				ssize_t *, ssize_t *);
+  ssize_t (*ctfo_get_vbytes) (unsigned short, ssize_t, size_t);
+} ctf_fileops_t;
+
 typedef struct ctf_list
 {
   struct ctf_list *l_prev;	/* Previous pointer or tail pointer.  */
   struct ctf_list *l_next;	/* Next pointer or head pointer.  */
 } ctf_list_t;
 
+typedef enum
+  {
+   CTF_PREC_BASE,
+   CTF_PREC_POINTER,
+   CTF_PREC_ARRAY,
+   CTF_PREC_FUNCTION,
+   CTF_PREC_MAX
+  } ctf_decl_prec_t;
+
+typedef struct ctf_decl_node
+{
+  ctf_list_t cd_list;		/* Linked list pointers.  */
+  ctf_id_t cd_type;		/* Type identifier.  */
+  uint32_t cd_kind;		/* Type kind.  */
+  uint32_t cd_n;		/* Type dimension if array.  */
+} ctf_decl_node_t;
+
+typedef struct ctf_decl
+{
+  ctf_list_t cd_nodes[CTF_PREC_MAX]; /* Declaration node stacks.  */
+  int cd_order[CTF_PREC_MAX];	     /* Storage order of decls.  */
+  ctf_decl_prec_t cd_qualp;	     /* Qualifier precision.  */
+  ctf_decl_prec_t cd_ordp;	     /* Ordered precision.  */
+  char *cd_buf;			     /* Buffer for output.  */
+  int cd_err;			     /* Saved error value.  */
+  int cd_enomem;		     /* Nonzero if OOM during printing.  */
+} ctf_decl_t;
+
+typedef struct ctf_dmdef
+{
+  ctf_list_t dmd_list;		/* List forward/back pointers.  */
+  char *dmd_name;		/* Name of this member.  */
+  ctf_id_t dmd_type;		/* Type of this member (for sou).  */
+  unsigned long dmd_offset;	/* Offset of this member in bits (for sou).  */
+  int dmd_value;		/* Value of this member (for enum).  */
+} ctf_dmdef_t;
+
+typedef struct ctf_dtdef
+{
+  ctf_list_t dtd_list;		/* List forward/back pointers.  */
+  char *dtd_name;		/* Name associated with definition (if any).  */
+  ctf_id_t dtd_type;		/* Type identifier for this definition.  */
+  ctf_type_t dtd_data;		/* Type node (see <ctf.h>).  */
+  union
+  {
+    ctf_list_t dtu_members;	/* struct, union, or enum */
+    ctf_arinfo_t dtu_arr;	/* array */
+    ctf_encoding_t dtu_enc;	/* integer or float */
+    ctf_id_t *dtu_argv;		/* function */
+    ctf_slice_t dtu_slice;	/* slice */
+  } dtd_u;
+} ctf_dtdef_t;
+
+typedef struct ctf_dvdef
+{
+  ctf_list_t dvd_list;		/* List forward/back pointers.  */
+  char *dvd_name;		/* Name associated with variable.  */
+  ctf_id_t dvd_type;		/* Type of variable.  */
+  unsigned long dvd_snapshots;	/* Snapshot count when inserted.  */
+} ctf_dvdef_t;
+
+typedef struct ctf_bundle
+{
+  ctf_file_t *ctb_file;		/* CTF container handle.  */
+  ctf_id_t ctb_type;		/* CTF type identifier.  */
+  ctf_dtdef_t *ctb_dtd;		/* CTF dynamic type definition (if any).  */
+} ctf_bundle_t;
+
+/* The ctf_file is the structure used to represent a CTF container to library
+   clients, who see it only as an opaque pointer.  Modifications can therefore
+   be made freely to this structure without regard to client versioning.  The
+   ctf_file_t typedef appears in <ctf-api.h> and declares a forward tag.
+
+   NOTE: ctf_update() requires that everything inside of ctf_file either be an
+   immediate value, a pointer to dynamically allocated data *outside* of the
+   ctf_file itself, or a pointer to statically allocated data.  If you add a
+   pointer to ctf_file that points to something within the ctf_file itself,
+   you must make corresponding changes to ctf_update().  */
+
+struct ctf_file
+{
+  const ctf_fileops_t *ctf_fileops; /* Version-specific file operations.  */
+  ctf_sect_t ctf_data;		    /* CTF data from object file.  */
+  ctf_sect_t ctf_symtab;	    /* Symbol table from object file.  */
+  ctf_sect_t ctf_strtab;	    /* String table from object file.  */
+  ctf_hash_t *ctf_structs;	    /* Hash table of struct types.  */
+  ctf_hash_t *ctf_unions;	    /* Hash table of union types.  */
+  ctf_hash_t *ctf_enums;	    /* Hash table of enum types.  */
+  ctf_hash_t *ctf_names;	    /* Hash table of remaining type names.  */
+  ctf_lookup_t ctf_lookups[5];	    /* Pointers to hashes for name lookup.  */
+  ctf_strs_t ctf_str[2];	    /* Array of string table base and bounds.  */
+  const unsigned char *ctf_base;  /* Base of CTF header + uncompressed buffer.  */
+  const unsigned char *ctf_buf;	  /* Uncompressed CTF data buffer.  */
+  size_t ctf_size;		  /* Size of CTF header + uncompressed data.  */
+  uint32_t *ctf_sxlate;		  /* Translation table for symtab entries.  */
+  unsigned long ctf_nsyms;	  /* Number of entries in symtab xlate table.  */
+  uint32_t *ctf_txlate;		  /* Translation table for type IDs.  */
+  uint32_t *ctf_ptrtab;		  /* Translation table for pointer-to lookups.  */
+  struct ctf_varent *ctf_vars;	  /* Sorted variable->type mapping.  */
+  unsigned long ctf_nvars;	  /* Number of variables in ctf_vars.  */
+  unsigned long ctf_typemax;	  /* Maximum valid type ID number.  */
+  const ctf_dmodel_t *ctf_dmodel; /* Data model pointer (see above).  */
+  struct ctf_file *ctf_parent;	  /* Parent CTF container (if any).  */
+  const char *ctf_parlabel;	  /* Label in parent container (if any).  */
+  const char *ctf_parname;	  /* Basename of parent (if any).  */
+  char *ctf_dynparname;		  /* Dynamically allocated name of parent.  */
+  uint32_t ctf_parmax;		  /* Highest type ID of a parent type.  */
+  uint32_t ctf_refcnt;		  /* Reference count (for parent links).  */
+  uint32_t ctf_flags;		  /* Libctf flags (see below).  */
+  int ctf_errno;		  /* Error code for most recent error.  */
+  int ctf_version;		  /* CTF data version.  */
+  ctf_dynhash_t *ctf_dthash;	  /* Hash of dynamic type definitions.  */
+  ctf_dynhash_t *ctf_dtbyname;	  /* DTDs, indexed by name.  */
+  ctf_list_t ctf_dtdefs;	  /* List of dynamic type definitions.  */
+  ctf_dynhash_t *ctf_dvhash;	  /* Hash of dynamic variable mappings.  */
+  ctf_list_t ctf_dvdefs;	  /* List of dynamic variable definitions.  */
+  size_t ctf_dtvstrlen;		  /* Total length of dynamic type+var strings.  */
+  unsigned long ctf_dtnextid;	  /* Next dynamic type id to assign.  */
+  unsigned long ctf_dtoldid;	  /* Oldest id that has been committed.  */
+  unsigned long ctf_snapshots;	  /* ctf_snapshot() plus ctf_update() count.  */
+  unsigned long ctf_snapshot_lu;  /* ctf_snapshot() call count at last update.  */
+  char *ctf_tmp_typeslice;	  /* Storage for slicing up type names.  */
+  size_t ctf_tmp_typeslicelen;	  /* Size of the typeslice.  */
+  void *ctf_specific;		  /* Data for ctf_get/setspecific().  */
+};
+
+/* Return x rounded up to an alignment boundary.
+   eg, P2ROUNDUP(0x1234, 0x100) == 0x1300 (0x13*align)
+   eg, P2ROUNDUP(0x5600, 0x100) == 0x5600 (0x56*align)  */
+#define P2ROUNDUP(x, align)		(-(-(x) & -(align)))
+
+/* * If an offs is not aligned already then round it up and align it. */
+#define LCTF_ALIGN_OFFS(offs, align) ((offs + (align - 1)) & ~(align - 1))
+
+#define LCTF_TYPE_ISPARENT(fp, id) ((id) <= fp->ctf_parmax)
+#define LCTF_TYPE_ISCHILD(fp, id) ((id) > fp->ctf_parmax)
+#define LCTF_TYPE_TO_INDEX(fp, id) ((id) & (fp->ctf_parmax))
+#define LCTF_INDEX_TO_TYPE(fp, id, child) (child ? ((id) | (fp->ctf_parmax+1)) : \
+					   (id))
+
+#define LCTF_INDEX_TO_TYPEPTR(fp, i) \
+  ((ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)]))
+
+#define LCTF_INFO_KIND(fp, info)	((fp)->ctf_fileops->ctfo_get_kind(info))
+#define LCTF_INFO_ISROOT(fp, info)	((fp)->ctf_fileops->ctfo_get_root(info))
+#define LCTF_INFO_VLEN(fp, info)	((fp)->ctf_fileops->ctfo_get_vlen(info))
+#define LCTF_VBYTES(fp, kind, size, vlen) \
+  ((fp)->ctf_fileops->ctfo_get_vbytes(kind, size, vlen))
+
+static inline ssize_t ctf_get_ctt_size (const ctf_file_t *fp,
+					const ctf_type_t *tp,
+					ssize_t *sizep,
+					ssize_t *incrementp)
+{
+  return (fp->ctf_fileops->ctfo_get_ctt_size (fp, tp, sizep, incrementp));
+}
+
+#define LCTF_MMAP	0x0001	/* libctf should munmap buffers on close.  */
+#define LCTF_CHILD	0x0002	/* CTF container is a child */
+#define LCTF_RDWR	0x0004	/* CTF container is writable */
+#define LCTF_DIRTY	0x0008	/* CTF container has been modified */
+
+extern const ctf_type_t *ctf_lookup_by_id (ctf_file_t **, ctf_id_t);
+
 typedef unsigned int (*ctf_hash_fun) (const void *ptr);
 extern unsigned int ctf_hash_integer (const void *ptr);
 extern unsigned int ctf_hash_string (const void *ptr);
@@ -101,6 +299,15 @@ extern void ctf_list_append (ctf_list_t *, void *);
 extern void ctf_list_prepend (ctf_list_t *, void *);
 extern void ctf_list_delete (ctf_list_t *, void *);
 
+extern void ctf_dtd_insert (ctf_file_t *, ctf_dtdef_t *);
+extern void ctf_dtd_delete (ctf_file_t *, ctf_dtdef_t *);
+extern ctf_dtdef_t *ctf_dtd_lookup (const ctf_file_t *, ctf_id_t);
+extern ctf_dtdef_t *ctf_dynamic_type (const ctf_file_t *, ctf_id_t);
+
+extern void ctf_dvd_insert (ctf_file_t *, ctf_dvdef_t *);
+extern void ctf_dvd_delete (ctf_file_t *, ctf_dvdef_t *);
+extern ctf_dvdef_t *ctf_dvd_lookup (const ctf_file_t *, const char *);
+
 extern const char *ctf_strraw (ctf_file_t *, uint32_t);
 extern const char *ctf_strptr (ctf_file_t *, uint32_t);
 
@@ -118,11 +325,21 @@ extern char *ctf_strdup (const char *);
 extern char *ctf_str_append (char *, const char *);
 extern const char *ctf_strerror (int);
 
+extern ctf_id_t ctf_type_resolve_unsliced (ctf_file_t *, ctf_id_t);
+extern int ctf_type_kind_unsliced (ctf_file_t *, ctf_id_t);
+
 _libctf_printflike_ (1, 2)
 extern void ctf_dprintf (const char *, ...);
 
 extern Elf64_Sym *ctf_sym_to_gelf (const Elf32_Sym *src, Elf64_Sym *dst);
+extern const char *ctf_lookup_symbol_name (ctf_file_t *fp, unsigned long symidx);
+
+/* Variables, all underscore-prepended. */
+
+extern const char _CTF_SECTION[];	/* name of CTF ELF section */
+extern const char _CTF_NULLSTR[];	/* empty string */
 
+extern int _libctf_version;	/* library client version */
 extern int _libctf_debug;	/* debugging messages enabled */
 
 #ifdef	__cplusplus
-- 
2.21.0.237.gd0cfaa883d

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (19 preceding siblings ...)
  2019-05-01  1:57 ` [PATCH 07/19] libctf: implementation definitions related to file creation Nick Alcock
@ 2019-05-01 16:02 ` Nick Clifton
  2019-05-01 16:16   ` Jose E. Marchesi
  2019-05-02 15:22 ` Joseph Myers
  2019-05-03 16:19 ` Florian Weimer
  22 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-01 16:02 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

  One quick question before I start to dive into this particular patch series:
  Is there a reason why you are using GPLv2 and not GPLv3 for your files ?

  The binutils project as a whole uses GPLv3, so I would be concerned about
  accepting a large number of GPLv2 source files.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-01 16:02 ` [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Clifton
@ 2019-05-01 16:16   ` Jose E. Marchesi
  2019-05-03 10:47     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Jose E. Marchesi @ 2019-05-01 16:16 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Nick Alcock, binutils


Hi Nick.

      One quick question before I start to dive into this particular patch series:
      Is there a reason why you are using GPLv2 and not GPLv3 for your files ?
    
      The binutils project as a whole uses GPLv3, so I would be concerned about
      accepting a large number of GPLv2 source files.

Doh!  We actually wanted to submit as GPLv3+, not GPLv2+.  There is no
reason to include v2, at all :)

We will change the notifications to "version 3, or any later version" in
subsequent versions of the patch serie.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 01/19] include: new header ctf.h: file format description
  2019-04-30 22:57 ` [PATCH 01/19] include: new header ctf.h: file format description Nick Alcock
@ 2019-05-01 16:57   ` Nick Clifton
  2019-05-01 21:29     ` Jim Wilson
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-01 16:57 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick.

 Some random thoughts as I read through this patch...

> +/* CTF format description.
> +   Copyright (C) 2004-2019 Free Software Foundation, Inc.

Copyright starting from 2004, really ?


> +/* CTF - Compact ANSI-C Type Format

ANSI-C ?  Isn't everyone using ISO-C these days ?

Also - does this format explicitly exclude other languages like C++ or Go or Rust ?


> +   operating system kernel in a form that is significantly more compact than
> +   the equivalent stabs or DWARF representation. 

Out of curiosity, do you have any data on how much better CTF is than say, DWARF ?




> +   CTF assumes that a standard ELF symbol table is
> +   available for use in the debugger,

In my experience many executables are stripped of their symbol tables.  (The
symbol tables are stored in the separate debug information file associated
with the executable, but often these are not installed by the users.  Plus if
they are installed, then what benefit would CTF provide ?)  

So will CTF work if the symbol table is missing ?


> +   header itself.  If the CTF data has been uniquified against another set of

Is "uniquified" really a word ? :-)

> +#define CTF_VERSION_3 4
> +#define CTF_VERSION CTF_VERSION_3 /* Current version.  */

Hang on - so the value of CTF_VERSION_3 is 4 ?  Does this mean that the
full version number is 3.4, or 4.0 or just 4 ?  I am a bit confused...

 
OK, I am going to stop here as my brain is starting to hurt.  I will resume
looking at the patches tomorrow.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 01/19] include: new header ctf.h: file format description
  2019-05-01 16:57   ` Nick Clifton
@ 2019-05-01 21:29     ` Jim Wilson
  2019-05-03 11:15       ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Jim Wilson @ 2019-05-01 21:29 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Nick Alcock, Binutils

On Wed, May 1, 2019 at 9:57 AM Nick Clifton <nickc@redhat.com> wrote:
> > +/* CTF format description.
> > +   Copyright (C) 2004-2019 Free Software Foundation, Inc.
>
> Copyright starting from 2004, really ?

Looks like CTF is part of dtrace which Oracle inherited from Sun.
Wikipedia tells me that the first release of dtrace was in Jan 2005,
so a 2004 copyright looks right if this is the original sources from
Sun subsequently modified by Oracle.

> > +/* CTF - Compact ANSI-C Type Format
> ANSI-C ?  Isn't everyone using ISO-C these days ?

I was going to say the same thing.

> Also - does this format explicitly exclude other languages like C++ or Go or Rust ?

Apparently doesn't explicitly exclude them, it just doesn't explicitly
include them, and with only 64 possible type classes, it looks like
you could run out without some clever encoding for other languages.

> > +#define CTF_VERSION_3 4
> > +#define CTF_VERSION CTF_VERSION_3 /* Current version.  */
>
> Hang on - so the value of CTF_VERSION_3 is 4 ?  Does this mean that the
> full version number is 3.4, or 4.0 or just 4 ?  I am a bit confused...

Looks like there was a version 1+ which took number 2.
https://github.com/oracle/libdtrace-ctf/blob/master/include/sys/ctf.h#L149

I don't have any expertise with CTF, I was just curious, so did a
little looking around for more info and found the version number
encoding.  I also found a FreeBSD man page which has some useful intro
data.
https://www.freebsd.org/cgi/man.cgi?query=ctf&sektion=5&manpath=freebsd-release-ports

Jim

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 02/19] include: new header ctf-api.h
  2019-04-30 22:57 ` [PATCH 02/19] include: new header ctf-api.h Nick Alcock
@ 2019-05-02 15:07   ` Nick Clifton
  2019-05-03 11:23     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-02 15:07 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

> This non-installed header is the means by which libctf consumers
> communicate with libctf.

By "non-installed" do you mean that it would not be placed into /usr/include ?
If so, then how do consumers know how to communicate with libctf, given that
they might be compiled without access to the ctf sources ?


> +/* Clients can open one or more CTF containers and obtain a pointer to an
> +   opaque ctf_file_t.  Types are identified by an opaque ctf_id_t token.
> +   They can also open or create read-only archives of CTF containers in a
> +   ctf_archive_t.

Are CTF archives just arbitrary collections of CTF containers or is there more
to them than that ?

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (20 preceding siblings ...)
  2019-05-01 16:02 ` [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Clifton
@ 2019-05-02 15:22 ` Joseph Myers
  2019-05-03 12:33   ` Nick Clifton
  2019-05-03 14:23   ` Nick Alcock
  2019-05-03 16:19 ` Florian Weimer
  22 siblings, 2 replies; 52+ messages in thread
From: Joseph Myers @ 2019-05-02 15:22 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

This patch series introduces a dependency of binutils on libctf.

This means libctf should be portable to the same range of hosts as 
binutils, all of which can be used as hosts for cross toolchains for a 
range of targets (ELF and non-ELF).  For example, it should be portable to 
hosts such as MinGW or OS X.

Some apparent portability issues in this code include:

* Use of dlfcn.h.  Such use in existing binutils code (e.g. bfd/plugin.c) 
is conditional, to avoid trying to use it on hosts without that 
functionality.

* Use of sys/mman.h.  Again, mmap usage in existing code is appropriately 
conditional.

* Use of sys/errno.h.  The standard name is errno.h.

* Use of elf.h.  Non-ELF hosts won't have such a header.  You should be 
working with the existing include/elf/*.h definitions of ELF data 
structures in binutils.

* Use of gelf.h.  This seems to be something from some versions of libelf, 
which isn't an existing build dependency of binutils at all (and given the 
existence of multiple, incompatible versions of libelf, one should be wary 
of depending on it).  The only gelf.h I have locally here is in a checkout 
of prelink sources.  Again, use existing ELF structures in headers present 
in binutils.

* Use of byteswap.h and endian.h.  Such headers are not portably 
available.  Note how byteswap.h usage in gold / elfcpp is appropriately 
conditional.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers
  2019-04-30 22:57 ` [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers Nick Alcock
@ 2019-05-02 15:29   ` Nick Clifton
  2019-05-03 19:12     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-02 15:29 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

> I could easily be convinced that all of these wrappers serve no purpose
> and should be globally removed, but the debugging tracer is frequently
> useful, and the malloc/free/mmap/munmap wrappers have proved mildly
> useful in conjunction with symbol interposition for allocation debugging
> in the (relatively distant) past.

I see no problem with retaining these wrappers.  They are not going to inflict
a large overhead on the library, and if they have proved helpful in debugging
then they have proved their worth.  Besides having functions like these allows
them to be intercepted by third parties, if for some reason that becomes
necessary.

> (I am amenable to replacing the environment-variable triggering of
> ctf_dprintf() with something else in the binutils commit,

I am not a fan of using environment variables, although in this particular
case it is not so bad.  There is of course the problem of documentation -
you must tell the users about the variable - and also the fact that users
of the library might wish to enable/disable debugging themselves.  Perhaps
the library could provide a function to set the value of _libctf_debug even
after _libctf_init() has been called ?

> +/* Miscellary.
> +   Copyright (C) 2003-2019 Free Software Foundation, Inc.
> +

Ooo - just noticed - this header, and others too, do not mention who
contributed the code.  It would be nice to see your efforts acknowledged
don't you think ?


> +void *
> +ctf_data_alloc (size_t size)
> +{
> +  return (mmap (NULL, size, PROT_READ | PROT_WRITE,
> +		MAP_PRIVATE | MAP_ANON, -1, 0));
> +}

I am not a memory allocation expert - but is it efficient to
call mmap for every memory allocation ?  Or do higher levels
of libctf manage the allocated memory so that this function is
only used when needed to grab large chunks of memory ?


> +void
> +ctf_data_free (void *buf, size_t size)
> +{
> +  (void) munmap (buf, size);
> +}

Why do you ignore and discard the return value from munmap() ?
If there is an error, surely you would want to examine it or
return it to the caller ?


> +void
> +ctf_free (void *buf, size_t size _libctf_unused_)
> +{
> +  free (buf);
> +}

Why does your free function have a size parameter at all ?


> +_libctf_printflike_ (1, 2)
> +void ctf_dprintf (const char *format, ...)
> +{
> +  if (_libctf_debug)
> +    {
> +      va_list alist;
> +
> +      va_start (alist, format);
> +      (void) fputs ("libctf DEBUG: ", stderr);
> +      (void) vfprintf (stderr, format, alist);

I would recommend calling "fflush (stdout)" before starting to
print to stderr, just in order to make sure that the debug output
does not appear halfway through a line of ordinary output.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 04/19] libctf: low-level list manipulation and helper utilities
  2019-04-30 22:57 ` [PATCH 04/19] libctf: low-level list manipulation and helper utilities Nick Alcock
@ 2019-05-02 16:04   ` Nick Clifton
  2019-05-03 19:25     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-02 16:04 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

> The distinction betweern this file and ctf-subr.c is lost in the mists
> of time: perhaps it was originally that ctf-subr.c contained nothing but
> wrappers.  I am quite amenable to combining the two, and also to
> splitting the errno-setting stuff out into ctf-error.c with the error
> fetchers.

Meh - whatever you want.  The distribution of the code within the library
is really just up to you.


> +#include <gelf.h>

This header is from the elfutils project right ?  Given that, and the fact
that you are using the types from this header, why are you submitting this
code to the binutils project ?  (Or maybe you are submitting it to both
projects - I have not checked).

In particular the BFD library has its own ELF reading and writing functions 
and its own headers defining the layout of ELF structures.  Unfortunately 
these headers do tend to conflict with the headers from the elfutils project, 
whoch makes combining them problematical.


> +/* Simple doubly-linked list append routine.  This implementation assumes that
> +   each list element contains an embedded ctf_list_t as the first member.
> +   An additional ctf_list_t is used to store the head (l_next) and tail
> +   (l_prev) pointers.  The current head and tail list elements have their
> +   previous and next pointers set to NULL, respectively.  */

You knows this kind of code seems awfully familiar.  I am sure that I have seen
it implemented in lots of different places... :-)


> +void
> +ctf_list_prepend (ctf_list_t * lp, void *new)

I think that using "new" here might be a problem if you try to compile this
source file with a C++ compiler.


> +const char *
> +ctf_strraw (ctf_file_t *fp, uint32_t name)
> +{
> +  ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];

My inner paranoia is screaming at code like this.  Unless you
are certain that these functions cannot be called with out of 
range parameters then I would strongly urge checking them before
using them.

Cheers
  Nick


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 05/19] libctf: error handling
  2019-04-30 22:57 ` [PATCH 05/19] libctf: error handling Nick Alcock
@ 2019-05-02 16:10   ` Nick Clifton
  2019-05-03 19:31     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-02 16:10 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

> +static const char *const _ctf_errlist[] = {
> +  "File is not in CTF or ELF format",		     /* ECTF_FMT */

Have you considered allowing these strings to be translated ?

Cheers
  Nick


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 06/19] libctf: hashing
  2019-04-30 22:57 ` [PATCH 06/19] libctf: hashing Nick Alcock
@ 2019-05-02 16:16   ` Nick Clifton
  2019-05-03 19:33     ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-02 16:16 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

> In the binutils implementation, these are both fairly thin wrappers
> around libiberty hashtab.

I could not think of anything useful to say about this patch, so this
is just a comment to let you know that I have looked over it.  I think
that this may well be the case with other patches in this series, so
from now on I will only post replies to patches where I actually have
something to say.  I will send an "end of comments" email as well
though, so that you know that I have finished.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-01 16:16   ` Jose E. Marchesi
@ 2019-05-03 10:47     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 10:47 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Nick Clifton, binutils

On 1 May 2019, Jose E. Marchesi spake thusly:

>
> Hi Nick.
>
>       One quick question before I start to dive into this particular patch series:
>       Is there a reason why you are using GPLv2 and not GPLv3 for your files ?
>     
>       The binutils project as a whole uses GPLv3, so I would be concerned about
>       accepting a large number of GPLv2 source files.
>
> Doh!  We actually wanted to submit as GPLv3+, not GPLv2+.  There is no
> reason to include v2, at all :)
> 
> We will change the notifications to "version 3, or any later version" in
> subsequent versions of the patch serie.

Adjusted. This was just historical paranoia, really. (We'll be fine as
long as Linux kernel build-time code in scripts/ can still link with it
when it's GPLv3, and since the existing prototype is linking with
elfutils now and it's only a build tool and thus is not distributed in
linked form, we're probably fine -- or in trouble already. :) )

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 01/19] include: new header ctf.h: file format description
  2019-05-01 21:29     ` Jim Wilson
@ 2019-05-03 11:15       ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 11:15 UTC (permalink / raw)
  To: Jim Wilson; +Cc: Nick Clifton, Binutils

[Sorry about the response delay: two-day family thing.]

On 1 May 2019, Jim Wilson spake thusly:

> On Wed, May 1, 2019 at 9:57 AM Nick Clifton <nickc@redhat.com> wrote:
>> > +/* CTF format description.
>> > +   Copyright (C) 2004-2019 Free Software Foundation, Inc.
>>
>> Copyright starting from 2004, really ?
>
> Looks like CTF is part of dtrace which Oracle inherited from Sun.
> Wikipedia tells me that the first release of dtrace was in Jan 2005,
> so a 2004 copyright looks right if this is the original sources from
> Sun subsequently modified by Oracle.

Exactly.

>> > +/* CTF - Compact ANSI-C Type Format
>> ANSI-C ?  Isn't everyone using ISO-C these days ?
>
> I was going to say the same thing.

Historical naming wart. I'm happy to adjust it. (The original headers
were inconsistent here and sometimes said ANSI-C and sometimes just C
and sometimes just 'Compact' with no language at all! Only the last is
definitely wrong.)

>> Also - does this format explicitly exclude other languages like C++ or Go or Rust ?
>
> Apparently doesn't explicitly exclude them, it just doesn't explicitly
> include them, and with only 64 possible type classes, it looks like
> you could run out without some clever encoding for other languages.

I had some ideas half an hour ago which should allow substantially more
format flexibility without making the libctf codebase horrifically
unreadable (in fact it should increase the readability of the codebase
by dropping most of the casts in it): this would let us have not only an
even more compact version of the ctf_stype_t for common C cases, but
also a longer ctt_info word for non-C cases with, oh, is 2^32 type
classes enough, or should I go to 2^64? ;) there will obviously be a
slight cost in space, but not a large one.

At this point I am mostly worried about the complexity of speccing
things like C++ out. I'm fairly sure the format can expand to handle
them in future (without breaking existing users) but I'm not so sure my
brain can!

A bigger question where multi-language support is concerned is whether
we need to handle more than one language in a given hierarchy of CTF
sections: in effect, allowing for multi-language translation units.

This would mean we could deduplicate types together for different
languages, but I doubt this would be useful for many language pairs
(which would have largely distinct language-specific type kinds). It
would increase compactness a bit more to say "dammit, if you have two
languages in your project you should have two CTF section hierarchies",
and come up with names like .ctf.cpp and .ctf.rust or something for the
other languages.

If we might handle additional languages in a one-language-per-container,
we might want to reserve a word in the header to indicate language even
though we don't plan to add any other languages yet, just to make it
possible to add them in future without another backward-compatibility
break.

>> > +#define CTF_VERSION_3 4
>> > +#define CTF_VERSION CTF_VERSION_3 /* Current version.  */
>>
>> Hang on - so the value of CTF_VERSION_3 is 4 ?  Does this mean that the
>> full version number is 3.4, or 4.0 or just 4 ?  I am a bit confused...
>
> Looks like there was a version 1+ which took number 2.
> https://github.com/oracle/libdtrace-ctf/blob/master/include/sys/ctf.h#L149

The history is... complicated, and all my fault, I'm afraid.

When we took libctf into the DTrace for Linux project, it was already at
v2: v1 then was an ancient Sun-era thing which had literally nothing but
the version number surviving in the codebase, much like you see above. I
reset it to v1, but after a few years its limitations became fairly
extreme: it only allowed 2^16 types in one program, only 998 members in
any one structure or union, we were running out of type kinds, etc. So I
introduced a v3... but v3 boosted the set of types to 2^32, thus changed
the boundary between parent and child type IDs, since type-parenthood is
indicated by the most significant bit in the type ID.

We upgrade old formats to new ones in memory aggressively at open time
to avoid duplicating codepaths for old formats, so this change in
parent/child boundary would have required the backward-compatibility
code to *renumber all the types* at the same time. This seemed
excessive, given that CTF containers are read-only after creation, so an
upgraded container couldn't ever have enough types in it for that
renumbering to be necessary: but we needed to note the fact that the
parent/child boundary was lower in some persistent form, in case the
user opened an old container (upgrading it in the process), then wrote
it back out again: we had to preserve the knowledge that this had once
been a v1 container, with a v1 parent/child boundary, *somewhere*.

So as a backward-compatibility hack I decreed that v1 when upgraded to
v2 would gain the CTF_VERSION_1_UPGRADED_3 version number, which was
interpreted as 'just like v2, except the parent/child boundary is like
v1'. If I'd been starting from scratch, a family of feature flags or
something might have been neater... but this works and the maintenance
burden is minimal (one conditional to note the existeince of
CTF_VERSION_1_UPGRADED_3 and set the parent/child boundary
appropriately).

> I don't have any expertise with CTF, I was just curious, so did a
> little looking around for more info and found the version number
> encoding.  I also found a FreeBSD man page which has some useful intro
> data.
> https://www.freebsd.org/cgi/man.cgi?query=ctf&sektion=5&manpath=freebsd-release-ports

Yep, that's the old v1 format all right (Sun format v2). Too small for
some real projects, even in the presence of aggressive deduplication.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 02/19] include: new header ctf-api.h
  2019-05-02 15:07   ` Nick Clifton
@ 2019-05-03 11:23     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 11:23 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 2 May 2019, Nick Clifton verbalised:

> Hi Nick,
>
>> This non-installed header is the means by which libctf consumers
>> communicate with libctf.
>
> By "non-installed" do you mean that it would not be placed into /usr/include ?

Yes. Mostly because I assumed that the bar was higher for installed
headers than for non-installed ones, and there are no users of libctf
yet.

> If so, then how do consumers know how to communicate with libctf, given that
> they might be compiled without access to the ctf sources ?

At the moment, libctf is an automatically-synched copy of the upstream
libdtrace-ctf project. Our aim is to eventually make binutils the
upstream, whereupon we can drop libdtrace-ctf entirely, and turn this
into an installed header :)

(If we do make it an installed header, we want to set up things like
symbol versioning first. libdtrace-ctf already has all of that.)

>> +/* Clients can open one or more CTF containers and obtain a pointer to an
>> +   opaque ctf_file_t.  Types are identified by an opaque ctf_id_t token.
>> +   They can also open or create read-only archives of CTF containers in a
>> +   ctf_archive_t.
>
> Are CTF archives just arbitrary collections of CTF containers or is there more
> to them than that ?

They are usually arbitrary collections of *related* CTF containers (with
associated names): e.g. a parent container and a bunch of children that
reuse types from the parent.

The format is given in ctf-impl.h: it's just an mmappable archive which
isn't tar or cpio and so doesn't have to deal with the infinite horrors
of tar or cpio versioning. :) One feature it does have that tar and cpio
don't is that, like zip files, the compression happens at the level of
individual archive members, via the CTF_F_COMPRESS flag bit in the
header.

This means that you can elect to not compress CTF files that are already
"small enough" (say, smaller than a page), whereupon they can get read
via mmap() directly out of the CTF archive, with no copying or
decompression overhead. CTF files with parents are often very small:
looking at Linux kernel 5.0, of 2938 CTF files in the archive I
generated in my most recent test build, all but 188 are under 4096
bytes: but they all have as a parent the 1.2MiB shared CTF file that
contains types shared across kernel modules (in a non-kernel context,
the parent container will usually contain types shared across TUs).

(Nearly 2000 of them are under 512 bytes long. By this stage just the
gzip header is bloating the thing up substantially, and you gain nothing
from compression of things so small.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-02 15:22 ` Joseph Myers
@ 2019-05-03 12:33   ` Nick Clifton
  2019-05-06 16:40     ` Nick Alcock
  2019-05-08 14:34     ` Michael Matz
  2019-05-03 14:23   ` Nick Alcock
  1 sibling, 2 replies; 52+ messages in thread
From: Nick Clifton @ 2019-05-03 12:33 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Joseph Myers, binutils

Hi Nick,

  OK, so I am going to stop my review of this patch series until we have 
  some answers to a few high level questions/requirements.  Specifically:

  * Hosting

    Is the binutils project the right place for this code ?  As Joseph 
    has already mentioned libctf appears to use code from the elfutils 
    project, so maybe that would be a better home for libctf ?

  * Testing

    I did not see a testsuite for the library, nor any additions to
    the binutils testsuite for the extensions to objdump and readelf.
    I would not be comfortable adding such a large body of code to the
    project without some 

  * Documentation

    It would be really good to have the CTF format documented somewhere
    (semi) permanent and publicly accessible.  It would also be good if
    there was a libctf.texi document describing how consumers are expected
    to use the library, and, ideally, providing code examples.

  * Usefulness

    This may be a bit contentious - but is the CTF format actually being
    used anywhere, or likely to be used in the near future ?  If this is
    a project that is just going to be used by a small group, or even just
    a single company, then I am worried that the code will just bit rot 
    away and not be actively maintained.

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-02 15:22 ` Joseph Myers
  2019-05-03 12:33   ` Nick Clifton
@ 2019-05-03 14:23   ` Nick Alcock
       [not found]     ` <alpine.DEB.2.21.1905072117440.19308@digraph.polyomino.org.uk>
  2019-05-24  8:57     ` Pedro Alves
  1 sibling, 2 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 14:23 UTC (permalink / raw)
  To: Joseph Myers; +Cc: binutils

[looking at your comments first because you were so very helpful last
 time I contributed to glibc. :) ]

(And thank you! I haven't done quite everything you suggested, at least
not yet, but the 90% I have done is entirely beneficial and you spotted
a lot of things I overlooked.)

On 2 May 2019, Joseph Myers spake thusly:

> This patch series introduces a dependency of binutils on libctf.
>
> This means libctf should be portable to the same range of hosts as 
> binutils, all of which can be used as hosts for cross toolchains for a 
> range of targets (ELF and non-ELF).  For example, it should be portable to 
> hosts such as MinGW or OS X.

Seems sensible. It might lose some functionality, though, at least to
start with. (Say, sharing string tables with the overarching container,
opening CTF files by handing them an fd to a containing binary, etc.
There are alternatives callers can use in all these cases.)

I'll probably arrange for the deduplicating linker plugin to be
ELF-only, at least to start with, because I have no way to test on
anything else, and it might always keep strings and symbols internal to
the CTF file rather than trying to share them with the enclosing binary,
until someone else contributes that sort of thing for non-ELF.

> Some apparent portability issues in this code include:
>
> * Use of dlfcn.h.  Such use in existing binutils code (e.g. bfd/plugin.c) 
> is conditional, to avoid trying to use it on hosts without that 
> functionality.

This was used by ancient code in the OpenSolaris days that endeavoured
to dlopen() zlib to avoid linking against it (why one would want to
avoid linking against zlib is opaque to me). No user these days:
dropped.

> * Use of sys/mman.h.  Again, mmap usage in existing code is appropriately 
> conditional.

We can fall back to copying or malloc in that situation, in most cases.

However, the CTF archive code would be made significantly more
complicated, more than cancelling out the implementation simplicity
which was one reason for using mmap() there in the first place. So for
now my no-mmap() CTF archive code just fails: callers can detect the
failure and fall back to storing CTF containers separately in that case.
(Both reading and writing fail symmetrically, so you aren't going to end
up creating containers you then can't read.)

If there are really still platforms relevant outside industrial museums
without mmap(), we can rethink this, but I bet there aren't, or that any
such platforms aren't going to be storing huge numbers of CTF containers
in any case. (The use case for this is if you have so many TUs that you
can't store one per section without risking blowing the 64K section
limit. Any machine new enough to be dealing with anything in that size
range is going to have mmap() as well, right? Or something we can use
instead of it with similar semantics...)


Note that it's only *creating* CTF archives without mmap() that is too
horrible to countenance. It is relatively easy to support reading CTF
archives on non-mmap-supporting systems, if quite inefficiently, so we
could arrange to fall back to read-and-copy in that case, allowing
people in cross environments to not need to worry about whether their
target supports mmap() before creating CTF archives. This might be a
reasonable middle ground, perhaps?


(Added fallbacks for mmap() in all cases but CTF archives: as noted
above, we can add fallbacks for archive usage, too, just not creation.)

(oh btw you missed a bit: we use pread() too, and badly, ignoring the
possibility of short reads or -EINTR returns. Fixing, and adding a
fallback for that as well.)

> * Use of sys/errno.h.  The standard name is errno.h.

Ancient historical wart: fixed, thank you! How did I miss that?!

> * Use of elf.h.  Non-ELF hosts won't have such a header.  You should be 
> working with the existing include/elf/*.h definitions of ELF data 
> structures in binutils.

This is all for build hosts that aren't ELF, right? I don't think we can
reasonably expect ctf_open() or ctf_fdopen() to work for anything but
raw CTF files on non-ELF hosts, given that by their very nature these
functions are getting CTF data out of ELF sections, and non-ELF formats
don't necessarily support anything like the named section concept ELF
has got at all.

The only other ELF-specificity is looking up types by symbol table
offset. Again, I don't know enough about non-ELF platforms to know if
this concept is even practical there, which would mean the data object
and function info sections would be empty on such hosts, and
ctf_lookup_by_symbol(), ctf_func_info() and ctf_func_args() would not
function or would be excluded from the set of exported symbols entirely.

This would reduce libctf's utility, but not eliminate it: external
systems can still look up types by name or CTF type ID even if they
can't do it by symbol.

It is possible that such things could be revived: all we'd need for a
given non-ELF platform would be a way to consistently split whatever
they use as a symbol table into an ordered list of data and function
objects that could be referenced by those CTF sections. However, for
now, this functionality is intrinsically ELF-only in the sense that
nobody has ever considered how it might work on non-ELF platforms and it
certainly has no users there.

However, for now we can do a little better than this: see below.

> * Use of gelf.h.  This seems to be something from some versions of libelf, 
> which isn't an existing build dependency of binutils at all (and given the 
> existence of multiple, incompatible versions of libelf, one should be wary 
> of depending on it).  The only gelf.h I have locally here is in a checkout 
> of prelink sources.  Again, use existing ELF structures in headers present 
> in binutils.

This is a historical thing: libelf was of course part of Solaris so its
usage was pervasive, even when unnecessary, as here. What we're actually
using is a few datatypes, nothing more: the Elf64_Sym, from <elf.h> (on
Linux, provided by glibc), the Elf*_GHdr and Elf*_SHdr, and the
primitive ELF-sized datatypes like Elf64_Word that those structures use.

I don't see any immediate replacement for most of this stuff in
binutils, even though I'd expect to find it: the Elf64_External_Sym's
members are entirely the wrong type (char arrays), and there doesn't
seem to be any common non-architecture-dependent structure with more
useful types at all!

Elf64_Internal_Sym is very bfd-specific (and I'm trying not to have
libctf depend on libbfd unnecessarily, since it needs little of its
functionality), and the code in readelf that mocks up an internal_sym
from file data spends almost all its time getting around the problem
that its datatypes are different from the (standard-guaranteed) data
types in the ELF file itself. This is more futzing about than seems sane
given that we're not using the rest of bfd at all.

So I'd rather find a way to do the simple 'get a bit of very simple data
out of an ELF file we have an fd to (symbol lookups and a couple of
section lookups)' without needing to rejig everything to use bfd just to
do that, particularly given that libctf's APIs that involve the caller
passing info corresponding to a section into libctf do not require the
caller to use bfd and I have not the least idea how to go from
data+size-and-no-fd to a bfd_asection (it's probably not possible).


I could just copy the (fairly small number of) relevant types from
glibc's installed elf.h header into the ctf internals (the license is
compatible, after all, as is the copyright ownership), using a different
(CTF-internal) name to avoid clashes causing trouble at build time.
Would that be acceptable?

This lets us operate unchanged on non-ELF hosts and when not targetting
ELF, and leave this code in and even functional in that situation: it
detects ELF files by their magic number, which will presumably never
match things passed in to ctf_open() on non-ELF targets, and nothing
would ever generate contents for the function info or data object
sections on such non-ELF targets either (until we figured out how to do
so), so the ELF-specific code involved in reading those sections is also
not a problem.

Adding more magic numbers for more executable types is possible: if we
started handling COFF or PE or Mach-O or something like that, we would
probably soon hit a stage where it would become useful to start using
some bfd abstractions, but I think the time is not yet. (I don't know
enough about these formats to know if they even *have* named sections.)

> * Use of byteswap.h and endian.h.  Such headers are not portably 
> available.  Note how byteswap.h usage in gold / elfcpp is appropriately 
> conditional.

Makes sense. I can easily arrange to use code like elfcpp does in that
case.

... (done.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
                   ` (21 preceding siblings ...)
  2019-05-02 15:22 ` Joseph Myers
@ 2019-05-03 16:19 ` Florian Weimer
  2019-05-03 19:45   ` Nick Alcock
  22 siblings, 1 reply; 52+ messages in thread
From: Florian Weimer @ 2019-05-03 16:19 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

* Nick Alcock:

>   - a very compact association between the ELF symbol table and CTF.
>     No symbol table indexes are recorded: all are implied: the
>     data-object section is as compact as possible, containing nothing
>     but a stream of type IDs describing the type of data symbols in
>     symbol table order.

Is this for GNU/Linux?

On GNU/Linux, DWARF unwinding information (in the form of
PT_GNU_EH_FRAME) is not optional, it is required by the ABI (although
many people pretend it's not, resulting in crashes or worse).

I'm worried that we have to add both in the future, DWARF data and CTF
data, which would be rather bad.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers
  2019-05-02 15:29   ` Nick Clifton
@ 2019-05-03 19:12     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 19:12 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 2 May 2019, Nick Clifton spake thusly:

> Hi Nick,
>> (I am amenable to replacing the environment-variable triggering of
>> ctf_dprintf() with something else in the binutils commit,
>
> I am not a fan of using environment variables, although in this particular
> case it is not so bad.  There is of course the problem of documentation -
> you must tell the users about the variable - and also the fact that users
> of the library might wish to enable/disable debugging themselves.  Perhaps
> the library could provide a function to set the value of _libctf_debug even
> after _libctf_init() has been called ?

That seems like an excellent idea and I have no idea why it didn't
already exist. That way the callers can look up the env var and then we
don't need to bother with the ELF constructor, and one more
compatibility headache for non-ELF platforms is gone. :)

... added ctf_setdebug() and ctf_getdebug(). (For compatibility with
existing callers, we set the default value from the environment variable
at the obvious open/create entry points, if ctf_setdebug() has not
already been called.)

>> +/* Miscellary.
>> +   Copyright (C) 2003-2019 Free Software Foundation, Inc.
>> +
>
> Ooo - just noticed - this header, and others too, do not mention who
> contributed the code.  It would be nice to see your efforts acknowledged
> don't you think ?

I was asked not to, and I thought it was current policy not to put that
sort of thing in (IIRC that is current policy in GCC, but I could be
wrong since this in old and crusty merely human memory). I'm quite happy
to put it in otherwise :)

>> +void *
>> +ctf_data_alloc (size_t size)
>> +{
>> +  return (mmap (NULL, size, PROT_READ | PROT_WRITE,
>> +		MAP_PRIVATE | MAP_ANON, -1, 0));
>> +}
>
> I am not a memory allocation expert - but is it efficient to
> call mmap for every memory allocation ?  Or do higher levels
> of libctf manage the allocated memory so that this function is
> only used when needed to grab large chunks of memory ?

This is only used for a few large allocations of the entire CTF buffer
at once: during compression and decompression, when endian-flipping, and
during transparent upgrading (which you can't see yet because I
unifdeffed it away, but it will return in v2 of the patch series).

The only reason for this is that it lets us mprotect() it afterward
using ctf_data_protect(), since after creation CTF files are always
read-only so all modifications are certain to be wild pointers. Whether
this particular piece of paranoia is justified, I'm not entirely sure:
it might be worth it only for larger CTF sections. (In that case, we
could easily arrange for ctf_data_alloc()/free() to mmap() only when the
size is much larger than one page, and malloc()/free() otherwise, and
for ctf_data_protect() to do nothing unless called for things above that
threshold.)

That should give us roughly the same degree of paranoia (since wild
pointers strike roughly at random, they'll probaly hit bigger CTF files
with more area to hit much more than smaller ones) while avoiding
wasting memory on smaller CTF files.

(Implemented that for v2, with an arbitrary limit set to one page. If
you think something else is better, let me know!)

>> +void
>> +ctf_data_free (void *buf, size_t size)
>> +{
>> +  (void) munmap (buf, size);
>> +}
>
> Why do you ignore and discard the return value from munmap() ?
> If there is an error, surely you would want to examine it or
> return it to the caller ?

Mostly because I couldn't think of anything to do if there is an error.
It's about as hard to deal with as an error from free().  If there is an
error there has been a disaster and I can't figure out any useful
recovery method, but this is a library so we surely shouldn't crash
either. I could certainly emit a ctf_dprintf() or output on stderr (but
that's unfriendly for a library, too).

I suppose we could return it to callers, most of which will also ignore
it because there is nothing they can do... :)

>> +void
>> +ctf_free (void *buf, size_t size _libctf_unused_)
>> +{
>> +  free (buf);
>> +}
>
> Why does your free function have a size parameter at all ?

I think there was an old debugging tool that needed the size at freeing
time. But the size *is* annoying to keep track of as far as the free and
adds pointless complexity for literally no benefit: if you don't want it
either, that's it, it has passed my threshold of annoyance and it's
gone.

I've also marked ctf_free(), ctf_data_alloc(), ctf_mmap() and
ctf_strdup() as __attribute__((__malloc__)): all four allocate new
storage which cannot contain pointers to any existing storage, so they
are eligible and marking them makes them better proxies for malloc().

>> +_libctf_printflike_ (1, 2)
>> +void ctf_dprintf (const char *format, ...)
>> +{
>> +  if (_libctf_debug)
>> +    {
>> +      va_list alist;
>> +
>> +      va_start (alist, format);
>> +      (void) fputs ("libctf DEBUG: ", stderr);
>> +      (void) vfprintf (stderr, format, alist);
>
> I would recommend calling "fflush (stdout)" before starting to
> print to stderr, just in order to make sure that the debug output
> does not appear halfway through a line of ordinary output.

... why on earth didn't I think of that?! I've been seeing that failure
now and then for ages. Thank you!!!

Fixed.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 04/19] libctf: low-level list manipulation and helper utilities
  2019-05-02 16:04   ` Nick Clifton
@ 2019-05-03 19:25     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 19:25 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 2 May 2019, Nick Clifton said:

> Hi Nick,
>
>> +#include <gelf.h>
>
> This header is from the elfutils project right ?  Given that, and the fact
> that you are using the types from this header, why are you submitting this
> code to the binutils project ?  (Or maybe you are submitting it to both
> projects - I have not checked).
>
> In particular the BFD library has its own ELF reading and writing functions 
> and its own headers defining the layout of ELF structures.  Unfortunately 
> these headers do tend to conflict with the headers from the elfutils project, 
> whoch makes combining them problematical.

See my response to Joseph. This is basically because Solaris has
<gelf.h> easily available and used it promiscuously: we are only using a
few types that are always necessarily typedefs of types from <elf.h>,
but of course that's glibc-specific so I suppose we can't rely on that
either. But the binutils types seem... very far from ideal for my
purposes here, terribly bfd-specific.

Hence my suggestion (in an email that I hadn't written when you sent
this) that I could simply copy the necessary types from the installed
glibc headers into libctf. I don't know if that's too ugly to live.

>> +/* Simple doubly-linked list append routine.  This implementation assumes that
>> +   each list element contains an embedded ctf_list_t as the first member.
>> +   An additional ctf_list_t is used to store the head (l_next) and tail
>> +   (l_prev) pointers.  The current head and tail list elements have their
>> +   previous and next pointers set to NULL, respectively.  */
>
> You knows this kind of code seems awfully familiar.  I am sure that I have seen
> it implemented in lots of different places... :-)

Yes, but what else can we use? I tried using the stuff in <sys/queue.h>
and my eyes melted from all the CAPITAL LETTERS. :)

>> +void
>> +ctf_list_prepend (ctf_list_t * lp, void *new)
>
> I think that using "new" here might be a problem if you try to compile this
> source file with a C++ compiler.

True! I was only thinking in terms of using the headers with a C++
compiler... adjusted. However, there are a lot of other things we need
to fix up before libctf is C++-ready: implicit conversions to/from void
* are most of the problems, but we also use the %zi printf format in
several places...

>> +const char *
>> +ctf_strraw (ctf_file_t *fp, uint32_t name)
>> +{
>> +  ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];
>
> My inner paranoia is screaming at code like this.  Unless you
> are certain that these functions cannot be called with out of 
> range parameters then I would strongly urge checking them before
> using them.

Possibly a nicer fix than explicitly checking is to change CTF_NAME_STID
a bit to mask, from:

#define CTF_NAME_STID(name)		((name) >> 31)

to

#define CTF_NAME_STID(name)		(((name) >> 31) & 1)

That should mask out all but the bottom bit, ensuring that even if
someone manages to pass a 64-bit value with 30 1-bits to CTF_NAME_STID
(... which cannot happen in ctf_strraw() as presently constituted, but a
later change might break that assmuption), the result of CTF_NAME_STID()
is always either 0 or 1.  Thus it will always fit into ctf_str and never
overwrite anything.

... or is this just piling too-cleverness on top of too-cleverness?

(I've done that, provisionally, for v2.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 05/19] libctf: error handling
  2019-05-02 16:10   ` Nick Clifton
@ 2019-05-03 19:31     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 19:31 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 2 May 2019, Nick Clifton uttered the following:

> Hi Nick,
>
>> +static const char *const _ctf_errlist[] = {
>> +  "File is not in CTF or ELF format",		     /* ECTF_FMT */
>
> Have you considered allowing these strings to be translated ?

Sure! But gettextization is a bigger job I haven't even looked at yet.
(e.g. do we need to gettextize all the debugging strings, too?)

I suppose we'd translate the error messages in particular via explicit
gettext() calls in ctf_errmsg()? (Of course, ctf_errmsg() can also
return a strerror() value, but I suppose libc will take care of
translating that for us.)

(But if you call gettext() explicitly, presumably you have to mark the
translatable strings in the array with something too, or they won't land
in the po files? I have no idea, and haven't read the gettext manual in
far too many years... I'd have to do some research first.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 06/19] libctf: hashing
  2019-05-02 16:16   ` Nick Clifton
@ 2019-05-03 19:33     ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 19:33 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 2 May 2019, Nick Clifton uttered the following:

> Hi Nick,
>
>> In the binutils implementation, these are both fairly thin wrappers
>> around libiberty hashtab.
>
> I could not think of anything useful to say about this patch, so this
> is just a comment to let you know that I have looked over it.  I think

Thank you for this! Excellent reviews: I'm responding only slowly
because of the volume of changes your comments have generated. :)

 15 files changed, 345 insertions(+), 85 deletions(-)

so far... I can only hope that, one day many years from now, I can
review code I've never seen before as well as this.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-03 16:19 ` Florian Weimer
@ 2019-05-03 19:45   ` Nick Alcock
  2019-05-06 12:07     ` Florian Weimer
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-05-03 19:45 UTC (permalink / raw)
  To: Florian Weimer; +Cc: binutils

On 3 May 2019, Florian Weimer verbalised:

> * Nick Alcock:
>
>>   - a very compact association between the ELF symbol table and CTF.
>>     No symbol table indexes are recorded: all are implied: the
>>     data-object section is as compact as possible, containing nothing
>>     but a stream of type IDs describing the type of data symbols in
>>     symbol table order.
>
> Is this for GNU/Linux?
>
> On GNU/Linux, DWARF unwinding information (in the form of
> PT_GNU_EH_FRAME) is not optional, it is required by the ABI (although
> many people pretend it's not, resulting in crashes or worse).
> 
> I'm worried that we have to add both in the future, DWARF data and CTF
> data, which would be rather bad.

I'm fairly sure they are quite distinct. CTF doesn't even try to record
unwinding information, or anything like it, but rather lets you
introspect into datatypes (not into the call stack, not into function
arguments, but into C types). Even the backtrace section, if and when we
add it, isn't going to do what DWARF unwinding info does: its purpose is
more to let debuggers find function arguments' values and types on the
call stack in a form much smaller than DW_TAG_call_site. Wherever
possible, if we find we need something the unwinding info is providing,
we'll point into that instead, to save space.

The one overriding rule of CTF is 'never duplicate anything you can find
elsewhere'. We already use strings from the ELF string table whenever
possible: if we ever come to need unwinding info, we'll definitely use
the DWARF unwinding info, because it is not stripped from binaries, so
its presence can be relied upon.

(Also, CTF is meant to be very small, small enough to ignore and to
leave even in stripped binaries except in very constrained environments.
I'm almost certain that it'll be *much* smaller than the DWARF unwinding
information. It certainly is in all cases I've examined so far. But
you're wise to reserve judgement on this until we have GCC and linker
support in place so you can see it for yourself.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-03 19:45   ` Nick Alcock
@ 2019-05-06 12:07     ` Florian Weimer
  0 siblings, 0 replies; 52+ messages in thread
From: Florian Weimer @ 2019-05-06 12:07 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

* Nick Alcock:

> On 3 May 2019, Florian Weimer verbalised:
>
>> * Nick Alcock:
>>
>>>   - a very compact association between the ELF symbol table and CTF.
>>>     No symbol table indexes are recorded: all are implied: the
>>>     data-object section is as compact as possible, containing nothing
>>>     but a stream of type IDs describing the type of data symbols in
>>>     symbol table order.
>>
>> Is this for GNU/Linux?
>>
>> On GNU/Linux, DWARF unwinding information (in the form of
>> PT_GNU_EH_FRAME) is not optional, it is required by the ABI (although
>> many people pretend it's not, resulting in crashes or worse).
>> 
>> I'm worried that we have to add both in the future, DWARF data and CTF
>> data, which would be rather bad.
>
> I'm fairly sure they are quite distinct. CTF doesn't even try to record
> unwinding information, or anything like it, but rather lets you
> introspect into datatypes (not into the call stack, not into function
> arguments, but into C types).

I don't know what happened on Friday.  I must have had a bad day.  (I
did have trouble backporting something that should have been a
straightforward fix, too.)  I suppose I somehow mixed up CTF and CFI
in my mind.  Sorry about that.

You are of course right, CTF isn't related to unwinding.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-03 12:33   ` Nick Clifton
@ 2019-05-06 16:40     ` Nick Alcock
  2019-05-08 14:34     ` Michael Matz
  1 sibling, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-06 16:40 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Joseph Myers, binutils

On 3 May 2019, Nick Clifton verbalised:

> Hi Nick,
>
>   OK, so I am going to stop my review of this patch series until we have 
>   some answers to a few high level questions/requirements.  Specifically:
>
>   * Hosting
>
>     Is the binutils project the right place for this code ?  As Joseph 
>     has already mentioned libctf appears to use code from the elfutils 
>     project, so maybe that would be a better home for libctf ?

It uses no code from elfutils: It uses one datatype from elfutils, and
shouldn't really even use that (it should use the stuff from <elf.h>
from glibc). (Thanks for spotting that! It'll be fixed this week.)

>   * Testing
>
>     I did not see a testsuite for the library, nor any additions to
>     the binutils testsuite for the extensions to objdump and readelf.
>     I would not be comfortable adding such a large body of code to the
>     project without some 

Agreed!!! Writing a testsuite is high on our priority list, but we need
compiler and linker support first. There will definitely be a testsuite
in place, probably in large part autogenerated. (The code is not at all
untested: the testing largely consists of generating CTF for the entire
Linux kernel and then letting the fairly sizeable DTrace testsuite run
over it. However, this is obviously not suitable for upstreaming into
binutils: something more systematic is needed, and will exist.)

>   * Documentation
>
>     It would be really good to have the CTF format documented somewhere
>     (semi) permanent and publicly accessible.  It would also be good if
>     there was a libctf.texi document describing how consumers are expected
>     to use the library, and, ideally, providing code examples.

Agreed!

>   * Usefulness
>
>     This may be a bit contentious - but is the CTF format actually being
>     used anywhere, or likely to be used in the near future ?  If this is
>     a project that is just going to be used by a small group, or even just
>     a single company, then I am worried that the code will just bit rot 
>     away and not be actively maintained.

It would be useful for many projects, but it was not easy to adopt it,
and it has been relatively unknown outside of Solaris and FreeBSD
circles.

We have been using it for many years with the Linux kernel and DTrace.
Other projects may adopt it. It is *useful* for many other projects, but
it was quite difficult to generate CTF-format data (from DWARF using a
variety of painful-to-port Solaris tools). I know I wanted it in the
past for various other profilers I was writing, but I didn't use it
because I had no idea it existed. It seems likely to be *useful* for
debuggers and tracers and introspectors of all sorts: anything that
wants to know what type an ELF object is, or what type function
arguments or return types are, and who wants to be able to decompose
that type into its constitutent pieces and chase pointers from it and
make sense of the results seems likely to be able to make use of CTF.

In particular, GDB, perf, and sysprof could definitely make use of it,
as could systemtap, rr, and honestly I'm only limited here by not
knowing the names of more obscure debugger projects. Right now these
either cannot do useful things with datatypes at all, or require all the
DWARF debuginfo to be present to do anything, and given that many of
these things are systemwide continuous debuggers, the debuginfo is
almost never present when the debugger points at a victim program and
tries to print out argument info or whatever.

I'm fairly confident that having type information for C programs as
widely and easily available as it is, for, say, Lisp programs (with a
cost, often, of only a few kilobytes) is a generally good thing. We're
making a start by adding CTF support to GCC, GNU ld and GDB.


Size-wise it really is pretty small. Let's try a few samples (with a
notably unscientific construction method). The first five numeric
columns are a count of types, and CTF sizes in bytes (the sizes of
specific sections: all uncompressed sizes but the first 'size' number.
"DWARF size" is the size of .debug_info.)

                       CTF
Program          types size (uncompressed)  stringsize  typesize   DWARF size
coreutils ls     396   10324 (26216)        13148       13068      74241
GAS 2.30         1123  55748 (172731)       106079      66652      1001453
emacs 26.1.50    3546  104276 (284479)      142231      142248     3912261
X.org 1.20.3     7266  152196 (473797)      201421      272376     4163434
GhostScript 9.26 7873  181036 (538901)      243293      295608     7943132
Gtk 3.24.7       9236  208612 (620926)      328174      292752     6106925

So a shrinkage over DWARF of roughly 80%, and usually less than 5% of
the size of the binary whose types are described. With planned format
and generation improvements, I expect that a 90% shrinkage over DWARF is
probably achievable without too much effort. (More than that might
require pruning out individual unused bits, a fairly radical change.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
       [not found]     ` <alpine.DEB.2.21.1905072117440.19308@digraph.polyomino.org.uk>
@ 2019-05-08 11:39       ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-08 11:39 UTC (permalink / raw)
  To: Joseph Myers; +Cc: binutils

On 7 May 2019, Joseph Myers said:

> On Fri, 3 May 2019, Nick Alcock wrote:
>
>> > This means libctf should be portable to the same range of hosts as 
>> > binutils, all of which can be used as hosts for cross toolchains for a 
>> > range of targets (ELF and non-ELF).  For example, it should be portable to 
>> > hosts such as MinGW or OS X.
>> 
>> Seems sensible. It might lose some functionality, though, at least to
>> start with. (Say, sharing string tables with the overarching container,
>> opening CTF files by handing them an fd to a containing binary, etc.
>> There are alternatives callers can use in all these cases.)
>
> I don't think that functionality should depend on the host, though it 
> might depend on the target.

I agree with all of that. We don't want cross-tools to generate
different output to non-cross tools, etc.

I guess that means I might *have* to figure out how to do the (very
limited) ELFish things currently being done with libelf with bfd
instead. (And I just noticed that bfd does in fact have useful texinfo,
so I can read that and most of my bfd fear should go away. I have no
*idea* why I thought it had no texinfo docs. Probably some out of date
fifteen year old memory fooling me or something.)

... ok with docs BFDizing this should be much less terrifying than I
thought.

I was also a bit worried about circular dependencies, but I don't think
there are any: we'll have {ld, binutils, gdb} -> libctf -> bfd, which is
fine, but no link from bfd back to libctf.

>> I'll probably arrange for the deduplicating linker plugin to be
>> ELF-only, at least to start with, because I have no way to test on
>
> A plugin is about the only thing I'd expect to depend on the host (in that 
> you'd need different build system logic to build a non-ELF shared object).  

Yes, except that if the host is horribly limited I'm starting to not
care about it. If mingw *does* have writable memory mappings, I'm
happy...

>> If there are really still platforms relevant outside industrial museums
>> without mmap(), we can rethink this, but I bet there aren't, or that any
>> such platforms aren't going to be storing huge numbers of CTF containers
>> in any case. (The use case for this is if you have so many TUs that you
>> can't store one per section without risking blowing the 64K section
>> limit. Any machine new enough to be dealing with anything in that size
>> range is going to have mmap() as well, right? Or something we can use
>> instead of it with similar semantics...)
>
> MinGW has similar APIs such as MapViewOfFile.  It's not mmap.

... and that's near enough I think. It looks like you can at least use
it to create files via ordinary memory I/O, just like mmap(): it has
weird restrictions but they're no harder to deal with than the
page-granularity restrictions that go with mmap() anyway. So I don't
need to rewrite all the archive code to use file I/O instead :)

>> reasonably expect ctf_open() or ctf_fdopen() to work for anything but
>> raw CTF files on non-ELF hosts, given that by their very nature these
>> functions are getting CTF data out of ELF sections, and non-ELF formats
>> don't necessarily support anything like the named section concept ELF
>> has got at all.
>
> I don't see why such functions should depend on whether the host is ELF at 
> all.  On the target, yes, but not on the host.

Oh true. I've constantly mixed up host and target for as long as I've
been using GNU tools, and I fear that after 25 years of getting it wrong
I'm not going to start getting it right any time soon. (I don't know
why. It's not as if the names are unclear.)

I did, of course, mean 'target' there, which does mean BFDizing to drop
the elfutils dependency.

I'll look at that soon. (Most of the other issues you raised I have
already fixed locally, and the fixes will be in the next patch rev.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-03 12:33   ` Nick Clifton
  2019-05-06 16:40     ` Nick Alcock
@ 2019-05-08 14:34     ` Michael Matz
  2019-05-08 16:01       ` Nick Clifton
  1 sibling, 1 reply; 52+ messages in thread
From: Michael Matz @ 2019-05-08 14:34 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Nick Alcock, Joseph Myers, binutils

Hello Nick,

On Fri, 3 May 2019, Nick Clifton wrote:

>   * Usefulness
> 
>     This may be a bit contentious - but is the CTF format actually being
>     used anywhere, or likely to be used in the near future ?  If this is
>     a project that is just going to be used by a small group, or even just
>     a single company, then I am worried that the code will just bit rot 
>     away and not be actively maintained.

FWIW, I'd be looking forward to have CTF in our distro binaries shipped by 
default, it might obviate the need for separate -debuginfo packages, you'd 
get somewhat useful analysis capabilities even without them then.

So, I'm very happy about someone investing into getting CTF onto linux; I 
considered doing that myself on and off, just never could bring myself 
to start ;-)


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-08 14:34     ` Michael Matz
@ 2019-05-08 16:01       ` Nick Clifton
  2019-05-08 16:20         ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Clifton @ 2019-05-08 16:01 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Michael Matz, Joseph Myers, binutils

Hi Nick,

  Well it looks like people do want this new feature in the binutils,
  so please go ahead and submit a v2 patch set for review.  (At your
  leisure - I am in no hurry...).

  By the way, I assume that you or somebody else will be volunteering
  to become an official maintainer for libctf, once it is in the binutils
  sources ?

Cheers
  Nick

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-08 16:01       ` Nick Clifton
@ 2019-05-08 16:20         ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-08 16:20 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Michael Matz, Joseph Myers, binutils

On 8 May 2019, Nick Clifton spake thusly:

> Hi Nick,
>
>   Well it looks like people do want this new feature in the binutils,

It is not mature to jump up and down and go 'wahoo' so obviously I
didn't just do that.

>   so please go ahead and submit a v2 patch set for review.  (At your
>   leisure - I am in no hurry...).

I have some improvements to do first so you're not reviewing stuff I'm
just going to change out from under you: format changes/improvements to
finalize, etc, but I am working on nothing else and once that is done it
will be posted, don't fear. (With every review comment so far resolved,
too, I hope. That's already done bar the ELF and ctf-archive mmap
stuff...)

>   By the way, I assume that you or somebody else will be volunteering
>   to become an official maintainer for libctf, once it is in the binutils
>   sources ?

Absolutely.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-03 14:23   ` Nick Alcock
       [not found]     ` <alpine.DEB.2.21.1905072117440.19308@digraph.polyomino.org.uk>
@ 2019-05-24  8:57     ` Pedro Alves
  2019-05-24 16:05       ` Nick Alcock
  1 sibling, 1 reply; 52+ messages in thread
From: Pedro Alves @ 2019-05-24  8:57 UTC (permalink / raw)
  To: Nick Alcock, Joseph Myers; +Cc: binutils

On 5/3/19 3:23 PM, Nick Alcock wrote:
> 
>> * Use of elf.h.  Non-ELF hosts won't have such a header.  You should be 
>> working with the existing include/elf/*.h definitions of ELF data 
>> structures in binutils.
> This is all for build hosts that aren't ELF, right? I don't think we can
> reasonably expect ctf_open() or ctf_fdopen() to work for anything but
> raw CTF files on non-ELF hosts, given that by their very nature these
> functions are getting CTF data out of ELF sections, and non-ELF formats
> don't necessarily support anything like the named section concept ELF
> has got at all.
> 
> The only other ELF-specificity is looking up types by symbol table
> offset. Again, I don't know enough about non-ELF platforms to know if
> this concept is even practical there, which would mean the data object
> and function info sections would be empty on such hosts, and
> ctf_lookup_by_symbol(), ctf_func_info() and ctf_func_args() would not
> function or would be excluded from the set of exported symbols entirely.
> 
> This would reduce libctf's utility, but not eliminate it: external
> systems can still look up types by name or CTF type ID even if they
> can't do it by symbol.

Even if you only want to support CTF on ELF containers, a cross
binutils build hosted on e.g., Windows, targeting an ELF port, should
still be able to use the CTF.  That's why it is important to not rely
on host headers for ELF definitions.  It wasn't clear to me from
your remarks above whether the cross use case is considered?

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-24  8:57     ` Pedro Alves
@ 2019-05-24 16:05       ` Nick Alcock
  2019-05-24 16:19         ` Pedro Alves
  0 siblings, 1 reply; 52+ messages in thread
From: Nick Alcock @ 2019-05-24 16:05 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Joseph Myers, binutils

On 24 May 2019, Pedro Alves spake thusly:

> On 5/3/19 3:23 PM, Nick Alcock wrote:
>>> * Use of elf.h.  Non-ELF hosts won't have such a header.  You should be 
>>> working with the existing include/elf/*.h definitions of ELF data 
>>> structures in binutils.
>> This is all for build hosts that aren't ELF, right? I don't think we can
>> reasonably expect ctf_open() or ctf_fdopen() to work for anything but
>> raw CTF files on non-ELF hosts, given that by their very nature these
>> functions are getting CTF data out of ELF sections, and non-ELF formats
>> don't necessarily support anything like the named section concept ELF
>> has got at all.
>> 
>> The only other ELF-specificity is looking up types by symbol table
>> offset. Again, I don't know enough about non-ELF platforms to know if
>> this concept is even practical there, which would mean the data object
>> and function info sections would be empty on such hosts, and
>> ctf_lookup_by_symbol(), ctf_func_info() and ctf_func_args() would not
>> function or would be excluded from the set of exported symbols entirely.
>> 
>> This would reduce libctf's utility, but not eliminate it: external
>> systems can still look up types by name or CTF type ID even if they
>> can't do it by symbol.
>
> Even if you only want to support CTF on ELF containers, a cross
> binutils build hosted on e.g., Windows, targeting an ELF port, should
> still be able to use the CTF.  That's why it is important to not rely
> on host headers for ELF definitions.  It wasn't clear to me from
> your remarks above whether the cross use case is considered?

My v2 posting (already out) and v3 (to be posted today, with a
bfdization layer that actually works and a bunch of interface changes to
make it more useful, and an example use in objdump) appear in my testing
to work on mingw, at least. I think that's a non-ELF-capable host.

Avoiding relying on host ELF headers is also important because the ELF
header I was unthinkingly relying on isn't portable outside glibc on
Linux and perhaps Solaris, and that's definitely not portable enough.

(We do still *need* a few lines of stuff from ELF headers, because the
low-level symbol lookup parts of libctf cannot rely on having a bfd
available, so we have to do symbol walkiing by hand -- but we don't need
the host to provide those few lines, and we do use BFD to get section
content etc when possible now.)

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-24 16:05       ` Nick Alcock
@ 2019-05-24 16:19         ` Pedro Alves
  2019-05-24 20:09           ` Nick Alcock
  0 siblings, 1 reply; 52+ messages in thread
From: Pedro Alves @ 2019-05-24 16:19 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Joseph Myers, binutils

On 5/24/19 5:04 PM, Nick Alcock wrote:
> On 24 May 2019, Pedro Alves spake thusly:
>> Even if you only want to support CTF on ELF containers, a cross
>> binutils build hosted on e.g., Windows, targeting an ELF port, should
>> still be able to use the CTF.  That's why it is important to not rely
>> on host headers for ELF definitions.  It wasn't clear to me from
>> your remarks above whether the cross use case is considered?
> 
> My v2 posting (already out) and v3 (to be posted today, with a
> bfdization layer that actually works and a bunch of interface changes to
> make it more useful, and an example use in objdump) appear in my testing
> to work on mingw, at least. I think that's a non-ELF-capable host.

Yes, mingw/Windows uses COFF/PE, not ELF.

> 
> Avoiding relying on host ELF headers is also important because the ELF
> header I was unthinkingly relying on isn't portable outside glibc on
> Linux and perhaps Solaris, and that's definitely not portable enough.
> 
> (We do still *need* a few lines of stuff from ELF headers, because the
> low-level symbol lookup parts of libctf cannot rely on having a bfd
> available, so we have to do symbol walkiing by hand -- but we don't need
> the host to provide those few lines, and we do use BFD to get section
> content etc when possible now.)

Awesome.  Sorry, I'm way behind on the lists.

If everything works in a cross endianness setting too (e.g., big endian
host x little endian target) then you're golden.  :-)

Thanks,
Pedro Alves
 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH 00/19] libctf, and CTF support for objdump and readelf
  2019-05-24 16:19         ` Pedro Alves
@ 2019-05-24 20:09           ` Nick Alcock
  0 siblings, 0 replies; 52+ messages in thread
From: Nick Alcock @ 2019-05-24 20:09 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Joseph Myers, binutils

On 24 May 2019, Pedro Alves told this:

> On 5/24/19 5:04 PM, Nick Alcock wrote:
> If everything works in a cross endianness setting too (e.g., big endian
> host x little endian target) then you're golden.  :-)

It did when I tested it last, which was some weeks ago. The ctf_archive
format is fixed-endian (little-endian): everything else byteswaps at
open time if the magic number suggests it needs to, since at open time
it's reading it all in and blowing the dcache anyway and byteswapping
everything necessary costs nothing. (And means we can ignore endianness
everywhere else in the codebase.)

Note: the original CTF format (as seen on Solaris, FreeBSD etc) is
completely endian-ignorant. It looks like they never considered
endianness at all, so it's totally nonportable to machines of opposing
endianness. Whoops...

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2019-05-24 20:09 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-30 22:57 [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Alcock
2019-04-30 22:57 ` [PATCH 02/19] include: new header ctf-api.h Nick Alcock
2019-05-02 15:07   ` Nick Clifton
2019-05-03 11:23     ` Nick Alcock
2019-04-30 22:57 ` [PATCH 15/19] libctf: mmappable archives Nick Alcock
2019-04-30 22:57 ` [PATCH 05/19] libctf: error handling Nick Alcock
2019-05-02 16:10   ` Nick Clifton
2019-05-03 19:31     ` Nick Alcock
2019-04-30 22:57 ` [PATCH 13/19] libctf: type copying Nick Alcock
2019-04-30 22:57 ` [PATCH 01/19] include: new header ctf.h: file format description Nick Alcock
2019-05-01 16:57   ` Nick Clifton
2019-05-01 21:29     ` Jim Wilson
2019-05-03 11:15       ` Nick Alcock
2019-04-30 22:57 ` [PATCH 09/19] libctf: opening Nick Alcock
2019-04-30 22:57 ` [PATCH 06/19] libctf: hashing Nick Alcock
2019-05-02 16:16   ` Nick Clifton
2019-05-03 19:33     ` Nick Alcock
2019-04-30 22:57 ` [PATCH 10/19] libctf: ELF file opening Nick Alcock
2019-04-30 22:57 ` [PATCH 19/19] binutils: CTF support for objdump and readelf Nick Alcock
2019-04-30 22:57 ` CTF format overview Nick Alcock
2019-04-30 22:57 ` [PATCH 08/19] libctf: creation functions Nick Alcock
2019-04-30 22:57 ` [PATCH 11/19] libctf: core type lookup Nick Alcock
2019-04-30 22:57 ` [PATCH 04/19] libctf: low-level list manipulation and helper utilities Nick Alcock
2019-05-02 16:04   ` Nick Clifton
2019-05-03 19:25     ` Nick Alcock
2019-04-30 22:57 ` [PATCH 14/19] libctf: library version enforcement Nick Alcock
2019-04-30 22:57 ` [PATCH 12/19] libctf: lookups by name and symbol Nick Alcock
2019-04-30 22:57 ` [PATCH 03/19] libctf: lowest-level memory allocation and debug-dumping wrappers Nick Alcock
2019-05-02 15:29   ` Nick Clifton
2019-05-03 19:12     ` Nick Alcock
2019-04-30 22:58 ` [PATCH 18/19] libctf: build system Nick Alcock
2019-05-01  0:13 ` [PATCH 17/19] libctf: debug dumping Nick Alcock
2019-05-01  0:19 ` [PATCH 16/19] libctf: labels Nick Alcock
2019-05-01  1:57 ` [PATCH 07/19] libctf: implementation definitions related to file creation Nick Alcock
2019-05-01 16:02 ` [PATCH 00/19] libctf, and CTF support for objdump and readelf Nick Clifton
2019-05-01 16:16   ` Jose E. Marchesi
2019-05-03 10:47     ` Nick Alcock
2019-05-02 15:22 ` Joseph Myers
2019-05-03 12:33   ` Nick Clifton
2019-05-06 16:40     ` Nick Alcock
2019-05-08 14:34     ` Michael Matz
2019-05-08 16:01       ` Nick Clifton
2019-05-08 16:20         ` Nick Alcock
2019-05-03 14:23   ` Nick Alcock
     [not found]     ` <alpine.DEB.2.21.1905072117440.19308@digraph.polyomino.org.uk>
2019-05-08 11:39       ` Nick Alcock
2019-05-24  8:57     ` Pedro Alves
2019-05-24 16:05       ` Nick Alcock
2019-05-24 16:19         ` Pedro Alves
2019-05-24 20:09           ` Nick Alcock
2019-05-03 16:19 ` Florian Weimer
2019-05-03 19:45   ` Nick Alcock
2019-05-06 12:07     ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).