Fix a number of build problems found on Solaris and NetBSD (was Re: Oh dear. I regret to inform you that commit 0e65dfbaf3a0299e4837216a103c28625d4b4f1d might be unfortunate)

Message ID 87lfyp43w8.fsf_-_@esperi.org.uk
State New, archived
Headers

Commit Message

Nick Alcock May 29, 2019, 4:33 p.m. UTC
  On 29 May 2019, Rainer Orth stated:

> Nix <nix@esperi.org.uk> writes:
>> I stripped almost all of these out, but it looks like one single one
>> survived. It is gone now.
>
> Thanks.

If you'd like to try the entirely unreviewed patch I'm trying out (works
for me on x86_64-pc-linux-gnu, i686-pc-linux-gnu, mingw, Solaris), here
it is:

commit ea9ad1fe21e0d42d554cb702b29cfc312cd5fd59
Author: Nick Alcock <nick.alcock@oracle.com>
Date:   Wed May 29 15:07:06 2019 +0100

    Fix a number of build problems found on Solaris and NetBSD
    
    - Use of nonportable <endian.h>
    - Use of qsort_r
    - Use of zlib without appropriate magic to pull in the binutils zlib
    - Use of off64_t without checking
    - signedness problems due to long being too short a type on 32-bit
      platforms: ctf_id_t is now 'unsigned long', and CTF_ERR must be
      used only for functions that return ctf_id_t
    - One lingering use of bzero() and of <sys/errno.h>
    
    All fixed, using code from gnulib where possible.
    
    include/
            * ctf-api.h (HAVE_OFF64_T): Define off64_t if need be.
            (ctf_id_t): This is now an unsigned type.
            (CTF_ERR): Cast it to ctf_id_t.  Note that it should only be used
            for ctf_id_t-returning functions.
    libctf/
            * Makefile.am (ZLIB): New.
            (ZLIBINC): Likewise.
            (AM_CFLAGS): Use them.
            (libctf_a_LIBADD): New, for LIBOBJS.
            * configure.ac: Check for zlib, endian.h, off64_t, and qsort_r.
            * ctf-endian.h: New, providing htole64 and le64toh.
            * swap.h: Code style fixes.
            (bswap_identity_64): New.
            * qsort_r.c: New, from gnulib (with one added #include).
            * ctf-decls.h: New, providing a conditional qsort_r declaration,
            and unconditional definitions of MIN and MAX.
            * ctf-impl.h: Use it.  Do not use <sys/errno.h>.
            (ctf_set_errno): Now returns unsigned long.
            * ctf-util.c (ctf_set_errno): Adjust here too.
            * ctf-archive.c: Use ctf-endian.h.
            (ctf_arc_open_by_offset): Use memset, not bzero.
            (ctf_arc_write): Drop debugging dependent on the size of off_t.
            * ctf-create.c: Provide a definition of roundup if not defined.
            (ctf_add_reftype): Do not check if type IDs are below zero.
            (ctf_add_slice): Likewise.
            (ctf_add_typedef): Likewise.
            (ctf_add_member_offset): Cast error-returning ssize_t's to size_t
            when known error-free.  Drop CTF_ERR usage for functions returning
            int.
            (ctf_add_member_encoded): Drop CTF_ERR usage for functions returning
            int.
            (ctf_add_variable): Likewise.
            (enumcmp): Likewise.
            (enumadd): Likewise.
            (membcmp): Likewise.
            (ctf_add_type): Likewise.  Cast error-returning ssize_t's to size_t
            when known error-free.
            * ctf-dump.c (ctf_is_slice): Drop CTF_ERR usage for functions
            returning int: use CTF_ERR for functions returning ctf_type_id.
            (ctf_dump_label): Likewise.
            (ctf_dump_objts): Likewise.
            * ctf-labels.c (ctf_label_topmost): Likewise.
            (ctf_label_iter): Likewise.
            (ctf_label_info): Likewise.
            * ctf-lookup.c (ctf_func_args): Likewise.
            * ctf-open.c (upgrade_types): Cast to size_t where appropriate.
            (ctf_bufopen): Likewise.  Use zlib types as needed.
            * ctf-types.c (ctf_member_iter): Drop CTF_ERR usage for functions
            returning int.
            (ctf_enum_iter): Likewise.
            (ctf_type_size): Likewise.
            (ctf_type_align): Likewise.  Cast to size_t where appropriate.
            (ctf_type_kind_unsliced): Likewise.
            (ctf_type_kind): Likewise.
            (ctf_type_encoding): Likewise.
            (ctf_member_info): Likewise.
            (ctf_array_info): Likewise.
            (ctf_enum_value): Likewise.
            (ctf_type_rvisit): Likewise.
            * Makefile.in: Regenerate.
            * aclocal.m4: Likewise.
            * config.h: Likewise.
            * configure: Likewise.
  

Comments

Rainer Orth May 29, 2019, 6:22 p.m. UTC | #1
Hi Nick,

> On 29 May 2019, Rainer Orth stated:
>
>> Nix <nix@esperi.org.uk> writes:
>>> I stripped almost all of these out, but it looks like one single one
>>> survived. It is gone now.
>>
>> Thanks.
>
> If you'd like to try the entirely unreviewed patch I'm trying out (works
> for me on x86_64-pc-linux-gnu, i686-pc-linux-gnu, mingw, Solaris), here
> it is:

I've just tried a build of the gdb side of binutils-gdb with your patch
applied on amd64-pc-solaris2.11 for good measure: worked just fine
without any warnings.

Thanks.
        Rainer
  
Nick Alcock May 29, 2019, 8:07 p.m. UTC | #2
On 29 May 2019, Rainer Orth outgrape:
> I've just tried a build of the gdb side of binutils-gdb with your patch
> applied on amd64-pc-solaris2.11 for good measure: worked just fine
> without any warnings.

Great news!

(This is quite irrelevant since we're not currently caring about ABI/API
stability for libctf, but it doesn't change the API or ABI on 64-bit
systems either, since no type will have an ID remotely near the 63-bit
sign-bit boundary: the max is currently 2^32-2.)
  
Kamil Rytarowski May 29, 2019, 8:22 p.m. UTC | #3
On 29.05.2019 18:33, Nick Alcock wrote:
> On 29 May 2019, Rainer Orth stated:
> 
>> Nix <nix@esperi.org.uk> writes:
>>> I stripped almost all of these out, but it looks like one single one
>>> survived. It is gone now.
>>
>> Thanks.
> 
> If you'd like to try the entirely unreviewed patch I'm trying out (works
> for me on x86_64-pc-linux-gnu, i686-pc-linux-gnu, mingw, Solaris), here
> it is:
> 

I wanted to check this patch on NetBSD but it does not apply for me for
some reason (I've used the original source of the mail as a patch).

Is it safe to use this off64_t define? Won't there be issues with off_t
that is 64-bit on NetBSD and 32-bit on some other OSs? NetBSD uses the
libctf stack from FreeBSD/SunOS for DTrace, will that be compatible with
this GDB code? Keeping CTF support is not the highest priority for us,
as we ship with DWARF.. but compatibility is good.

Feel free to apply this patch and it will be checked with the buildbot node.

$ cat /tmp/1.x |gpatch -p1
patching file include/ChangeLog
patching file include/ctf-api.h
patching file libctf/ChangeLog
Hunk #1 succeeded at 1 with fuzz 1.
patching file libctf/Makefile.am
patching file libctf/Makefile.in
patching file libctf/aclocal.m4
patching file libctf/config.h.in
Hunk #1 FAILED at 1.
Hunk #2 succeeded at 15 (offset -3 lines).
Hunk #3 succeeded at 94 (offset -3 lines).
1 out of 3 hunks FAILED -- saving rejects to file libctf/config.h.in.rej
patching file libctf/configure
Hunk #5 FAILED at 6139.
Hunk #6 succeeded at 6082 with fuzz 2 (offset -108 lines).
Hunk #7 succeeded at 6340 (offset -108 lines).
Hunk #8 succeeded at 6500 (offset -108 lines).
1 out of 8 hunks FAILED -- saving rejects to file libctf/configure.rej
patching file libctf/configure.ac
Hunk #1 FAILED at 56.
Hunk #2 FAILED at 86.
2 out of 2 hunks FAILED -- saving rejects to file libctf/configure.ac.rej
patching file libctf/ctf-archive.c
patching file libctf/ctf-create.c
patching file libctf/ctf-decls.h
patching file libctf/ctf-dump.c
patching file libctf/ctf-endian.h
patching file libctf/ctf-impl.h
patching file libctf/ctf-labels.c
patching file libctf/ctf-lookup.c
patching file libctf/ctf-open.c
patching file libctf/ctf-types.c
patching file libctf/ctf-util.c
patching file libctf/qsort_r.c
patching file libctf/swap.h
  

Patch

diff --git a/include/ChangeLog b/include/ChangeLog
index 05083763b1..1ad53db690 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,10 @@ 
+2019-05-29  Nick Alcock  <nick.alcock@oracle.com>
+
+	* ctf-api.h (HAVE_OFF64_T): Define off64_t if need be.
+	(ctf_id_t): This is now an unsigned type.
+	(CTF_ERR): Cast it to ctf_id_t.  Note that it should only be used
+	for ctf_id_t-returning functions.
+
 2019-05-28  Nick Alcock  <nick.alcock@oracle.com>
 
 	* ctf-api.h (ctf_dump_decorate_f): New.
diff --git a/include/ctf-api.h b/include/ctf-api.h
index 822b3bf5a9..5d9274c55d 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -29,6 +29,10 @@ 
 #include <ctf.h>
 #include <zlib.h>
 
+#ifndef HAVE_OFF64_T
+#define off64_t off_t
+#endif
+
 #ifdef	__cplusplus
 extern "C"
   {
@@ -43,7 +47,7 @@  extern "C"
 
 typedef struct ctf_file ctf_file_t;
 typedef struct ctf_archive_internal ctf_archive_t;
-typedef long ctf_id_t;
+typedef unsigned long ctf_id_t;
 
 /* This opaque definition allows libctf to accept BFD data structures without
    importing all the BFD noise into users' namespaces.  */
@@ -125,9 +129,10 @@  typedef struct ctf_snapshot_id
 
 #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)
+/* Functions that return a ctf_id_t use the following value to indicate failure.
+   ctf_errno() can be used to obtain an error code.  Functions that return
+   a straight integral -1 also use ctf_errno().  */
+#define	CTF_ERR	((ctf_id_t) -1L)
 
 #define	ECTF_BASE	1000	/* Base value for libctf errnos.  */
 
diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index 879aeed38f..d4e760f576 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,64 @@ 
+2019-05-29  Nick Alcock  <nick.alcock@oracle.com>
+
+	* Makefile.am (ZLIB): New.
+	(ZLIBINC): Likewise.
+	(AM_CFLAGS): Use them.
+	(libctf_a_LIBADD): New, for LIBOBJS.
+	* configure.ac: Check for zlib, endian.h, off64_t, and qsort_r.
+	* ctf-endian.h: New, providing htole64 and le64toh.
+	* swap.h: Code style fixes.
+	(bswap_identity_64): New.
+	* qsort_r.c: New, from gnulib (with one added #include).
+	* ctf-decls.h: New, providing a conditional qsort_r declaration,
+	and unconditional definitions of MIN and MAX.
+	* ctf-impl.h: Use it.  Do not use <sys/errno.h>.
+	(ctf_set_errno): Now returns unsigned long.
+	* ctf-util.c (ctf_set_errno): Adjust here too.
+	* ctf-archive.c: Use ctf-endian.h.
+	(ctf_arc_open_by_offset): Use memset, not bzero.
+	(ctf_arc_write): Drop debugging dependent on the size of off_t.
+	* ctf-create.c: Provide a definition of roundup if not defined.
+	(ctf_add_reftype): Do not check if type IDs are below zero.
+	(ctf_add_slice): Likewise.
+	(ctf_add_typedef): Likewise.
+	(ctf_add_member_offset): Cast error-returning ssize_t's to size_t
+	when known error-free.  Drop CTF_ERR usage for functions returning
+	int.
+	(ctf_add_member_encoded): Drop CTF_ERR usage for functions returning
+	int.
+	(ctf_add_variable): Likewise.
+	(enumcmp): Likewise.
+	(enumadd): Likewise.
+	(membcmp): Likewise.
+	(ctf_add_type): Likewise.  Cast error-returning ssize_t's to size_t
+	when known error-free.
+	* ctf-dump.c (ctf_is_slice): Drop CTF_ERR usage for functions
+	returning int: use CTF_ERR for functions returning ctf_type_id.
+	(ctf_dump_label): Likewise.
+	(ctf_dump_objts): Likewise.
+	* ctf-labels.c (ctf_label_topmost): Likewise.
+	(ctf_label_iter): Likewise.
+	(ctf_label_info): Likewise.
+	* ctf-lookup.c (ctf_func_args): Likewise.
+	* ctf-open.c (upgrade_types): Cast to size_t where appropriate.
+	(ctf_bufopen): Likewise.  Use zlib types as needed.
+	* ctf-types.c (ctf_member_iter): Drop CTF_ERR usage for functions
+	returning int.
+	(ctf_enum_iter): Likewise.
+	(ctf_type_size): Likewise.
+	(ctf_type_align): Likewise.  Cast to size_t where appropriate.
+	(ctf_type_kind_unsliced): Likewise.
+	(ctf_type_kind): Likewise.
+	(ctf_type_encoding): Likewise.
+	(ctf_member_info): Likewise.
+	(ctf_array_info): Likewise.
+	(ctf_enum_value): Likewise.
+	(ctf_type_rvisit): Likewise.
+	* Makefile.in: Regenerate.
+	* aclocal.m4: Likewise.
+	* config.h: Likewise.
+	* configure: Likewise.
+
 2019-05-28  Nick Alcock  <nick.alcock@oracle.com>
 
 	* configure.in: Check for bfd_section_from_elf_index.
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 5fe2c95901..49c9f5280a 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -21,11 +21,18 @@  ACLOCAL_AMFLAGS = -I .. -I ../config
 
 AUTOMAKE_OPTIONS = foreign no-texinfo.tex
 
+# This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
+# -I../zlib, unless we were configured with --with-system-zlib, in which
+# case both are empty.
+ZLIB = @zlibdir@ -lz
+ZLIBINC = @zlibinc@
+
 AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir) -I$(top_srcdir)/../include -I$(top_srcdir)/../bfd -I../bfd
-AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
 
 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-lookup.c ctf-open.c ctf-open-bfd.c \
 		   ctf-subr.c ctf-types.c ctf-util.c
+libctf_a_LIBADD = $(LIBOBJS)
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index b0afa5b80d..c2cada6616 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -109,7 +109,8 @@  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
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../config/zlib.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -127,7 +128,7 @@  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 =
+libctf_a_DEPENDENCIES = $(LIBOBJS)
 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-lookup.$(OBJEXT) \
@@ -194,7 +195,8 @@  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
+	$(top_srcdir)/../missing $(top_srcdir)/../mkinstalldirs \
+	ChangeLog qsort_r.c
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -308,15 +310,24 @@  top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 warn = @warn@
+zlibdir = @zlibdir@
+zlibinc = @zlibinc@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+
+# This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
+# -I../zlib, unless we were configured with --with-system-zlib, in which
+# case both are empty.
+ZLIB = @zlibdir@ -lz
+ZLIBINC = @zlibinc@
 AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir) -I$(top_srcdir)/../include -I$(top_srcdir)/../bfd -I../bfd
-AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
 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-lookup.c ctf-open.c ctf-open-bfd.c \
 		   ctf-subr.c ctf-types.c ctf-util.c
 
+libctf_a_LIBADD = $(LIBOBJS)
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -385,6 +396,7 @@  mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/qsort_r.Po@am__quote@
 @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@
@@ -675,7 +687,7 @@  clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf ./$(DEPDIR)
+	-rm -rf $(DEPDIR) ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-tags
@@ -723,7 +735,7 @@  installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf ./$(DEPDIR)
+	-rm -rf $(DEPDIR) ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/libctf/aclocal.m4 b/libctf/aclocal.m4
index d792e62dfb..074f03638f 100644
--- a/libctf/aclocal.m4
+++ b/libctf/aclocal.m4
@@ -1231,3 +1231,4 @@  m4_include([../config/depstand.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/override.m4])
 m4_include([../config/warnings.m4])
+m4_include([../config/zlib.m4])
diff --git a/libctf/config.h.in b/libctf/config.h.in
index 829201033e..afdfeecd3a 100644
--- a/libctf/config.h.in
+++ b/libctf/config.h.in
@@ -1,11 +1,21 @@ 
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
 /* Whether libbfd was configured for an ELF target. */
 #undef HAVE_BFD_ELF
 
 /* Define to 1 if you have the <byteswap.h> header file. */
 #undef HAVE_BYTESWAP_H
 
+/* Define to 1 if you have the declaration of `qsort_r', and to 0 if you
+   don't. */
+#undef HAVE_DECL_QSORT_R
+
+/* Define to 1 if you have the <endian.h> header file. */
+#undef HAVE_ENDIAN_H
+
 /* Define to 1 if you have the `getpagesize' function. */
 #undef HAVE_GETPAGESIZE
 
@@ -18,6 +28,9 @@ 
 /* Define to 1 if you have a working `mmap' system call. */
 #undef HAVE_MMAP
 
+/* Define to 1 if the system has the type `off64_t'. */
+#undef HAVE_OFF64_T
+
 /* Define to 1 if you have the `pread' function. */
 #undef HAVE_PREAD
 
@@ -94,6 +107,18 @@ 
 /* Version number of package */
 #undef VERSION
 
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
 /* Enable large inode numbers on Mac OS X 10.5.  */
 #ifndef _DARWIN_USE_64_BIT_INODE
 # define _DARWIN_USE_64_BIT_INODE 1
diff --git a/libctf/configure b/libctf/configure
index 1c0340125a..4a8ca2708f 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -624,6 +624,8 @@  ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+zlibinc
+zlibdir
 ac_libctf_warn_cflags
 MAINT
 MAINTAINER_MODE_FALSE
@@ -728,6 +730,7 @@  enable_silent_rules
 enable_largefile
 enable_werror_always
 enable_maintainer_mode
+with_system_zlib
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1364,6 +1367,11 @@  Optional Features:
                           enable make rules and dependencies not useful (and
                           sometimes confusing) to the casual installer
 
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-system-zlib      use installed libz
+
 Some influential environment variables:
   CC          C compiler command
   CFLAGS      C compiler flags
@@ -1801,6 +1809,106 @@  $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
 } # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  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
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=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
+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_type
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_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_decl
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
@@ -6031,6 +6139,23 @@  if test "$ac_res" != no; then :
 fi
 
 
+  # Use the system's zlib library.
+  zlibdir="-L\$(top_builddir)/../zlib"
+  zlibinc="-I\$(top_srcdir)/../zlib"
+
+# Check whether --with-system-zlib was given.
+if test "${with_system_zlib+set}" = set; then :
+  withval=$with_system_zlib; if test x$with_system_zlib = xyes ; then
+    zlibdir=
+    zlibinc=
+  fi
+
+fi
+
+
+
+
+
 # Similar to GDB_AC_CHECK_BFD.
 OLD_CFLAGS=$CFLAGS
 OLD_LDFLAGS=$LDFLAGS
@@ -6082,18 +6207,253 @@  $as_echo "#define HAVE_BFD_ELF 1" >>confdefs.h
 
 fi
 
-for ac_header in byteswap.h
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+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
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+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
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+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_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+for ac_header in byteswap.h endian.h
 do :
-  ac_fn_c_check_header_mongrel "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default"
-if test "x$ac_cv_header_byteswap_h" = xyes; then :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_BYTESWAP_H 1
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 fi
 
 done
 
+ac_fn_c_check_type "$LINENO" "off64_t" "ac_cv_type_off64_t" "$ac_includes_default"
+if test "x$ac_cv_type_off64_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_OFF64_T 1
+_ACEOF
+
+
+fi
+
 for ac_func in pread
 do :
   ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
@@ -6105,6 +6465,23 @@  _ACEOF
 fi
 done
 
+ac_fn_c_check_decl "$LINENO" "qsort_r" "ac_cv_have_decl_qsort_r" "$ac_includes_default"
+if test "x$ac_cv_have_decl_qsort_r" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_QSORT_R $ac_have_decl
+_ACEOF
+
+case " $LIBOBJS " in
+  *" qsort_r.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS qsort_r.$ac_objext"
+ ;;
+esac
+
 
 ac_config_files="$ac_config_files Makefile"
 
@@ -6248,6 +6625,7 @@  if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
 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
diff --git a/libctf/configure.ac b/libctf/configure.ac
index 2df10935c0..6a2eb500ee 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -56,6 +56,7 @@  ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libctf_warn_cflags])
 
 AC_FUNC_MMAP
 AC_SEARCH_LIBS(dlopen, dl)
