[libctf] Fix a number of build problems found on Solaris and NetBSD

Message ID 8736kw2h5b.fsf@esperi.org.uk
State New
Headers show
Series
  • [libctf] Fix a number of build problems found on Solaris and NetBSD
Related show

Commit Message

Nick Alcock May 30, 2019, 1:42 p.m.
- 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.
---
 binutils/ChangeLog    |   6 +
 binutils/objdump.c    |   3 -
 binutils/readelf.c    |   3 -
 include/ChangeLog     |   7 +
 include/ctf-api.h     |  12 +-
 libctf/ChangeLog      |  67 +++++++++
 libctf/Makefile.am    |   9 +-
 libctf/Makefile.in    |  24 +++-
 libctf/aclocal.m4     |   1 +
 libctf/config.h.in    |  22 +++
 libctf/configure      | 322 +++++++++++++++++++++++++++++++++++++++++-
 libctf/configure.ac   |   6 +-
 libctf/ctf-archive.c  |   8 +-
 libctf/ctf-create.c   |  50 ++++---
 libctf/ctf-decls.h    |  37 +++++
 libctf/ctf-dump.c     |  20 +--
 libctf/ctf-endian.h   |  37 +++++
 libctf/ctf-impl.h     |   5 +-
 libctf/ctf-labels.c   |   8 +-
 libctf/ctf-lookup.c   |   4 +-
 libctf/ctf-open-bfd.c |  11 +-
 libctf/ctf-open.c     |  13 +-
 libctf/ctf-types.c    |  48 +++----
 libctf/ctf-util.c     |   4 +-
 libctf/qsort_r.c      | 259 +++++++++++++++++++++++++++++++++
 libctf/swap.h         |  12 +-
 26 files changed, 883 insertions(+), 115 deletions(-)
 create mode 100644 libctf/ctf-decls.h
 create mode 100644 libctf/ctf-endian.h
 create mode 100644 libctf/qsort_r.c

This patch assumes that commit
90bd54236cb8b1c31c3662977159be971044c20d is reverted first. (It, and
commit e33f2313bf63b77763739732be14b469b4b647b7, are unnecessary now
that commit 9698cf9b1c485edbbeabc9f65bfd0fdef92e3854 is in.)

-- 
2.21.0.237.gd0cfaa883d

Comments

Szabolcs Nagy May 30, 2019, 2:21 p.m. | #1
On 30/05/2019 14:42, Nick Alcock wrote:
> - 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.

> ---

>  binutils/ChangeLog    |   6 +

>  binutils/objdump.c    |   3 -

>  binutils/readelf.c    |   3 -

>  include/ChangeLog     |   7 +

>  include/ctf-api.h     |  12 +-

>  libctf/ChangeLog      |  67 +++++++++

>  libctf/Makefile.am    |   9 +-

>  libctf/Makefile.in    |  24 +++-

>  libctf/aclocal.m4     |   1 +

>  libctf/config.h.in    |  22 +++

>  libctf/configure      | 322 +++++++++++++++++++++++++++++++++++++++++-

>  libctf/configure.ac   |   6 +-

>  libctf/ctf-archive.c  |   8 +-

>  libctf/ctf-create.c   |  50 ++++---

>  libctf/ctf-decls.h    |  37 +++++

>  libctf/ctf-dump.c     |  20 +--

>  libctf/ctf-endian.h   |  37 +++++

>  libctf/ctf-impl.h     |   5 +-

>  libctf/ctf-labels.c   |   8 +-

>  libctf/ctf-lookup.c   |   4 +-

>  libctf/ctf-open-bfd.c |  11 +-

>  libctf/ctf-open.c     |  13 +-

>  libctf/ctf-types.c    |  48 +++----

>  libctf/ctf-util.c     |   4 +-

>  libctf/qsort_r.c      | 259 +++++++++++++++++++++++++++++++++

>  libctf/swap.h         |  12 +-

>  26 files changed, 883 insertions(+), 115 deletions(-)

>  create mode 100644 libctf/ctf-decls.h

>  create mode 100644 libctf/ctf-endian.h

>  create mode 100644 libctf/qsort_r.c

> 

> This patch assumes that commit

> 90bd54236cb8b1c31c3662977159be971044c20d is reverted first. (It, and

> commit e33f2313bf63b77763739732be14b469b4b647b7, are unnecessary now

> that commit 9698cf9b1c485edbbeabc9f65bfd0fdef92e3854 is in.)

