Patchwork 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)

login
register
mail settings
Submitter Nick Alcock
Date May 29, 2019, 9:45 p.m.
Message ID <87d0k13pf4.fsf@esperi.org.uk>
Download mbox | patch
Permalink /patch/32913/
State New
Headers show

Comments

Nick Alcock - May 29, 2019, 9:45 p.m.
[Do we want to Cc: the gdb buildbot on this? I presume not: dropped from Cc:.]

On 29 May 2019, Kamil Rytarowski uttered the following:

> 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).

It is based on commit 9698cf9b1c485edbbeabc9f65bfd0fdef92e3854, for what
it's worth.

> 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?

Unlikely. This definition is only used for platforms that don't have an
off64_t already, and is only used for the size of ctf_sect_t.offset.
Platforms on which off_t is 32-bit and without a 64-bit off_t will
presumably have a 32-bit limit on the size of their binaries, too, so it
is not a limitation to restrict section offsets to 32-bit.

(However... we don't *use* the offset field in any case. If we don't
mind losing things from the ctf_sect_t, we *could* just entirely drop
that field, and the cts_type and cts_flags as well. None are used since
the old ELF reading code was dropped.)

... yeah, I'll rejig things that way. It's easier. There's no point
going through portability trouble for a field we're not even *using*.

... found an outright bug in the process: we were sometimes failing to
set the section size when opening associated string and symbol tables.
Fixed at the same time (it was right next to a line we were removing).

>                                                        NetBSD uses the
> libctf stack from FreeBSD/SunOS for DTrace, will that be compatible with
> this GDB code?

As previously noted, the formats are incompatible (and will get more so:
there are a number of huge size reductions that can be made, all of
which are of course format changes).

I can, however, add backward-compatibility code to dynamically upgrade
the old CTF format to the new one at open time, if this seems to be
useful. (It's not too different from our format v1). I'm just skeptical
that it *is* useful, since CTF info is mostly found in OS kernels so
far, and is in a differently-named section.

... new patch (though I'm not sure you'll be able to apply it any more
than you could apply the last one). Observe lack of dependence on
off64_t :)

Still builds on Solaris. :)

Atop 9698cf9b1c485edbbeabc9f65bfd0fdef92e3854 (on the grounds that the
following two commits should be reverted as no longer necessary and
overly restrictive).

commit 3b0ccc60eff83939d8d3958c882795c0d958e3a0
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 (fixed by dropping the unused fields
      that need off64_t entirely)
    - 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.
    
    Relatedly, set cts_size in a couple of places it was missed
    (string table and symbol table loading upon ctf_bfdopen()).
    
    binutils/
            * objdump.c (make_ctfsect): Drop cts_type, cts_flags, and
            cts_offset.
            * readelf.c (shdr_to_ctf_sect): Likewise.
    include/
            * ctf-api.h (ctf_sect_t): Drop cts_type, cts_flags, and cts_offset.
            (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, 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.  Drop cts_type,
            cts_flags and cts_offset.
            (ctf_arc_write): Drop debugging dependent on the size of off_t.
            * ctf-create.c: Provide a definition of roundup if not defined.
            (ctf_create): Drop cts_type, cts_flags and cts_offset.
            (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.
            * ctf-open-bfd.c (ctf_bfdopen): Drop cts_type, cts_flags and
            cts_offset.
            (ctf_simple_open): Likewise.
            (ctf_bfdopen_ctfsect): Likewise.  Set cts_size properly.
            * Makefile.in: Regenerate.
            * aclocal.m4: Likewise.
            * config.h: Likewise.
            * configure: Likewise.
Sergio Durigan Junior - May 30, 2019, 12:54 a.m.
On Wednesday, May 29 2019, Nick Alcock wrote:

> [Do we want to Cc: the gdb buildbot on this? I presume not: dropped from Cc:.]

Everything sent to that address that doesn't follow a very specific
format is discarded.  I should updated the Reply-To/M-F-T headers
accordingly; maybe some day :-).

Thanks for taking care of the breakage, btw.
Kamil Rytarowski - May 30, 2019, 7:09 a.m.
On 29.05.2019 23:45, Nick Alcock wrote:
> [Do we want to Cc: the gdb buildbot on this? I presume not: dropped from Cc:.]
> 
> On 29 May 2019, Kamil Rytarowski uttered the following:
> 
>> 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).
> 
> It is based on commit 9698cf9b1c485edbbeabc9f65bfd0fdef92e3854, for what
> it's worth.
> 
>> 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?
> 
> Unlikely. This definition is only used for platforms that don't have an
> off64_t already, and is only used for the size of ctf_sect_t.offset.
> Platforms on which off_t is 32-bit and without a 64-bit off_t will
> presumably have a 32-bit limit on the size of their binaries, too, so it
> is not a limitation to restrict section offsets to 32-bit.
> 
> (However... we don't *use* the offset field in any case. If we don't
> mind losing things from the ctf_sect_t, we *could* just entirely drop
> that field, and the cts_type and cts_flags as well. None are used since
> the old ELF reading code was dropped.)
> 
> ... yeah, I'll rejig things that way. It's easier. There's no point
> going through portability trouble for a field we're not even *using*.
> 
> ... found an outright bug in the process: we were sometimes failing to
> set the section size when opening associated string and symbol tables.
> Fixed at the same time (it was right next to a line we were removing).
> 
>>                                                        NetBSD uses the
>> libctf stack from FreeBSD/SunOS for DTrace, will that be compatible with
>> this GDB code?
> 
> As previously noted, the formats are incompatible (and will get more so:
> there are a number of huge size reductions that can be made, all of
> which are of course format changes).
> 
> I can, however, add backward-compatibility code to dynamically upgrade
> the old CTF format to the new one at open time, if this seems to be
> useful. (It's not too different from our format v1). I'm just skeptical
> that it *is* useful, since CTF info is mostly found in OS kernels so
> far, and is in a differently-named section.
> 

We build every binary on NetBSD with CTF and it is used by DTrace.
FreeBSD additionally ported mdb from SunOS.

However there is still DWARF available always so it's not a big problem,
at least in the default environment.

> ... new patch (though I'm not sure you'll be able to apply it any more
> than you could apply the last one). Observe lack of dependence on
> off64_t :)
> 
> Still builds on Solaris. :)
> 