+AM_ZLIB
 
 # Similar to GDB_AC_CHECK_BFD.
 OLD_CFLAGS=$CFLAGS
@@ -86,8 +87,12 @@  if test $ac_cv_libctf_bfd_elf = yes; then
 	    [Whether libbfd was configured for an ELF target.])
 fi
 
-AC_CHECK_HEADERS(byteswap.h)
+AC_C_BIGENDIAN
+AC_CHECK_HEADERS(byteswap.h endian.h)
+AC_CHECK_TYPES(off64_t)
 AC_CHECK_FUNCS(pread)
+AC_CHECK_DECLS([qsort_r])
+AC_LIBOBJ([qsort_r])
 
 AC_CONFIG_FILES(Makefile)
 AC_CONFIG_HEADERS(config.h)
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index ab658fd351..f68bc13e60 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -21,7 +21,7 @@ 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <elf.h>
-#include <endian.h>
+#include "ctf-endian.h"
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -150,7 +150,6 @@  ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
       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 "
@@ -512,7 +511,7 @@  ctf_arc_open_by_offset (const struct ctf_archive *arc,
 
   ctf_dprintf ("ctf_arc_open_by_offset(%zi): opening\n", offset);
 
-  bzero (&ctfsect, sizeof (ctf_sect_t));
+  memset (&ctfsect, 0, sizeof (ctf_sect_t));
 
   offset += le64toh (arc->ctfa_ctfs);
 
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 5409ca4bb4..35d525927e 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -23,6 +23,10 @@ 
 #include <string.h>
 #include <zlib.h>
 
+#ifndef roundup
+#define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
+#endif
+
 /* 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
@@ -812,7 +816,7 @@  ctf_add_reftype (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   ctf_id_t type;
   ctf_file_t *tmp = fp;
 
-  if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+  if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
@@ -843,7 +847,7 @@  ctf_add_slice (ctf_file_t *fp, uint32_t flag, ctf_id_t ref,
   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)
+  if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
   if ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL)
@@ -1175,7 +1179,7 @@  ctf_add_typedef (ctf_file_t *fp, uint32_t flag, const char *name,
   ctf_id_t type;
   ctf_file_t *tmp = fp;
 
-  if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+  if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
@@ -1304,9 +1308,9 @@  ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
 	}
     }
 
-  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 ((msize = ctf_type_size (fp, type)) < 0 ||
+      (malign = ctf_type_align (fp, type)) < 0)
+    return -1;			/* errno is set for us.  */
 
   if ((dmd = ctf_alloc (sizeof (ctf_dmdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
@@ -1334,9 +1338,9 @@  ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
 	  ctf_encoding_t linfo;
 	  ssize_t lsize;
 
-	  if (ctf_type_encoding (fp, ltype, &linfo) != CTF_ERR)
+	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
 	    off += linfo.cte_bits;
-	  else if ((lsize = ctf_type_size (fp, ltype)) != CTF_ERR)
+	  else if ((lsize = ctf_type_size (fp, ltype)) > 0)
 	    off += lsize * NBBY;
 
 	  /* Round up the offset of the end of the last member to
@@ -1359,7 +1363,7 @@  ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
 
 	  dmd->dmd_offset = bit_offset;
 	  ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
-	  ssize = MAX (ssize, (bit_offset / NBBY) + msize);
+	  ssize = MAX (ssize, ((signed) bit_offset / NBBY) + msize);
 	}
     }
   else
@@ -1369,7 +1373,7 @@  ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
       ssize = MAX (ssize, msize);
     }
 
-  if (ssize > CTF_MAX_SIZE)
+  if ((size_t) ssize > CTF_MAX_SIZE)
     {
       dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
       dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
@@ -1401,7 +1405,7 @@  ctf_add_member_encoded (ctf_file_t *fp, ctf_id_t souid, const char *name,
     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 -1;			/* errno is set for us.  */
 
   return ctf_add_member_offset (fp, souid, name, type, bit_offset);
 }
@@ -1426,7 +1430,7 @@  ctf_add_variable (ctf_file_t *fp, const char *name, ctf_id_t ref)
     return (ctf_set_errno (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((dvd = ctf_alloc (sizeof (ctf_dvdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
@@ -1452,7 +1456,7 @@  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)
+  if (ctf_enum_value (ctb->ctb_file, ctb->ctb_type, name, &bvalue) < 0)
     {
       ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
       return 1;
@@ -1472,7 +1476,7 @@  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);
+			      name, value) < 0);
 }
 
 static int
@@ -1482,7 +1486,7 @@  membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset,
   ctf_bundle_t *ctb = arg;
   ctf_membinfo_t ctm;
 
-  if (ctf_member_info (ctb->ctb_file, ctb->ctb_type, name, &ctm) == CTF_ERR)
+  if (ctf_member_info (ctb->ctb_file, ctb->ctb_type, name, &ctm) < 0)
     {
       ctf_dprintf ("Conflict due to member %s iteration error.\n", name);
       return 1;
@@ -1550,7 +1554,6 @@  ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
 
   ctf_dtdef_t *dtd;
   ctf_funcinfo_t ctc;
-  ssize_t size;
 
   ctf_hash_t *hp;
 
@@ -1756,7 +1759,7 @@  ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
       break;
 
     case CTF_K_ARRAY:
-      if (ctf_array_info (src_fp, src_type, &src_ar) == CTF_ERR)
+      if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
 	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
 
       src_ar.ctr_contents =
@@ -1803,6 +1806,8 @@  ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
       {
 	ctf_dmdef_t *dmd;
 	int errs = 0;
+	size_t size;
+	ssize_t ssize;
 
 	/* Technically to match a struct or union we need to check both
 	   ways (src members vs. dst, dst members vs. src) but we make
@@ -1818,7 +1823,7 @@  ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t 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",
+			     "union size differs, old %zi, new %zi\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));
@@ -1848,7 +1853,11 @@  ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
 	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)
+	if ((ssize = ctf_type_size (src_fp, src_type)) < 0)
+	  return CTF_ERR;			/* errno is set for us.  */
+
+	size = (size_t) ssize;
+	if (size > CTF_MAX_SIZE)
 	  {
 	    dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
 	    dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
diff --git a/libctf/ctf-decls.h b/libctf/ctf-decls.h
new file mode 100644
index 0000000000..5e9ede4809
--- /dev/null
+++ b/libctf/ctf-decls.h
@@ -0,0 +1,37 @@ 
+/* Declarations for missing functions.
+   Copyright (C) 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 3, 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_DECLS_H
+#define _CTF_DECLS_H
+
+#include "config.h"
+
+#if !HAVE_DECL_QSORT_R
+#include <stddef.h>
+void qsort_r (void *base, size_t nmemb, size_t size,
+	      int (*compar)(const void *, const void *, void *),
+	      void *arg);
+#endif /* !HAVE_DECL_QSORT_R */
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#endif /* _CTF_DECLS_H */
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 28f31e4872..c2ed791eea 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -88,7 +88,7 @@  ctf_is_slice (ctf_file_t *fp, ctf_id_t id, ctf_encoding_t *enc)
   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);
+	  && ctf_type_encoding (fp, id, enc) == 0);
 }
 
 /* Return a dump for a single type, without member info: but do show the
@@ -168,7 +168,7 @@  ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type)) == NULL)
     {
       free (str);
-      return CTF_ERR;			/* errno is set for us.  */
+      return -1;			/* errno is set for us.  */
     }
 
   str = ctf_str_append (str, typestr);
@@ -194,14 +194,14 @@  ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
       const char *sym_name;
       ctf_id_t type;
 
-      if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) < 0)
+      if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) == CTF_ERR)
 	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;
+	    return -1;
 	  case ECTF_NOTDATA:
 	  case ECTF_NOTYPEDAT:
 	    continue;
@@ -224,7 +224,7 @@  ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
       if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
 	{
 	  free (str);
-	  return CTF_ERR;		/* errno is set for us.  */
+	  return -1;			/* errno is set for us.  */
 	}
 
       str = ctf_str_append (str, typestr);
@@ -253,14 +253,14 @@  ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
       size_t j;
       ctf_id_t *args;
 
-      if ((type = ctf_func_info (state->cds_fp, i, &fi)) < 0)
+      if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR)
 	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;