> 


fwiw i applied the patch on top of
9698cf9b1c485edbbeabc9f65bfd0fdef92e3854
and it fixes my build issue.

i cannot apply it on top of master, but i'd
like to fix the build issue soon, so our
builders can continue testing binutils.
Nick Alcock May 30, 2019, 2:46 p.m. | #2
On 30 May 2019, Szabolcs Nagy said:
> i cannot apply it on top of master, but i'd

> like to fix the build issue soon, so our

> builders can continue testing binutils.


The variant that applies on top of master has literally a
one-space-character difference outside ChangeLogs, fwiw, and that only
in the context of one hunk:

  diff --git a/binutils/objdump.c b/binutils/objdump.c
  --- a/binutils/objdump.c
@@ -127,7 +127,7 @@
 @@
  shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
  {
-   buf->cts_name = SECTION_NAME(shdr);
+   buf->cts_name = SECTION_NAME (shdr);
 -  buf->cts_type = shdr->sh_type;
 -  buf->cts_flags = shdr->sh_flags;
    buf->cts_size = shdr->sh_size;

The binutils/objdump.c parts need approval, but once I have that
approval I'll push whatever version is appropriate given the state of
master at the time (even if this makes it a bit harder to revert Nick's
no-libctf-when-no-ELF patches, the conflict above is trivial to
resolve).
Nick Alcock May 30, 2019, 3:09 p.m. | #3
On 30 May 2019, Nick Alcock verbalised:

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


This needs approval from someone with global write privs for the
binutils/objdump.c part. (I don't believe the include/ctf-api.h parts
need approval, but it would be nice for someone to glance at them
anyway.)

(Note: the objdump hunk will have a one-byte change to context if
applied before the reversion of Nick's
90bd54236cb8b1c31c3662977159be971044c20d, but no change in semantics.)
Alan Modra May 31, 2019, 12:19 a.m. | #4
On Thu, May 30, 2019 at 04:09:25PM +0100, Nick Alcock wrote:
> This needs approval from someone with global write privs for the

> binutils/objdump.c part.


OK, but you're fine without global approval.  Changing the library API
is up to your discretion as the library maintainer, and that obviously
requires updates elsewhere.

-- 
Alan Modra
Australia Development Lab, IBM
Jose E. Marchesi May 31, 2019, 9:13 a.m. | #5
> This needs approval from someone with global write privs for the

    > binutils/objdump.c part.

    
    OK, but you're fine without global approval.  Changing the library API
    is up to your discretion as the library maintainer, and that obviously
    requires updates elsewhere.

I just pushed the patch in behalf of Nick.
Thanks.
John Marshall May 31, 2019, 12:24 p.m. | #6
On 31 May 2019, at 10:13, Jose E. Marchesi <jose.marchesi@oracle.com> wrote:
> I just pushed the patch in behalf of Nick.


This has improved the build on macOS (previously it was failing due to <endian.h> and off64_t), but the added qsort_r() remains problematic:

gcc -DHAVE_CONFIG_H -I. -I../../../binutils-gdb/libctf  -D_GNU_SOURCE -I../../../binutils-gdb/libctf -I../../../binutils-gdb/libctf/../include -I../../../binutils-gdb/libctf/../bfd -I../bfd  -std=gnu99 -Wall -W -Wall -Wno-narrowing -Wwrite-strings -Wmissing-format-attribute -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -pedantic -Wno-long-long  -I../../../binutils-gdb/libctf/../zlib -g -O2 -MT qsort_r.o -MD -MP -MF .deps/qsort_r.Tpo -c -o qsort_r.o ../../../binutils-gdb/libctf/qsort_r.c
../../../binutils-gdb/libctf/qsort_r.c:99:1: error: conflicting types for 'qsort_r'
_quicksort (void *const pbase, size_t total_elems, size_t size,
^
../../../binutils-gdb/libctf/qsort_r.c:33:21: note: expanded from macro '_quicksort'
# define _quicksort qsort_r
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/stdlib.h:325:7: note:
previous declaration is here
void     qsort_r(void *__base, size_t __nel, size_t __width, void *,
^

MacOS (and e.g. it appears FreeBSD, but there it is possibly hidden by a __BSD_VISIBLE define) declares a qsort_r() function with a different signature:

	void
	qsort_r(void *base, size_t nel, size_t width, void *thunk,
		int (*compar)(void *, const void *, const void *));

i.e. the extra void* argument is added before the comparison function rather than after, and similarly in the callback's parameters.

The generated libctf/config.h contains "#define HAVE_DECL_QSORT_R 1", so it's a bit surprising that it tries to build qsort_r.c at all. I suspect AC_LIBOBJ([qsort_r]) should be inside a conditional. However, even if qsort_r.o were properly omitted, trying to use the system qsort_r() with its different signature won't work.

Changing the identifier (e.g. to qsort_r_bork) in the four libctf/*.[ch] files it appears in leads to a working compilation.


Incidentally, this warning seems accurate in saying this free() should be further down:

../../../binutils-gdb/libctf/ctf-dump.c:276:13: warning: variable 'bit' is uninitialized when used here

    John
Nick Alcock June 1, 2019, 10:16 a.m. | #7
On 31 May 2019, John Marshall outgrape:

> ../../../binutils-gdb/libctf/qsort_r.c:33:21: note: expanded from macro '_quicksort'

> # define _quicksort qsort_r

> ^

> /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/stdlib.h:325:7: note:

> previous declaration is here

> void     qsort_r(void *__base, size_t __nel, size_t __width, void *,

> ^

>

> MacOS (and e.g. it appears FreeBSD, but there it is possibly hidden by a __BSD_VISIBLE define) declares a qsort_r() function with a different signature:

>

> 	void

> 	qsort_r(void *base, size_t nel, size_t width, void *thunk,

> 		int (*compar)(void *, const void *, const void *));

>

> i.e. the extra void* argument is added before the comparison function rather than after, and similarly in the callback's parameters.

>

> The generated libctf/config.h contains "#define HAVE_DECL_QSORT_R 1", so it's a bit surprising that it tries to build qsort_r.c at all. I suspect AC_LIBOBJ([qsort_r]) should be inside a conditional. However, even if qsort_r.o were properly omitted, trying to use the system qsort_r() with its different signature won't work.


Quite. I didn't realise qsort_r() was so nonportable that qsort_r()s
with entirely different type signatures were out there.

> Changing the identifier (e.g. to qsort_r_bork) in the four libctf/*.[ch] files it appears in leads to a working compilation.


Downside: this can be quite a *large* sort. Doing this would mean
eschewing the system qsort() at all times. Do we want to do that? (Is it
actually going to be any faster than gnulib's?)

> Incidentally, this warning seems accurate in saying this free() should be further down:

>

> ../../../binutils-gdb/libctf/ctf-dump.c:276:13: warning: variable 'bit' is uninitialized when used here


Ugh. Sorry, this was the most recently-written code in libctf and
sometimes that shows: in this case some late code motion on my part
shoved the free some lines up, to before its first allocation. (Freeing
a garbage pointer would cause obvious problems in real use, of course,
but the code that generates the function info section is still under
development...)

Will fix, of course. (I wonder why I haven't seen this warning with any
of the GCCs I've compiled it with... oh, this is one of the middle-end
warnings whose appearance depends on fine details of the optimizer,
right? That might explain it.)
Sebastian Huber June 3, 2019, 9:10 a.m. | #8
Hello Jose,

commit a0486bac41d6ce47f27795a5abbca5cc53ddba00
Author: Jose E. Marchesi <jose.marchesi@oracle.com>
Date:   Fri May 31 11:10:51 2019 +0200

     libctf: fix a number of build problems found on Solaris and NetBSD

breaks the build on FreeBSD 12:

/usr/bin/cc -O2 -pipe -fbracket-depth=1024 
-I/usr/home/user/rtems-source-builder/rtems/build/tmp/sb-user/6/rtems-aarch64.bset/usr/local/rtems/5/include 
-DHAVE_CONFIG_H -I. 
-I../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf -D_GNU_SOURCE 
-I../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf 
-I../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/../include 
-I../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/../bfd 
-I../bfd   -std=gnu99 -Wall -W -Wall -Wno-narrowing -Wwrite-strings 
-Wmissing-format-attribute -Wstrict-prototypes -Wmissing-prototypes 
-Wold-style-definition -pedantic -Wno-long-long 
-I../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/../zlib -MT 
qsort_r.o -MD -MP -MF .deps/qsort_r.Tpo -c -o qsort_r.o 
../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/qsort_r.c
../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/qsort_r.c:99:1: 
error: conflicting types for 'qsort_r'
_quicksort (void *const pbase, size_t total_elems, size_t size,
^
../../sourceware-mirror-binutils-gdb-4f6d070adb/libctf/qsort_r.c:33:21: 
note: expanded from macro '_quicksort'
# define _quicksort qsort_r
                     ^
/usr/include/stdlib.h:300:7: note: previous declaration is here
void     qsort_r(void *, size_t, size_t, void *,
          ^
1 error generated.

-- 
Sebastian Huber, embedded brains GmbH

Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone   : +49 89 189 47 41-16
Fax     : +49 89 189 47 41-09
E-Mail  : sebastian.huber@embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.
John Marshall June 3, 2019, 12:09 p.m. | #9
On 1 Jun 2019, at 11:16, Nick Alcock <nick.alcock@oracle.com> wrote:
> On 31 May 2019, John Marshall outgrape:

>> Changing the identifier (e.g. to qsort_r_bork) in the four libctf/*.[ch] files it appears in leads to a working compilation.

> 

> Downside: this can be quite a *large* sort. Doing this would mean

> eschewing the system qsort() at all times. Do we want to do that? (Is it

> actually going to be any faster than gnulib's?)


This comment about qsort_r_bork() was mostly to confirm that once this qsort_r() problem is fixed, there are no further issues on macOS.

I suppose your options would be:

* just use the system qsort() with a global
* code ctf-archive.c etc in terms of a xqsort_r() or so, that is the system qsort_r() if it has the expected signature or qsort_r.c's otherwise
* ...or that also calls the macOS/BSD qsort_r() with a shim around the compare function to rearrange the arguments
* play preprocessor games in ctf-archive.c etc so that compare functions have their parameters in the order the system qsort_r() (if any) expects

>> Incidentally, this warning seems accurate in saying this free() should be further down:

>> ../../../binutils-gdb/libctf/ctf-dump.c:276:13: warning: variable 'bit' is uninitialized when used here

> 

> Will fix, of course. (I wonder why I haven't seen this warning with any

> of the GCCs I've compiled it with...


Despite the "gcc" command name, this warning came from Clang. Sometimes you get a useful warning from one compiler, sometimes from the other one... :-)

    John
Nick Alcock June 3, 2019, 7:24 p.m. | #10
On 3 Jun 2019, John Marshall verbalised:

> * just use the system qsort() with a global

> * code ctf-archive.c etc in terms of a xqsort_r() or so, that is the system qsort_r() if it has the expected signature or qsort_r.c's otherwise

> * ...or that also calls the macOS/BSD qsort_r() with a shim around the compare function to rearrange the arguments

> * play preprocessor games in ctf-archive.c etc so that compare functions have their parameters in the order the system qsort_r() (if any) expects


I'm doing the second, using AC_RUN_IFELSE to verify the order of
parameters, not just the existence of a declaration, and pulling in a
replacement if that fails.  (Unfortunately we have to use AC_RUN_IFELSE
because we cannot rely on prototype errors of this nature being fatal to
the compilation, and there is no portable way to make them fatal. So
we also fall back to the gnulib implementation when cross-compiling.)

Verified functional with the patch below on FreeBSD, mingw, Solaris, and
x86_64-pc-linux-gnu. (Just doing some other regtests before submitting.)

I cannot test MacOS X, I'm afraid, but it should work there too, since
it seems to have the same problem as FreeBSD.

>>> Incidentally, this warning seems accurate in saying this free() should be further down:

>>> ../../../binutils-gdb/libctf/ctf-dump.c:276:13: warning: variable 'bit' is uninitialized when used here

>> 

>> Will fix, of course. (I wonder why I haven't seen this warning with any

>> of the GCCs I've compiled it with...

>

> Despite the "gcc" command name, this warning came from Clang. Sometimes you get a useful warning from one compiler, sometimes from the other one... :-)


Aha, that explains it. I'll make sure to test-compile with clang, then.

Thanks for the heads-up. (And sorry for the delay: reviving my FreeBSD
installation took longer than I'd hoped.)

(Note: the patch below contains a file rename: use 'git apply' or 'git
am' to apply it, not patch(1).)


From 0af8b01cb3c50f80b1d7a638c96316d33dac3530 Mon Sep 17 00:00:00 2001
From: Nick Alcock <nick.alcock@oracle.com>

Date: Mon, 3 Jun 2019 14:02:09 +0100
Subject: [PATCH] libctf: look for a qsort_r that functions properly

We cannot just look for any declaration of qsort_r, because some
operating systems have a qsort_r that has a different prototype
but which still has a pair of pointers in the right places (the last two
args are interchanged), so we cannot rely on compilation errors to flag
up a problem.

So, instead, use AC_RUN_IFELSE to check for the function of qsort_r(),
passing function pointers in to both args and making sure that we never
actually dereference the arg pointer.

This may still be problematic on systems with different representations
for function pointers and integer pointers, but even then we should get
the right result from configure (there just might be an ugly coredump
too).

(Now we are not using AC_LIBOBJ any more, we can use a better name for
the qsort_r replacement as well.)

libctf/
	* qsort_r.c: Rename to...
	* ctf-qsort_r.c: ... this.
	(_quicksort): Define to ctf_qsort_r.
	* ctf-decls.h (qsort_r): Remove.
	(ctf_qsort_r): Add.
	* Makefile.am (libctf_a_LIBADD): Remove.
	(libctf_a_SOURCES): New, add ctf-qsort_r.c.
	* ctf-archive.c (ctf_arc_write): Call ctf_qsort_r, not qsort_r.
	* ctf-create.c (ctf_update): Likewise.
	* configure.ac: Check for specific qsort_r that functions properly,
	not just for any declaration of it.
	* Makefile.in: Regenerate.
	* config.h.in: Likewise.
	* configure: Likewise.
---
 libctf/ChangeLog                    |  17 ++++
 libctf/Makefile.am                  |   4 +-
 libctf/Makefile.in                  |  29 ++++---
 libctf/config.h.in                  |   7 +-
 libctf/configure                    | 115 +++++++++++++++-------------
 libctf/configure.ac                 |  30 +++++++-
 libctf/ctf-archive.c                |   9 ++-
 libctf/ctf-create.c                 |   2 +-
 libctf/ctf-decls.h                  |  16 +++-
 libctf/{qsort_r.c => ctf-qsort_r.c} |   2 +-
 11 files changed, 152 insertions(+), 81 deletions(-)
 rename libctf/{qsort_r.c => ctf-qsort_r.c} (99%)

diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index d059d58d19..25ce9b3e61 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,20 @@
+2019-06-03  Nick Alcock  <nick.alcock@oracle.com>
+
+	* qsort_r.c: Rename to...
+	* ctf-qsort_r.c: ... this.
+	(_quicksort): Define to ctf_qsort_r.
+	* ctf-decls.h (qsort_r): Remove.
+	(ctf_qsort_r): Add.
+	* Makefile.am (libctf_a_LIBADD): Remove.
+	(libctf_a_SOURCES): New, add ctf-qsort_r.c.
+	* ctf-archive.c (ctf_arc_write): Call ctf_qsort_r, not qsort_r.
+	* ctf-create.c (ctf_update): Likewise.
+	* configure.ac: Check for specific qsort_r that functions properly,
+	not just for any declaration of it.
+	* Makefile.in: Regenerate.
+	* config.h.in: Likewise.
+	* configure: Likewise.
+
 2019-05-29  Nick Alcock  <nick.alcock@oracle.com>
 
 	* Makefile.am (ZLIB): New.
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 49c9f5280a..926c9919c5 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -35,4 +35,6 @@ 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)
+if NEED_CTF_QSORT_R
+libctf_a_SOURCES += ctf-qsort_r.c
+endif
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index c2cada6616..4fea156c44 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -104,6 +104,7 @@ POST_INSTALL = :
 NORMAL_UNINSTALL = :
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
+@NEED_CTF_QSORT_R_TRUE@am__append_1 = ctf-qsort_r.c
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
@@ -128,12 +129,17 @@ 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_DEPENDENCIES = $(LIBOBJS)
+libctf_a_LIBADD =
+am__libctf_a_SOURCES_DIST = 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 \
+	ctf-qsort_r.c
+@NEED_CTF_QSORT_R_TRUE@am__objects_1 = ctf-qsort_r.$(OBJEXT)
 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) \
 	ctf-open.$(OBJEXT) ctf-open-bfd.$(OBJEXT) ctf-subr.$(OBJEXT) \
-	ctf-types.$(OBJEXT) ctf-util.$(OBJEXT)
+	ctf-types.$(OBJEXT) ctf-util.$(OBJEXT) $(am__objects_1)
 libctf_a_OBJECTS = $(am_libctf_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -164,7 +170,7 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libctf_a_SOURCES)
-DIST_SOURCES = $(libctf_a_SOURCES)
+DIST_SOURCES = $(am__libctf_a_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -196,7 +202,7 @@ 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 \
-	ChangeLog qsort_r.c
+	ChangeLog
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -323,11 +329,10 @@ 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@ $(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)
+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 \
+	$(am__append_1)
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -396,7 +401,6 @@ 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@
@@ -407,6 +411,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-lookup.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-open-bfd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-open.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-qsort_r.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-subr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-types.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-util.Po@am__quote@
@@ -687,7 +692,7 @@ clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf $(DEPDIR) ./$(DEPDIR)
+	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-tags
@@ -735,7 +740,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf $(DEPDIR) ./$(DEPDIR)
+	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/libctf/config.h.in b/libctf/config.h.in
index 0ecb5bb721..dff5501609 100644
--- a/libctf/config.h.in
+++ b/libctf/config.h.in
@@ -9,10 +9,6 @@
 /* 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
 
@@ -31,6 +27,9 @@
 /* Define to 1 if you have the `pread' function. */
 #undef HAVE_PREAD
 
+/* Whether a qsort_r exists with a void *arg as its last arg. */
+#undef HAVE_QSORT_R_ARG_LAST
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
diff --git a/libctf/configure b/libctf/configure
index 4fb44eb2cc..c59e4c6abc 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -624,6 +624,8 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+NEED_CTF_QSORT_R_FALSE
+NEED_CTF_QSORT_R_TRUE
 zlibinc
 zlibdir
 ac_libctf_warn_cflags
@@ -1809,52 +1811,6 @@ $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.
@@ -6401,16 +6357,65 @@ _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
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for qsort_r with arg last" >&5
+$as_echo_n "checking for qsort_r with arg last... " >&6; }
+if ${ac_cv_libctf_qsort_r_arg_last+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_libctf_qsort_r_arg_last=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+  int do_not_call (const void *a, const void *b, void *arg)
+  {
+    return (a < b);
+  }
+  static int works = 0;
+  int conftest_compar (const void *a, const void *b, void *arg)
+  {
+    if (arg == do_not_call)
+      works = 1;
+    return (a < b);
+  }
+  int foo[2] = { 0, 1 };
+int
+main ()
+{
+qsort_r (foo, 2, sizeof (int), conftest_compar, do_not_call);
+   return (works == 0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_libctf_qsort_r_arg_last=yes
 else
-  ac_have_decl=0
+  ac_cv_libctf_qsort_r_arg_last=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libctf_qsort_r_arg_last" >&5
+$as_echo "$ac_cv_libctf_qsort_r_arg_last" >&6; }
+
+if test $ac_cv_libctf_qsort_r_arg_last = yes; then
+
+$as_echo "#define HAVE_QSORT_R_ARG_LAST 1" >>confdefs.h
+
+fi
+ if test "${ac_cv_libctf_qsort_r_arg_last}" != yes; then
+  NEED_CTF_QSORT_R_TRUE=
+  NEED_CTF_QSORT_R_FALSE='#'
+else
+  NEED_CTF_QSORT_R_TRUE='#'
+  NEED_CTF_QSORT_R_FALSE=
 fi
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_QSORT_R $ac_have_decl
-_ACEOF
 
 case " $LIBOBJS " in
   *" qsort_r.$ac_objext "* ) ;;
@@ -6561,6 +6566,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 
+if test -z "${NEED_CTF_QSORT_R_TRUE}" && test -z "${NEED_CTF_QSORT_R_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_CTF_QSORT_R\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 
 : "${CONFIG_STATUS=./config.status}"
 ac_write_fail=0
diff --git a/libctf/configure.ac b/libctf/configure.ac
index 8fd5388d2a..185aa94378 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -90,7 +90,35 @@ fi
 AC_C_BIGENDIAN
 AC_CHECK_HEADERS(byteswap.h endian.h)
 AC_CHECK_FUNCS(pread)
-AC_CHECK_DECLS([qsort_r])
+
+AC_CACHE_CHECK([for qsort_r with arg last], ac_cv_libctf_qsort_r_arg_last,
+[AC_RUN_IFELSE(
+  [AC_LANG_PROGRAM(
+  [#include <stdlib.h>
+  int do_not_call (const void *a, const void *b, void *arg)
+  {
+    return (a < b);
+  }
+  static int works = 0;
+  int conftest_compar (const void *a, const void *b, void *arg)
+  {
+    if (arg == do_not_call)
+      works = 1;
+    return (a < b);
+  }
+  int foo[[2]] = { 0, 1 };],
+  [qsort_r (foo, 2, sizeof (int), conftest_compar, do_not_call);
+   return (works == 0);])],
+  [ac_cv_libctf_qsort_r_arg_last=yes],
+  [ac_cv_libctf_qsort_r_arg_last=no],
+  [ac_cv_libctf_qsort_r_arg_last=no])])
+
+if test $ac_cv_libctf_qsort_r_arg_last = yes; then
+  AC_DEFINE([HAVE_QSORT_R_ARG_LAST], 1,
+	    [Whether a qsort_r exists with a void *arg as its last arg.])
+fi
+AM_CONDITIONAL(NEED_CTF_QSORT_R, test "${ac_cv_libctf_qsort_r_arg_last}" != yes)
+
 AC_LIBOBJ([qsort_r])
 
 AC_CONFIG_FILES(Makefile)
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index a238edb66b..90cd020b78 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -169,10 +169,11 @@ ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
       modent++;
     }
 
-  qsort_r ((ctf_archive_modent_t *) ((char *) archdr
-				     + sizeof (struct ctf_archive)),
-	   le64toh (archdr->ctfa_nfiles),
-	   sizeof (struct ctf_archive_modent), sort_modent_by_name, nametbl);
+  ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
+					 + sizeof (struct ctf_archive)),
+	       le64toh (archdr->ctfa_nfiles),
+	       sizeof (struct ctf_archive_modent), sort_modent_by_name,
+	       nametbl);
 
    /* Now the name table.  */
 
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 227f62d8fd..3beed88712 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -344,7 +344,7 @@ ctf_update (ctf_file_t *fp)
     }
   assert (i == nvars);
 