After an attempt to apply the patch and manual fixups of rejected chunks
(patch seems to be malformed in the inlined form), gdb builds again on
NetBSD/amd64 8.99.41.
Nick Alcock - May 30, 2019, 9:34 a.m.
On 30 May 2019, Kamil Rytarowski stated:

> On 29.05.2019 23:45, Nick Alcock wrote:
>> I can, however, add backward-compatibility code to dynamically upgrade
>> the old CTF format to the new one at open time, if this seems to be
>> useful. (It's not too different from our format v1). I'm just skeptical
>> that it *is* useful, since CTF info is mostly found in OS kernels so
>> far, and is in a differently-named section.
>> 
>
> We build every binary on NetBSD with CTF and it is used by DTrace.

Ooh, the half-written userspace CTF stuff got finished? That seems...
interesting.

(OK, it looks like I need to add v1 support, so GDB can use it, and
presumably search .SUNW_ctf for CTF sections too. I'll do that after the
next round of format adjustments, since that will include a
refactoring which will among other things make the dynamic upgrading
code a lot easier to maintain when it has lots of divergent formats to
deal with.)

> However there is still DWARF available always so it's not a big problem,
> at least in the default environment.

Hey, if NetBSD can benefit *already* if I just do a few simple bits of
work, it should do so :)

> After an attempt to apply the patch and manual fixups of rejected chunks
> (patch seems to be malformed in the inlined form),

Strange. I'll attach from now on, or send through a known-not-corruptive
mailserver as nix@esperi.org.uk or something.

(But thanks for the report! I think that means we have all known
breakages fixed.)

Patch

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index ac3f3b9a2f..ea7fd06d55 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@ 
+2019-05-29  Nick Alcock  <nick.alcock@oracle.com>
+
+	* objdump.c (make_ctfsect): Drop cts_type, cts_flags, and
+	cts_offset.
+	* readelf.c (shdr_to_ctf_sect): Likewise.
+
 2019-05-28  Nick Alcock  <nick.alcock@oracle.com>
 
 	* MAINTAINERS: Add myself as CTF maintainer.
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 156331b502..d9c8cea364 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -3223,10 +3223,7 @@  make_ctfsect (const char *name, bfd_byte *data,
   ctf_sect_t ctfsect;
 
   ctfsect.cts_name = name;
-  ctfsect.cts_type = SHT_PROGBITS;
-  ctfsect.cts_flags = 0;
   ctfsect.cts_entsize = 1;
-  ctfsect.cts_offset = 0;
   ctfsect.cts_size = size;
   ctfsect.cts_data = data;
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5ae58574fb..4c413575d7 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -13812,11 +13812,8 @@  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;
 }