+	    return -1;
 	  case ECTF_NOTDATA:
 	  case ECTF_NOTYPEDAT:
 	    continue;
@@ -321,7 +321,7 @@  ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
     err:
       free (args);
       free (str);
-      return CTF_ERR;		/* errno is set for us.  */
+      return -1;		/* errno is set for us.  */
     }
   return 0;
 }
@@ -340,7 +340,7 @@  ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
     {
       free (str);
-      return CTF_ERR;			/* errno is set for us.  */
+      return -1;			/* errno is set for us.  */
     }
 
   str = ctf_str_append (str, typestr);
@@ -426,7 +426,7 @@  ctf_dump_type (ctf_id_t id, void *arg)
 
  err:
   free (str);
-  return CTF_ERR;			/* errno is set for us.  */
+  return -1;				/* errno is set for us.  */
 }
 
 /* Dump the string table into the cds_items.  */
diff --git a/libctf/ctf-endian.h b/libctf/ctf-endian.h
new file mode 100644
index 0000000000..ec177d1bdd
--- /dev/null
+++ b/libctf/ctf-endian.h
@@ -0,0 +1,37 @@ 
+/* Interface to endianness-neutrality functions.
+   Copyright (C) 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 3, 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_ENDIAN_H
+#define _CTF_ENDIAN_H
+
+#include "config.h"
+#include <stdint.h>
+#include "swap.h"
+
+#ifndef HAVE_ENDIAN_H
+#ifndef WORDS_BIGENDIAN
+# define htole64(x) bswap_identity_64 ((x))
+# define le64toh(x) bswap_identity_64 ((x))
+#else
+# define htole64(x) bswap_64 ((x))
+# define le64toh(x) bswap_64 ((x))
+#endif /* WORDS_BIGENDIAN */
+#endif /* !defined(HAVE_ENDIAN_H) */
+
+#endif /* !defined(_CTF_ENDIAN_H) */
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 363b62de7d..fa9c574941 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -21,7 +21,8 @@ 
 #define	_CTF_IMPL_H
 
 #include "config.h"