-  qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var, s0);
+  ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var, s0);
   t += sizeof (ctf_varent_t) * nvars;
 
   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
diff --git a/libctf/ctf-decls.h b/libctf/ctf-decls.h
index 5e9ede4809..1f8aab11e4 100644
--- a/libctf/ctf-decls.h
+++ b/libctf/ctf-decls.h
@@ -22,12 +22,22 @@
 
 #include "config.h"
 
-#if !HAVE_DECL_QSORT_R
 #include <stddef.h>
-void qsort_r (void *base, size_t nmemb, size_t size,
+#if HAVE_QSORT_R_ARG_LAST
+#include <stdlib.h>
+
+inline void
+ctf_qsort_r (void *base, size_t nmemb, size_t size,
+	     int (*compar)(const void *, const void *, void *),
+	     void *arg)
+{
+  qsort_r (base, nmemb, size, compar, arg);
+}
+#else
+void ctf_qsort_r (void *base, size_t nmemb, size_t size,
 	      int (*compar)(const void *, const void *, void *),
 	      void *arg);
-#endif /* !HAVE_DECL_QSORT_R */
+#endif /* !HAVE_QSORT_R_ARG_LAST */
 
 #undef MAX
 #undef MIN
diff --git a/libctf/qsort_r.c b/libctf/ctf-qsort_r.c
similarity index 99%
rename from libctf/qsort_r.c
rename to libctf/ctf-qsort_r.c
index 6c334fdaf3..6cb221d6f5 100644
--- a/libctf/qsort_r.c
+++ b/libctf/ctf-qsort_r.c
@@ -30,7 +30,7 @@
 #include "ctf-decls.h"
 
 #ifndef _LIBC
-# define _quicksort qsort_r
+# define _quicksort ctf_qsort_r
 # define __compar_d_fn_t compar_d_fn_t
 typedef int (*compar_d_fn_t) (const void *, const void *, void *);
 #endif
-- 
2.21.0.237.gd0cfaa883d

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)