diff --git a/include/ChangeLog b/include/ChangeLog
index 05083763b1..1f216b3821 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,10 @@ 
+2019-05-29  Nick Alcock  <nick.alcock@oracle.com>
+
+	* ctf-api.h (ctf_sect_t): Drop cts_type, cts_flags, and cts_offset.
+	(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..3acbc91b9a 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -43,7 +43,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.  */
@@ -60,12 +60,9 @@  struct bfd;
 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.  */
@@ -125,9 +122,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..d059d58d19 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,70 @@ 
+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, 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.  Drop cts_type,
+	cts_flags and cts_offset.
+	(ctf_arc_write): Drop debugging dependent on the size of off_t.
+	* ctf-create.c: Provide a definition of roundup if not defined.
+	(ctf_create): Drop cts_type, cts_flags and cts_offset.
+	(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.
+	* ctf-open-bfd.c (ctf_bfdopen): Drop cts_type, cts_flags and
+	cts_offset.
+	(ctf_simple_open): Likewise.
+	(ctf_bfdopen_ctfsect): Likewise.  Set cts_size properly.
+	* 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..0ecb5bb721 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
 
@@ -94,6 +104,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..4fb44eb2cc 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,52 @@  $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
 } # ac_fn_c_check_func
+
+# 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 +6085,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,12 +6153,237 @@  $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
@@ -6105,6 +6401,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 +6561,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..8fd5388d2a 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,11 @@  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_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..a238edb66b 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,16 +511,13 @@  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);
 
   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, symsect, strsect, errp);
   if (fp)
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 5409ca4bb4..227f62d8fd 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
@@ -67,12 +71,9 @@  ctf_create (int *errp)
     }
 
   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;
@@ -812,7 +813,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 +844,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 +1176,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 +1305,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 +1335,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 +1360,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 +1370,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 +1402,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 +1427,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 +1453,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 +1473,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 +1483,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 +1551,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 +1756,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 +1803,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 +1820,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 +1850,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-bfd.c b/libctf/ctf-open-bfd.c
index 5e34d12369..76b7f9d162 100644
--- a/libctf/ctf-open-bfd.c
+++ b/libctf/ctf-open-bfd.c
@@ -97,10 +97,7 @@  ctf_bfdopen (struct bfd *abfd, int *errp)
     }
 
   ctfsect.cts_name = _CTF_SECTION;
-  ctfsect.cts_type = SHT_PROGBITS;
-  ctfsect.cts_flags = 0;
   ctfsect.cts_entsize = 1;
-  ctfsect.cts_offset = 0;
   ctfsect.cts_size = bfd_section_size (abfd, ctf_asect);
   ctfsect.cts_data = contents;
 
@@ -158,10 +155,8 @@  ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
 	    }
 	  strsect.cts_data = contents;
 	  strsect.cts_name = (char *) strsect.cts_data + strhdr->sh_name;
-	  strsect.cts_type = strhdr->sh_type;
-	  strsect.cts_flags = strhdr->sh_flags;
+	  strsect.cts_size = bfd_section_size (abfd, str_asect);
 	  strsect.cts_entsize = strhdr->sh_size;
-	  strsect.cts_offset = strhdr->sh_offset;
 	  strsectp = &strsect;
 
 	  if (!bfd_malloc_and_get_section (abfd, sym_asect, &contents))
@@ -172,11 +167,9 @@  ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
 	    }
 
 	  symsect.cts_name = (char *) strsect.cts_data + symhdr->sh_name;
-	  symsect.cts_type = symhdr->sh_type;
-	  symsect.cts_flags = symhdr->sh_flags;
 	  symsect.cts_entsize = symhdr->sh_size;
+	  symsect.cts_size = bfd_section_size (abfd, sym_asect);
 	  symsect.cts_data = contents;
-	  symsect.cts_offset = symhdr->sh_offset;
 	  symsectp = &symsect;
 	}
     }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 5230d09a97..1a517a140c 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
 	    {
@@ -1170,10 +1170,7 @@  ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
   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)
     {
@@ -1317,7 +1314,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 +1337,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 +1676,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)