-#include <sys/errno.h>
+#include <errno.h>
+#include "ctf-decls.h"
 #include <ctf-api.h>
 #include <sys/types.h>
 #include <stdlib.h>
@@ -339,7 +340,7 @@  extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern struct ctf_archive *ctf_arc_bufopen (const void *, size_t, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern void *ctf_set_open_errno (int *, int);
-extern long ctf_set_errno (ctf_file_t *, int);
+extern unsigned long ctf_set_errno (ctf_file_t *, int);
 
 _libctf_malloc_
 extern void *ctf_data_alloc (size_t);
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 9b9fffea4e..1755b9720a 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -43,7 +43,7 @@  ctf_label_topmost (ctf_file_t *fp)
   const char *s;
   uint32_t num_labels = 0;
 
-  if (extract_label_info (fp, &ctlp, &num_labels) == CTF_ERR)
+  if (extract_label_info (fp, &ctlp, &num_labels) < 0)
     return NULL;				/* errno is set for us.  */
 
   if (num_labels == 0)
@@ -70,8 +70,8 @@  ctf_label_iter (ctf_file_t *fp, ctf_label_f *func, void *arg)
   const char *lname;
   int rc;
 
-  if (extract_label_info (fp, &ctlp, &num_labels) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+  if (extract_label_info (fp, &ctlp, &num_labels) < 0)
+    return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
     return (ctf_set_errno (fp, ECTF_NOLABELDATA));
@@ -128,7 +128,7 @@  ctf_label_info (ctf_file_t *fp, const char *lname, ctf_lblinfo_t *linfo)
   cb_arg.lca_name = lname;
   cb_arg.lca_info = linfo;
 
-  if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) == CTF_ERR)
+  if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) < 0)
     return rc;
 
   if (rc != 1)
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 7ea46a7295..ab12715f4b 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -412,8 +412,8 @@  ctf_func_args (ctf_file_t * fp, unsigned long symidx, uint32_t argc,
   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.  */
+  if (ctf_func_info (fp, symidx, &f) < 0)
+    return -1;			/* 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. */
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 5230d09a97..77cefc820b 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -503,7 +503,7 @@  upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
 	case CTF_K_UNION:
 	case CTF_K_ENUM:
 	case CTF_K_UNKNOWN:
-	  if (size <= CTF_MAX_SIZE)
+	  if ((size_t) size <= CTF_MAX_SIZE)
 	    t2p->ctt_size = size;
 	  else
 	    {
@@ -1317,7 +1317,8 @@  ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
   if (hp.cth_flags & CTF_F_COMPRESS)
     {
-      size_t srclen, dstlen;
+      size_t srclen;
+      uLongf dstlen;
       const void *src;
       int rc = Z_OK;
 
@@ -1339,7 +1340,7 @@  ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 	  return (ctf_set_open_errno (errp, ECTF_DECOMPRESS));
 	}
 
-      if (dstlen != size)
+      if ((size_t) dstlen != size)
 	{
 	  ctf_dprintf ("zlib inflate short -- got %lu of %lu "
 		       "bytes\n", (unsigned long) dstlen, (unsigned long) size);
@@ -1678,12 +1679,15 @@  ctf_getmodel (ctf_file_t *fp)
   return fp->ctf_dmodel->ctd_code;
 }
 
+/* The caller can hang an arbitrary pointer off each ctf_file_t using this
+   function.  */
 void
 ctf_setspecific (ctf_file_t *fp, void *data)
 {
   fp->ctf_specific = data;
 }
 
+/* Retrieve the arbitrary pointer again.  */
 void *
 ctf_getspecific (ctf_file_t *fp)
 {
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index a7fe5d0b18..dc158e2f52 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -47,10 +47,10 @@  ctf_member_iter (ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
   int rc;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   (void) ctf_get_ctt_size (fp, tp, &size, &increment);
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
@@ -102,10 +102,10 @@  ctf_enum_iter (ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
   int rc;
 
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     return (ctf_set_errno (ofp, ECTF_NOTENUM));
@@ -406,8 +406,8 @@  ctf_type_size (ctf_file_t *fp, ctf_id_t type)
       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)
+      if (ctf_array_info (fp, type, &ar) < 0
+	  || (size = ctf_type_size (fp, ar.ctr_contents)) < 0)
 	return -1;		/* errno is set for us.  */
 
       return size * ar.ctr_nelems;
@@ -445,7 +445,7 @@  ctf_type_align (ctf_file_t *fp, ctf_id_t type)
     case CTF_K_ARRAY:
       {
 	ctf_arinfo_t r;
-	if (ctf_array_info (fp, type, &r) == CTF_ERR)
+	if (ctf_array_info (fp, type, &r) < 0)
 	  return -1;		/* errno is set for us.  */
 	return (ctf_type_align (fp, r.ctr_contents));
       }
@@ -474,7 +474,7 @@  ctf_type_align (ctf_file_t *fp, ctf_id_t type)
 		for (; n != 0; n--, mp++)
 		  {
 		    ssize_t am = ctf_type_align (fp, mp->ctm_type);
-		    align = MAX (align, am);
+		    align = MAX (align, (size_t) am);
 		  }
 	      }
 	    else
@@ -483,7 +483,7 @@  ctf_type_align (ctf_file_t *fp, ctf_id_t type)
 		for (; n != 0; n--, lmp++)
 		  {
 		    ssize_t am = ctf_type_align (fp, lmp->ctlm_type);
-		    align = MAX (align, am);
+		    align = MAX (align, (size_t) am);
 		  }
 	      }
 	  }
@@ -495,7 +495,7 @@  ctf_type_align (ctf_file_t *fp, ctf_id_t type)
 		   dmd != NULL; dmd = ctf_list_next (dmd))
 		{
 		  ssize_t am = ctf_type_align (fp, dmd->dmd_type);
-		  align = MAX (align, am);
+		  align = MAX (align, (size_t) am);
 		  if (kind == CTF_K_STRUCT)
 		    break;
 		}
@@ -520,7 +520,7 @@  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 -1;			/* errno is set for us.  */
 
   return (LCTF_INFO_KIND (fp, tp->ctt_info));
 }
@@ -533,13 +533,13 @@  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_type_kind_unsliced (fp, type)) < 0)
+    return -1;
 
   if (kind == CTF_K_SLICE)
     {
       if ((type = ctf_type_reference (fp, type)) == CTF_ERR)
-	return CTF_ERR;
+	return -1;
       kind = ctf_type_kind_unsliced (fp, type);
     }
 
@@ -624,7 +624,7 @@  ctf_type_encoding (ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
   uint32_t data;
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     {
@@ -790,10 +790,10 @@  ctf_member_info (ctf_file_t *fp, ctf_id_t type, const char *name,
   uint32_t kind, n;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   (void) ctf_get_ctt_size (fp, tp, &size, &increment);
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
@@ -847,7 +847,7 @@  ctf_array_info (ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
   ssize_t increment;
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY)
     return (ctf_set_errno (ofp, ECTF_NOTARRAY));
@@ -919,15 +919,15 @@  ctf_enum_value (ctf_file_t * fp, ctf_id_t type, const char *name, int *valp)
   uint32_t n;
 
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* 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;
+      return -1;
     }
 
   (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
@@ -945,7 +945,7 @@  ctf_enum_value (ctf_file_t * fp, ctf_id_t type, const char *name, int *valp)
     }
 
   (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
-  return CTF_ERR;
+  return -1;
 }
 
 /* Recursively visit the members of any type.  This function is used as the
@@ -965,10 +965,10 @@  ctf_type_rvisit (ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func,
   int rc;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return -1;			/* errno is set for us.  */
 
   if ((rc = func (name, otype, offset, depth, arg)) != 0)
     return rc;
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 44600467a7..730f358a93 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -166,9 +166,9 @@  ctf_set_open_errno (int *errp, int error)
 }
 
 /* Store the specified error code into the CTF container, and then return
-   CTF_ERR for the benefit of the caller. */
+   CTF_ERR / -1 for the benefit of the caller. */
 
-long
+unsigned long
 ctf_set_errno (ctf_file_t * fp, int err)
 {
   fp->ctf_errno = err;
diff --git a/libctf/qsort_r.c b/libctf/qsort_r.c
new file mode 100644
index 0000000000..6c334fdaf3
--- /dev/null
+++ b/libctf/qsort_r.c
@@ -0,0 +1,259 @@ 
+/* Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   This file is part of libctf (imported from Gnulib).
+   Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* If you consider tuning this algorithm, you should consult first:
+   Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+   Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ctf-decls.h"
+
+#ifndef _LIBC
+# define _quicksort qsort_r
+# define __compar_d_fn_t compar_d_fn_t
+typedef int (*compar_d_fn_t) (const void *, const void *, void *);
+#endif
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size)						      \
+  do									      \
+    {									      \
+      size_t __size = (size);						      \
+      char *__a = (a), *__b = (b);					      \
+      do								      \
+	{								      \
+	  char __tmp = *__a;						      \
+	  *__a++ = *__b;						      \
+	  *__b++ = __tmp;						      \
+	} while (--__size > 0);						      \
+    } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+   This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+  {
+    char *lo;
+    char *hi;
+  } stack_node;
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+   log(MAX_THRESH)).  Since total_elements has type size_t, we get as
+   upper bound for log (total_elements):
+   bits per byte (CHAR_BIT) * sizeof(size_t).  */
+#define STACK_SIZE	(CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high)	((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define	POP(low, high)	((void) (--top, (low = top->lo), (high = top->hi)))
+#define	STACK_NOT_EMPTY	(stack < top)
+
+
+/* Order size using quicksort.  This implementation incorporates
+   four optimizations discussed in Sedgewick:
+
+   1. Non-recursive, using an explicit stack of pointer that store the
+      next array partition to sort.  To save time, this maximum amount
+      of space required to store an array of SIZE_MAX is allocated on the
+      stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
+      only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+      Pretty cheap, actually.
+
+   2. Chose the pivot element using a median-of-three decision tree.
+      This reduces the probability of selecting a bad pivot value and
+      eliminates certain extraneous comparisons.
+
+   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+      insertion sort to order the MAX_THRESH items within each partition.
+      This is a big win, since insertion sort is faster for small, mostly
+      sorted array segments.
+
+   4. The larger of the two sub-partitions is always pushed onto the
+      stack first, with the algorithm then concentrating on the
+      smaller partition.  This *guarantees* no more than log (total_elems)
+      stack size is needed (actually O(1) in this case)!  */
+
+void
+_quicksort (void *const pbase, size_t total_elems, size_t size,
+	    __compar_d_fn_t cmp, void *arg)
+{
+  char *base_ptr = (char *) pbase;
+
+  const size_t max_thresh = MAX_THRESH * size;
+
+  if (total_elems == 0)
+    /* Avoid lossage with unsigned arithmetic below.  */
+    return;
+
+  if (total_elems > MAX_THRESH)
+    {
+      char *lo = base_ptr;
+      char *hi = &lo[size * (total_elems - 1)];
+      stack_node stack[STACK_SIZE];
+      stack_node *top = stack;
+
+      PUSH (NULL, NULL);
+
+      while (STACK_NOT_EMPTY)
+        {
+          char *left_ptr;
+          char *right_ptr;
+
+	  /* Select median value from among LO, MID, and HI. Rearrange
+	     LO and HI so the three values are sorted. This lowers the
+	     probability of picking a pathological pivot value and
+	     skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+	     the while loops. */
+
+	  char *mid = lo + size * ((hi - lo) / size >> 1);
+
+	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
+	    SWAP (mid, lo, size);
+	  if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
+	    SWAP (mid, hi, size);
+	  else
+	    goto jump_over;
+	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
+	    SWAP (mid, lo, size);
+	jump_over:;
+
+	  left_ptr  = lo + size;
+	  right_ptr = hi - size;
+
+	  /* Here's the famous ``collapse the walls'' section of quicksort.
+	     Gotta like those tight inner loops!  They are the main reason
+	     that this algorithm runs much faster than others. */
+	  do
+	    {
+	      while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
+		left_ptr += size;
+
+	      while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
+		right_ptr -= size;
+
+	      if (left_ptr < right_ptr)
+		{
+		  SWAP (left_ptr, right_ptr, size);
+		  if (mid == left_ptr)
+		    mid = right_ptr;
+		  else if (mid == right_ptr)
+		    mid = left_ptr;
+		  left_ptr += size;
+		  right_ptr -= size;
+		}
+	      else if (left_ptr == right_ptr)
+		{
+		  left_ptr += size;
+		  right_ptr -= size;
+		  break;
+		}
+	    }
+	  while (left_ptr <= right_ptr);
+
+          /* Set up pointers for next iteration.  First determine whether
+             left and right partitions are below the threshold size.  If so,
+             ignore one or both.  Otherwise, push the larger partition's
+             bounds on the stack and continue sorting the smaller one. */
+
+          if ((size_t) (right_ptr - lo) <= max_thresh)
+            {
+              if ((size_t) (hi - left_ptr) <= max_thresh)
+		/* Ignore both small partitions. */
+                POP (lo, hi);
+              else
+		/* Ignore small left partition. */
+                lo = left_ptr;
+            }
+          else if ((size_t) (hi - left_ptr) <= max_thresh)
+	    /* Ignore small right partition. */
+            hi = right_ptr;
+          else if ((right_ptr - lo) > (hi - left_ptr))
+            {
+	      /* Push larger left partition indices. */
+              PUSH (lo, right_ptr);
+              lo = left_ptr;
+            }
+          else
+            {
+	      /* Push larger right partition indices. */
+              PUSH (left_ptr, hi);
+              hi = right_ptr;
+            }
+        }
+    }
+
+  /* Once the BASE_PTR array is partially sorted by quicksort the rest
+     is completely sorted using insertion sort, since this is efficient
+     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+     of the array to sort, and END_PTR points at the very last element in
+     the array (*not* one beyond it!). */
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+  {
+    char *const end_ptr = &base_ptr[size * (total_elems - 1)];
+    char *tmp_ptr = base_ptr;
+    char *thresh = min(end_ptr, base_ptr + max_thresh);
+    char *run_ptr;
+
+    /* Find smallest element in first threshold and place it at the
+       array's beginning.  This is the smallest array element,
+       and the operation speeds up insertion sort's inner loop. */
+
+    for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+      if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
+        tmp_ptr = run_ptr;
+
+    if (tmp_ptr != base_ptr)
+      SWAP (tmp_ptr, base_ptr, size);
+
+    /* Insertion sort, running from left-hand-side up to right-hand-side.  */
+
+    run_ptr = base_ptr + size;
+    while ((run_ptr += size) <= end_ptr)
+      {
+	tmp_ptr = run_ptr - size;
+	while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
+	  tmp_ptr -= size;
+
+	tmp_ptr += size;
+        if (tmp_ptr != run_ptr)
+          {
+            char *trav;
+
+	    trav = run_ptr + size;
+	    while (--trav >= run_ptr)
+              {
+                char c = *trav;
+                char *hi, *lo;
+
+                for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+                  *hi = *lo;
+                *hi = c;
+              }
+          }
+      }
+  }
+}
diff --git a/libctf/swap.h b/libctf/swap.h
index 06a9330181..e75e8d408a 100644
--- a/libctf/swap.h
+++ b/libctf/swap.h
@@ -29,13 +29,13 @@ 
 
 /* Provide our own versions of the byteswap functions.  */
 inline uint16_t
-bswap_16(uint16_t v)
+bswap_16 (uint16_t v)
 {
   return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
 }
 
 inline uint32_t
-bswap_32(uint32_t v)
+bswap_32 (uint32_t v)
 {
   return (  ((v & 0xff000000) >> 24)
 	  | ((v & 0x00ff0000) >>  8)
@@ -44,7 +44,13 @@  bswap_32(uint32_t v)
 }
 
 inline uint64_t
-bswap_64(uint64_t v)
+bswap_identity_64 (uint64_t v)
+{
+  return v;
+}
+
+inline uint64_t
+bswap_64 (uint64_t v)
 {
   return (  ((v & 0xff00000000000000ULL) >> 56)
 	  | ((v & 0x00ff000000000000ULL) >> 40)