[v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error

Message ID 20230913095727.1420654-1-torbjorn.svensson@foss.st.com
State New
Headers
Series [v3] libctf: ctf_member_next needs to return (ssize_t)-1 on error |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

Torbjorn SVENSSON Sept. 13, 2023, 9:57 a.m. UTC
  v1 -> v2:
Changed all functions with signed interger return type to return -1 based on
comment from Alan.

v2 -> v3:
Added ctf_set_errno_signed function to return a signed -1 value based on
comment from Nick.


Ok for trunk?

---

The function ctf_member_next should return (ssize_t)-1 on
error. As the function ctf_set_errno returns (ctf_id_t)-1L and that is
then cast to "unsigned long" as it's the return type of the function,
it's not compatible and causes the value 0xffffffff to be returned on
64-bit Windows builds. As a result, the check for a negative value in
ctf_dedup_rhash_type will never be true and a resulting infinit loop is
created.

This was found testing an arm-none-eabi toolchain built with
x86_64-w64-mingw32. If the same source tree is built with
i686-w64-mingw32, everything appears to be working correctly.

libctf/
        * ctf-impl.h (ctf_set_errno_signed): New function.
        * ctf-util.c (ctf_set_errno_signed): Likewise.
        * ctf-create.c (ctf_add_enumerator): Call ctf_set_errno_signed.
        (ctf_add_funcobjt_sym): Likewise.
        (ctf_add_member_encoded): Likewise.
        (ctf_add_member_offset): Likewise.
        (ctf_add_variable): Likewise.
        (ctf_grow_ptrtab): Likewise.
        (ctf_grow_vlen): Likewise.
        (ctf_rollback): Likewise.
        (ctf_set_array): Likewise.
        (ctf_update): Likewise.
        * ctf-dedup.c (ctf_dedup_atoms_init): Likewise.
        (ctf_dedup_conflictify_unshared): Likewise.
        (ctf_dedup_detect_name_ambiguity): Likewise.
        (ctf_dedup_emit_struct_members): Likewise.
        (ctf_dedup_emit_type): Likewise.
        (ctf_dedup_hash_kind): Likewise.
        (ctf_dedup_init): Likewise.
        (ctf_dedup_mark_conflicting_hash): Likewise.
        (ctf_dedup_multiple_input_dicts): Likewise.
        (ctf_dedup_populate_mappings): Likewise.
        (ctf_dedup_record_origin): Likewise.
        (ctf_dedup_rwalk_output_mapping): Likewise.
        (ctf_dedup_walk_output_mapping): Likewise.
        * ctf-dump.c (ctf_dump_append): Likewise.
        (ctf_dump_header): Likewise.
        (ctf_dump_header_sectfield): Likewise.
        (ctf_dump_header_strfield): Likewise.
        (ctf_dump_label): Likewise.
        (ctf_dump_member): Likewise.
        (ctf_dump_str): Likewise.
        (ctf_dump_type): Likewise.
        (ctf_dump_var): Likewise.
        * ctf-labels.c (ctf_label_info): Likewise.
        (ctf_label_iter): Likewise.
        * ctf-link.c (ctf_link_add_ctf_internal): Likewise.
        (ctf_link_add_cu_mapping): Likewise.
        (ctf_link_add): Likewise.
        (ctf_link_deduplicating_one_symtypetab): Likewise.
        (ctf_link_deduplicating_per_cu): Likewise.
        (ctf_link_deduplicating_variables): Likewise.
        (ctf_link): Likewise.
        (ctf_link_one_variable): Likewise.
        * ctf-lookup.c (ctf_func_args): Likewise.
        (ctf_func_info): Likewise.
        (grow_pptrtab): Likewise.
        * ctf-open.c (ctf_cuname_set): Likewise.
        (ctf_import): Likewise.
        (ctf_parent_name_set): Likewise.
        (ctf_setmodel): Likewise.
        * ctf-serialize.c (ctf_gzwrite): Likewise.
        (ctf_serialize): Likewise.
        (symtypetab_density): Likewise.
        * ctf-string.c (ctf_str_move_pending): Likewise.
        * ctf-types.c (ctf_array_info): Likewise.
        (ctf_func_type_info): Likewise.
        (ctf_member_count): Likewise.
        (ctf_member_info): Likewise.
        (ctf_member_next): Likewise.
        (ctf_type_align): Likewise.
        (ctf_type_encoding): Likewise.
        (ctf_type_rvisit): Likewise.
        (ctf_type_size): Likewise.

Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Co-Authored-By: Yvan ROUX <yvan.roux@foss.st.com>
---
 libctf/ctf-create.c    | 66 +++++++++++++++++------------------
 libctf/ctf-dedup.c     | 78 +++++++++++++++++++++---------------------
 libctf/ctf-dump.c      | 22 ++++++------
 libctf/ctf-impl.h      |  1 +
 libctf/ctf-labels.c    |  6 ++--
 libctf/ctf-link.c      | 74 +++++++++++++++++++--------------------
 libctf/ctf-lookup.c    |  6 ++--
 libctf/ctf-open.c      | 16 ++++-----
 libctf/ctf-serialize.c | 28 +++++++--------
 libctf/ctf-string.c    |  6 ++--
 libctf/ctf-types.c     | 44 ++++++++++++------------
 libctf/ctf-util.c      | 12 +++++++
 12 files changed, 186 insertions(+), 173 deletions(-)
  

Comments

Nick Alcock Sept. 13, 2023, 6:37 p.m. UTC | #1
On 13 Sep 2023, Torbjörn SVENSSON verbalised:

> v1 -> v2:
> Changed all functions with signed interger return type to return -1 based on
> comment from Alan.
>
> v2 -> v3:
> Added ctf_set_errno_signed function to return a signed -1 value based on
> comment from Nick.
>
> Ok for trunk?

If this touches exactly those functions that return int, and fixes the
reported bug, it's good as far as I'm concerned, except for a couple of
possible comment improvements:

> +/* Store the specified error code into the CTF dict, and then return -1
> +   (CTF_ERR) for the benefit of the caller. */

It's not CTF_ERR in this case, it's just -1. Perhaps:

/* Store the specified error code into the CTF dict, and then return -1
   for the benefit of the caller, which is expected to return int,
   as opposed to ctf_id_t. */

> +int
> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
> +{
> +  fp->ctf_errno = err;
> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
> +     Windows ABI.  */
> +  return -1;
> +}

... that Windows is not really the problem here. It's more

/* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
   it will be truncated to a non--1 value on platforms on which int
   and unsigned long are different sizes.  */

perhaps? (At least, I think that's what's going on.)

This probably needs testing on a wide variety of platforms with
different type sizes. I'll add throwing this through my entire test
matrix to my todo list, and fix any bugs observed: but the basic idea
looks sound to me.
  
Torbjorn SVENSSON Sept. 13, 2023, 8:20 p.m. UTC | #2
On 2023-09-13 20:37, Nick Alcock wrote:
> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
> 
>> v1 -> v2:
>> Changed all functions with signed interger return type to return -1 based on
>> comment from Alan.
>>
>> v2 -> v3:
>> Added ctf_set_errno_signed function to return a signed -1 value based on
>> comment from Nick.
>>
>> Ok for trunk?
> 
> If this touches exactly those functions that return int, and fixes the
> reported bug, it's good as far as I'm concerned, except for a couple of
> possible comment improvements:

I've verified the calls by building binutils (with the configure flags 
mentioned in my last mail) with CFLAGS="-Wsign-conversion -Wconversion" 
and looking for any warnings related to ctf_set_errno. After applying 
this patch, there were no warnings left.

>> +/* Store the specified error code into the CTF dict, and then return -1
>> +   (CTF_ERR) for the benefit of the caller. */
> 
> It's not CTF_ERR in this case, it's just -1. Perhaps:

True, but why is then ctf_set_errno returning CTF_ERR?
I somehow want to make it obvious that it's not wrong and that it should 
*never* be CTF_ERR in the signed function or the problem would reappear.

The other possibility is to do the inverse, meaning that the 
ctf_set_errno function is returning an integer (-1) and that there is a 
function ctf_set_errno_unsigned that is calling the ctf_set_errno 
function but casting the returned value to unsigned long (or ctf_id_t). 
I personally think this solution is a bit more clean as -1 is the error 
value from all functions, just a matter if it's signed or unsigned.

I.e:

int
ctf_set_errno (ctf_dict_t *fp, int err)
{
   fp->ctf_errno = err;
   return -1;
}

unsigned long
ctf_set_errno_unsigned (ctf_dict_t *fp, int err)
{
   return (unsigned long)ctf_set_errno (fp, err);
}

I suppose the ctf_set_errno_unsigned could even be a macro in the 
ctf-impl.h header file.



> /* Store the specified error code into the CTF dict, and then return -1
>     for the benefit of the caller, which is expected to return int,
>     as opposed to ctf_id_t. */
> 

Ok!

>> +int
>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>> +{
>> +  fp->ctf_errno = err;
>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>> +     Windows ABI.  */
>> +  return -1;
>> +}
> 
> ... that Windows is not really the problem here. It's more
> 
> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>     it will be truncated to a non--1 value on platforms on which int
>     and unsigned long are different sizes.  */
> 
> perhaps? (At least, I think that's what's going on.)

The problem happens when the signed integral type is wider than unsigned 
long.

  /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
      it will be extended to a non--1 value on platforms on which int
      is larger than unsigned long are different sizes.  */

> 
> This probably needs testing on a wide variety of platforms with
> different type sizes. I'll add throwing this through my entire test
> matrix to my todo list, and fix any bugs observed: but the basic idea
> looks sound to me.

Do you want to run this full matrix before or after submitting the patch?
If it's before; when do you think you will have time to do that?


Let me know how you want to proceed.
  
Torbjorn SVENSSON Sept. 20, 2023, 5:44 p.m. UTC | #3
Ping?

On 2023-09-13 22:20, Torbjorn SVENSSON wrote:
> 
> 
> On 2023-09-13 20:37, Nick Alcock wrote:
>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>>
>>> v1 -> v2:
>>> Changed all functions with signed interger return type to return -1 
>>> based on
>>> comment from Alan.
>>>
>>> v2 -> v3:
>>> Added ctf_set_errno_signed function to return a signed -1 value based on
>>> comment from Nick.
>>>
>>> Ok for trunk?
>>
>> If this touches exactly those functions that return int, and fixes the
>> reported bug, it's good as far as I'm concerned, except for a couple of
>> possible comment improvements:
> 
> I've verified the calls by building binutils (with the configure flags 
> mentioned in my last mail) with CFLAGS="-Wsign-conversion -Wconversion" 
> and looking for any warnings related to ctf_set_errno. After applying 
> this patch, there were no warnings left.
> 
>>> +/* Store the specified error code into the CTF dict, and then return -1
>>> +   (CTF_ERR) for the benefit of the caller. */
>>
>> It's not CTF_ERR in this case, it's just -1. Perhaps:
> 
> True, but why is then ctf_set_errno returning CTF_ERR?
> I somehow want to make it obvious that it's not wrong and that it should 
> *never* be CTF_ERR in the signed function or the problem would reappear.
> 
> The other possibility is to do the inverse, meaning that the 
> ctf_set_errno function is returning an integer (-1) and that there is a 
> function ctf_set_errno_unsigned that is calling the ctf_set_errno 
> function but casting the returned value to unsigned long (or ctf_id_t). 
> I personally think this solution is a bit more clean as -1 is the error 
> value from all functions, just a matter if it's signed or unsigned.
> 
> I.e:
> 
> int
> ctf_set_errno (ctf_dict_t *fp, int err)
> {
>    fp->ctf_errno = err;
>    return -1;
> }
> 
> unsigned long
> ctf_set_errno_unsigned (ctf_dict_t *fp, int err)
> {
>    return (unsigned long)ctf_set_errno (fp, err);
> }
> 
> I suppose the ctf_set_errno_unsigned could even be a macro in the 
> ctf-impl.h header file.
> 
> 
> 
>> /* Store the specified error code into the CTF dict, and then return -1
>>     for the benefit of the caller, which is expected to return int,
>>     as opposed to ctf_id_t. */
>>
> 
> Ok!
> 
>>> +int
>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>> +{
>>> +  fp->ctf_errno = err;
>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend 
>>> on 64-bit
>>> +     Windows ABI.  */
>>> +  return -1;
>>> +}
>>
>> ... that Windows is not really the problem here. It's more
>>
>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>     it will be truncated to a non--1 value on platforms on which int
>>     and unsigned long are different sizes.  */
>>
>> perhaps? (At least, I think that's what's going on.)
> 
> The problem happens when the signed integral type is wider than unsigned 
> long.
> 
>   /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>       it will be extended to a non--1 value on platforms on which int
>       is larger than unsigned long are different sizes.  */
> 
>>
>> This probably needs testing on a wide variety of platforms with
>> different type sizes. I'll add throwing this through my entire test
>> matrix to my todo list, and fix any bugs observed: but the basic idea
>> looks sound to me.
> 
> Do you want to run this full matrix before or after submitting the patch?
> If it's before; when do you think you will have time to do that?
> 
> 
> Let me know how you want to proceed.
  
Nick Alcock Sept. 26, 2023, 2:51 p.m. UTC | #4
On 13 Sep 2023, Torbjorn SVENSSON outgrape:

> On 2023-09-13 20:37, Nick Alcock wrote:
>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
>> 
>>> v1 -> v2:
>>> Changed all functions with signed interger return type to return -1 based on
>>> comment from Alan.
>>>
>>> v2 -> v3:
>>> Added ctf_set_errno_signed function to return a signed -1 value based on
>>> comment from Nick.
>>>
>>> Ok for trunk?
>> If this touches exactly those functions that return int, and fixes the
>> reported bug, it's good as far as I'm concerned, except for a couple of
>> possible comment improvements:
>
> I've verified the calls by building binutils (with the configure flags mentioned in my last mail) with CFLAGS="-Wsign-conversion
> -Wconversion" and looking for any warnings related to ctf_set_errno. After applying this patch, there were no warnings left.

Oh right, that should work (given a platform on which this goes wrong in
the first place).

I should add -Wconversion to my test flags...

>>> +/* Store the specified error code into the CTF dict, and then return -1
>>> +   (CTF_ERR) for the benefit of the caller. */
>> It's not CTF_ERR in this case, it's just -1. Perhaps:
>
> True, but why is then ctf_set_errno returning CTF_ERR?

Simply because I foolishly assumed that CTF_ERR would always end up
== -1 even when passed through a function returning int. This is, uh,
not true.

I do wish that C was defined such that we had one consistent type we
could compare with for errors and not have to worry, but we don't:
functions returning a ctf_id_t return CTF_ERR on error, functions
returning an int return -1 on error and that's just the way it is :(
(This was always true, even in the Solaris era, but when ctf_id_t was an
int this was less visible than it is now.)

> I somehow want to make it obvious that it's not wrong and that it
> should *never* be CTF_ERR in the signed function or the problem would
> reappear.

Yeah.

> The other possibility is to do the inverse, meaning that the
> ctf_set_errno function is returning an integer (-1) and that there is
> a function ctf_set_errno_unsigned that is calling the ctf_set_errno
> function but casting the returned value to unsigned long (or

... and then all the ctf_id_t-returning functions call that?

> ctf_id_t). I personally think this solution is a bit more clean as -1
> is the error value from all functions, just a matter if it's signed or
> unsigned.

Honestly I suspect all we need is a better name:

ctf_set_int_errno(...);
ctf_set_type_errno(...)

and then use one or the other, consistently. (Neither needs to call the
other: they're only two lines long!)

> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.

I'd make both of them inline functions personally (I bet it would reduce
code size!)

>>> +int
>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>> +{
>>> +  fp->ctf_errno = err;
>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>> +     Windows ABI.  */
>>> +  return -1;
>>> +}
>> ... that Windows is not really the problem here. It's more
>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>     it will be truncated to a non--1 value on platforms on which int
>>     and unsigned long are different sizes.  */
>> perhaps? (At least, I think that's what's going on.)
>
> The problem happens when the signed integral type is wider than unsigned long.

... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
possible? I would have assumed from the C type hierarchy and the integer
conversion rank rules would have required that unsigned long int was at
least as big as any non-long integral type, but I don't see anywhere
it's required in the standard, dammit...

>> This probably needs testing on a wide variety of platforms with
>> different type sizes. I'll add throwing this through my entire test
>> matrix to my todo list, and fix any bugs observed: but the basic idea
>> looks sound to me.
>
> Do you want to run this full matrix before or after submitting the patch?
> If it's before; when do you think you will have time to do that?
>
> Let me know how you want to proceed.

OK, I'm back from various conferences so I can throw tests past this at
any time, it's largely automated. So once I stop faffing about and
changing my mind and we converge on something I'll throw it past every
test I've got. (It takes a day or so.)
  
Torbjorn SVENSSON Sept. 26, 2023, 5:49 p.m. UTC | #5
On 2023-09-26 16:51, Nick Alcock wrote:
> On 13 Sep 2023, Torbjorn SVENSSON outgrape:
>> On 2023-09-13 20:37, Nick Alcock wrote:
>>> On 13 Sep 2023, Torbjörn SVENSSON verbalised:
> Honestly I suspect all we need is a better name:
> 
> ctf_set_int_errno(...);
> ctf_set_type_errno(...)
> 
> and then use one or the other, consistently. (Neither needs to call the
> other: they're only two lines long!)

Ok. I've updated the patch (V4) to be like you suggested above.
> 
>> I suppose the ctf_set_errno_unsigned could even be a macro in the ctf-impl.h header file.
> 
> I'd make both of them inline functions personally (I bet it would reduce
> code size!)

I do not see any major difference in code size for the ld.exe binary 
after the change.

> 
>>>> +int
>>>> +ctf_set_errno_signed (ctf_dict_t *fp, int err)
>>>> +{
>>>> +  fp->ctf_errno = err;
>>>> +  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
>>>> +     Windows ABI.  */
>>>> +  return -1;
>>>> +}
>>> ... that Windows is not really the problem here. It's more
>>> /* Don't rely on CTF_ERR here; it is a ctf_id_t (unsigned long), and
>>>      it will be truncated to a non--1 value on platforms on which int
>>>      and unsigned long are different sizes.  */
>>> perhaps? (At least, I think that's what's going on.)
>>
>> The problem happens when the signed integral type is wider than unsigned long.
> 
> ... sizeof(signed int) > sizeof(unsigned long int)?! Is that even
> possible? I would have assumed from the C type hierarchy and the integer
> conversion rank rules would have required that unsigned long int was at
> least as big as any non-long integral type, but I don't see anywhere
> it's required in the standard, dammit...

I don't know about the 'sizeof(signed int) > sizeof(unsigned long int)' 
part, but what I said was _integral type_, not _int_. In the case where 
I saw the problem, it was ssize_t but I'm not sure what that maps to, 
but it's wider than unsigned long int apparently in this case.

>>> This probably needs testing on a wide variety of platforms with
>>> different type sizes. I'll add throwing this through my entire test
>>> matrix to my todo list, and fix any bugs observed: but the basic idea
>>> looks sound to me.
>>
>> Do you want to run this full matrix before or after submitting the patch?
>> If it's before; when do you think you will have time to do that?
>>
>> Let me know how you want to proceed.
> 
> OK, I'm back from various conferences so I can throw tests past this at
> any time, it's largely automated. So once I stop faffing about and
> changing my mind and we converge on something I'll throw it past every
> test I've got. (It takes a day or so.)

If you do not see any problem with the V4 patch, then please go ahead 
and run the tests that you have to get a verdict.

Kind regards,
Torbjörn
  

Patch

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6b342dc64a2..c6e64244aa9 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -60,7 +60,7 @@  ctf_grow_ptrtab (ctf_dict_t *fp)
 
       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_errno_signed (fp, ENOMEM));
 
       fp->ctf_ptrtab = new_ptrtab;
       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
@@ -87,7 +87,7 @@  ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
 				dtd->dtd_vlen_alloc * 2)) == NULL)
     {
       dtd->dtd_vlen = old;
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_errno_signed (fp, ENOMEM));
     }
   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
   dtd->dtd_vlen_alloc *= 2;
@@ -197,7 +197,7 @@  int
 ctf_update (ctf_dict_t *fp)
 {
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   fp->ctf_dtoldid = fp->ctf_typemax;
   return 0;
@@ -226,7 +226,7 @@  ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
 			  dtd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return -1;
     }
 
@@ -239,7 +239,7 @@  ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 	{
 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
 			      dtd->dtd_type);
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_errno_signed (fp, ENOMEM);
 	  return -1;
 	}
     }
@@ -330,7 +330,7 @@  ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
 {
   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return -1;
     }
   ctf_list_append (&fp->ctf_dvdefs, dvd);
@@ -391,10 +391,10 @@  ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dvdef_t *dvd, *nvd;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (fp->ctf_snapshot_lu >= id.snapshot_id)
-    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
+    return (ctf_set_errno_signed (fp, ECTF_OVERROLLBACK));
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -723,11 +723,11 @@  ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
@@ -1055,23 +1055,23 @@  ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   uint32_t kind, vlen, root;
 
   if (name == NULL)
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_ENUM)
-    return (ctf_set_errno (fp, ECTF_NOTENUM));
+    return (ctf_set_errno_signed (fp, ECTF_NOTENUM));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_errno_signed (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
@@ -1090,7 +1090,7 @@  ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 
   for (i = 0; i < vlen; i++)
     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+      return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
   en[i].cte_value = value;
@@ -1119,10 +1119,10 @@  ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (dtd == NULL)
-    return (ctf_set_errno (fp, ECTF_BADID));
+    return (ctf_set_errno_signed (fp, ECTF_BADID));
 
   if (name != NULL && name[0] == '\0')
     name = NULL;
@@ -1132,10 +1132,10 @@  ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (fp, ECTF_NOTSOU));
+    return (ctf_set_errno_signed (fp, ECTF_NOTSOU));
 
   if (vlen == CTF_MAX_VLEN)
-    return (ctf_set_errno (fp, ECTF_DTFULL));
+    return (ctf_set_errno_signed (fp, ECTF_DTFULL));
 
   old_vlen = dtd->dtd_vlen;
   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
@@ -1156,7 +1156,7 @@  ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       for (i = 0; i < vlen; i++)
 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1174,7 +1174,7 @@  ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
       msize = 0;
       malign = 0;
       if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
-	ctf_set_errno (fp, 0);
+	ctf_set_errno_signed (fp, 0);
       else if (ctf_errno (fp) == ECTF_INCOMPLETE)
 	is_incomplete = 1;
       else
@@ -1212,7 +1212,7 @@  ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 			      "incomplete type %lx to struct %lx without "
 			      "specifying explicit offset\n"),
 			    name ? name : _("(unnamed member)"), type, souid);
-	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	      return (ctf_set_errno_signed (fp, ECTF_INCOMPLETE));
 	    }
 
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
@@ -1285,7 +1285,7 @@  ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   int otype = type;
 
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
-    return (ctf_set_errno (fp, ECTF_NOTINTFP));
+    return (ctf_set_errno_signed (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1307,10 +1307,10 @@  ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
   ctf_dict_t *tmp = fp;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (ctf_dvd_lookup (fp, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, ref) == NULL)
     return -1;			/* errno is set for us.  */
@@ -1321,12 +1321,12 @@  ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
     return -1;
 
   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_errno_signed (fp, EAGAIN));
 
   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
     {
       free (dvd);
-      return (ctf_set_errno (fp, EAGAIN));
+      return (ctf_set_errno_signed (fp, EAGAIN));
     }
   dvd->dvd_type = ref;
   dvd->dvd_snapshots = fp->ctf_snapshots;
@@ -1350,25 +1350,25 @@  ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
-    return (ctf_set_errno (fp, ECTF_DUPLICATE));
+    return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                                  /* errno is set for us.  */
 
   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   if ((dupname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
     {
       free (dupname);
-      return (ctf_set_errno (fp, ENOMEM));
+      return (ctf_set_errno_signed (fp, ENOMEM));
     }
   return 0;
 }
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 5fdddfd0b54..5ad15ffd67f 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -378,7 +378,7 @@  ctf_dedup_atoms_init (ctf_dict_t *fp)
       if ((fp->ctf_dedup_atoms_alloc
 	   = ctf_dynset_create (htab_hash_string, htab_eq_string,
 				free)) == NULL)
-	return ctf_set_errno (fp, ENOMEM);
+	return ctf_set_errno_signed (fp, ENOMEM);
     }
   fp->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc;
   return 0;
@@ -543,7 +543,7 @@  ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
 
   if (populate_origin)
     if (ctf_dynhash_cinsert (d->cd_struct_origin, decorated, origin) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_errno_signed (fp, errno);
   return 0;
 }
 
@@ -1185,7 +1185,7 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
     }
   else
     if (ctf_dynhash_cinsert (d->cd_output_mapping_guard, id, hval) < 0)
-      return ctf_set_errno (fp, errno);
+      return ctf_set_errno_signed (fp, errno);
 #endif
 
   /* Record the type in the output mapping: if this is the first time this type
@@ -1197,17 +1197,17 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 				      hval)) == NULL)
     {
       if (ctf_dynhash_cinsert (d->cd_output_first_gid, hval, id) < 0)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_errno_signed (fp, errno);
 
       if ((type_ids = ctf_dynset_create (htab_hash_pointer,
 					 htab_eq_pointer,
 					 NULL)) == NULL)
-	return ctf_set_errno (fp, errno);
+	return ctf_set_errno_signed (fp, errno);
       if (ctf_dynhash_insert (d->cd_output_mapping, (void *) hval,
 			      type_ids) < 0)
 	{
 	  ctf_dynset_destroy (type_ids);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
 	}
     }
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
@@ -1248,7 +1248,7 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 	    }
 	}
       if (err != ECTF_NEXT_END)
-	return ctf_set_errno (fp, err);
+	return ctf_set_errno_signed (fp, err);
     }
 #endif
 
@@ -1256,7 +1256,7 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
      don't waste time reinserting the same keys in that case.  */
   if (!ctf_dynset_exists (type_ids, id, NULL)
       && ctf_dynset_insert (type_ids, id) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_errno_signed (fp, errno);
 
   /* The rest only needs to happen for types with names.  */
   if (!decorated_name)
@@ -1273,12 +1273,12 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
       if ((name_counts = ctf_dynhash_create (ctf_hash_string,
 					     ctf_hash_eq_string,
 					     NULL, NULL)) == NULL)
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
       if (ctf_dynhash_cinsert (d->cd_name_counts, decorated_name,
 			       name_counts) < 0)
 	{
 	  ctf_dynhash_destroy (name_counts);
-	  return ctf_set_errno (fp, errno);
+	  return ctf_set_errno_signed (fp, errno);
 	}
     }
 
@@ -1287,7 +1287,7 @@  ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
 
   if (ctf_dynhash_cinsert (name_counts, hval,
 			   (const void *) (uintptr_t) (count + 1)) < 0)
-    return ctf_set_errno (fp, errno);
+    return ctf_set_errno_signed (fp, errno);
 
   return 0;
 }
@@ -1318,7 +1318,7 @@  ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
   if (ctf_dynset_cinsert (d->cd_conflicting_types, hval) < 0)
     {
       ctf_dprintf ("Out of memory marking %s as conflicted\n", hval);
-      ctf_set_errno (fp, errno);
+      ctf_set_errno_signed (fp, errno);
       return -1;
     }
 
@@ -1340,7 +1340,7 @@  ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 	}
     }
   if (err != ECTF_NEXT_END)
-    return ctf_set_errno (fp, err);
+    return ctf_set_errno_signed (fp, err);
 
   return 0;
 }
@@ -1366,7 +1366,7 @@  ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
   if (!type_ids)
     {
       ctf_dprintf ("Looked up type kind by nonexistent hash %s.\n", hash);
-      return ctf_set_errno (fp, ECTF_INTERNAL);
+      return ctf_set_errno_signed (fp, ECTF_INTERNAL);
     }
   id = ctf_dynset_lookup_any (type_ids);
   if (!ctf_assert (fp, id))
@@ -1585,7 +1585,7 @@  ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 
  iterr:
   ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
-  return ctf_set_errno (fp, err);
+  return ctf_set_errno_signed (fp, err);
 
  assert_err:
   ctf_next_destroy (i);
@@ -1683,7 +1683,7 @@  ctf_dedup_init (ctf_dict_t *fp)
  oom:
   ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
 				 "out of memory"));
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_errno_signed (fp, ENOMEM);
 }
 
 /* No ctf_dedup calls are allowed after this call other than starting a new
@@ -1784,7 +1784,7 @@  ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, err, _("iteration error "
 				      "propagating conflictedness"));
-      return ctf_set_errno (output, err);
+      return ctf_set_errno_signed (output, err);
     }
 
   if (multiple)
@@ -1872,14 +1872,14 @@  ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
   return 0;
 
  err_no:
-  ctf_set_errno (output, errno);
+  ctf_set_errno_signed (output, errno);
  err:
   err = ctf_errno (output);
   ctf_next_destroy (i);
  iterr:
   ctf_dynset_destroy (to_mark);
   ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
-  return ctf_set_errno (output, err);
+  return ctf_set_errno_signed (output, err);
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -1913,7 +1913,7 @@  ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
       if (ctf_dynhash_insert (d->cd_input_nums, inputs[i],
 			      (void *) (uintptr_t) i) < 0)
 	{
-	  ctf_set_errno (output, errno);
+	  ctf_set_errno_signed (output, errno);
 	  ctf_err_warn (output, 0, errno, _("ctf_dedup: cannot initialize: %s\n"),
 			ctf_errmsg (errno));
 	  goto err;
@@ -1950,7 +1950,7 @@  ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
 	{
-	  ctf_set_errno (output, ctf_errno (inputs[i]));
+	  ctf_set_errno_signed (output, ctf_errno (inputs[i]));
 	  ctf_err_warn (output, 0, 0, _("iteration failure "
 					"computing type hashes"));
 	  goto err;
@@ -2176,7 +2176,7 @@  ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
 		    type_id, depth, arg);
 
  err_msg:
-  ctf_set_errno (output, ctf_errno (fp));
+  ctf_set_errno_signed (output, ctf_errno (fp));
   ctf_err_warn (output, 0, 0, _("%s in input file %s at type ID %lx"),
 		gettext (whaterr), ctf_link_input_name (fp), type);
  err:
@@ -2219,7 +2219,7 @@  ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ECTF_INTERNAL,
 		    _("looked up type kind by nonexistent hash %s"), hval);
-      return ctf_set_errno (output, ECTF_INTERNAL);
+      return ctf_set_errno_signed (output, ECTF_INTERNAL);
     }
 
   /* Have we seen this type before?  */
@@ -2237,7 +2237,7 @@  ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
 	{
 	  ctf_err_warn (output, 0, ENOMEM,
 			_("out of memory tracking already-visited types"));
-	  return ctf_set_errno (output, ENOMEM);
+	  return ctf_set_errno_signed (output, ENOMEM);
 	}
     }
 
@@ -2274,7 +2274,7 @@  ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
-      return ctf_set_errno (output, err);
+      return ctf_set_errno_signed (output, err);
     }
 
   return 0;
@@ -2376,7 +2376,7 @@  ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if ((already_visited = ctf_dynset_create (htab_hash_string,
 					    htab_eq_string,
 					    NULL)) == NULL)
-    return ctf_set_errno (output, ENOMEM);
+    return ctf_set_errno_signed (output, ENOMEM);
 
   sort_arg.inputs = inputs;
   sort_arg.ninputs = ninputs;
@@ -2400,7 +2400,7 @@  ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
   if (err != ECTF_NEXT_END)
     {
       ctf_err_warn (output, 0, err, _("cannot recurse over output mapping"));
-      ctf_set_errno (output, err);
+      ctf_set_errno_signed (output, err);
       goto err;
     }
   ctf_dynset_destroy (already_visited);
@@ -2664,7 +2664,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	      ctf_err_warn (output, 0, err,
 			    _("cannot create per-CU CTF archive for CU %s"),
 			    ctf_link_input_name (input));
-	      return ctf_set_errno (output, err);
+	      return ctf_set_errno_signed (output, err);
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2687,7 +2687,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ctf_errno (input),
 		    _("%s: lookup failure for type %lx"),
 		    ctf_link_input_name (real_input), type);
-      return ctf_set_errno (output, ctf_errno (input));
+      return ctf_set_errno_signed (output, ctf_errno (input));
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2765,7 +2765,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 			      ctf_link_input_name (input), input_num, name,
 			      type);
 		ctf_next_destroy (i);
-		return ctf_set_errno (output, ctf_errno (target));
+		return ctf_set_errno_signed (output, ctf_errno (target));
 	      }
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
@@ -2860,7 +2860,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
-	    ctf_set_errno (input, ENOMEM);
+	    ctf_set_errno_signed (input, ENOMEM);
 	    goto err_input;
 	  }
 
@@ -2912,7 +2912,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
 	/* Record the need to emit the members of this structure later.  */
 	if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
 	  {
-	    ctf_set_errno (target, errno);
+	    ctf_set_errno_signed (target, errno);
 	    goto err_target;
 	  }
 	break;
@@ -2921,7 +2921,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
       ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
 					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return ctf_set_errno (output, ECTF_CORRUPT);
+      return ctf_set_errno_signed (output, ECTF_CORRUPT);
     }
 
   if (!emission_hashed
@@ -2931,7 +2931,7 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
     {
       ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
 					 "global type IDs"));
-	return ctf_set_errno (output, ENOMEM);
+	return ctf_set_errno_signed (output, ENOMEM);
     }
 
   if (!emission_hashed && new_type != 0)
@@ -2944,21 +2944,21 @@  ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
  oom_hash:
   ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
 				     "hashes"));
-  return ctf_set_errno (output, ENOMEM);
+  return ctf_set_errno_signed (output, ENOMEM);
 
  err_input:
   ctf_err_warn (output, 0, ctf_errno (input),
 		_("%s (%i): while emitting deduplicated %s, error getting "
 		  "input type %lx"), ctf_link_input_name (input),
 		input_num, errtype, type);
-  return ctf_set_errno (output, ctf_errno (input));
+  return ctf_set_errno_signed (output, ctf_errno (input));
  err_target:
   ctf_err_warn (output, 0, ctf_errno (target),
 		_("%s (%i): while emitting deduplicated %s, error emitting "
 		  "target type from input type %lx"),
 		ctf_link_input_name (input), input_num,
 		errtype, type);
-  return ctf_set_errno (output, ctf_errno (target));
+  return ctf_set_errno_signed (output, ctf_errno (target));
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -3051,11 +3051,11 @@  ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
   ctf_err_warn (output, 0, ctf_errno (err_fp),
 		_("%s (%i): error emitting members for structure type %lx"),
 		ctf_link_input_name (input_fp), input_num, err_type);
-  return ctf_set_errno (output, ctf_errno (err_fp));
+  return ctf_set_errno_signed (output, ctf_errno (err_fp));
  iterr:
   ctf_err_warn (output, 0, err, _("iteration failure emitting "
 				  "structure members"));
-  return ctf_set_errno (output, err);
+  return ctf_set_errno_signed (output, err);
 }
 
 /* Emit deduplicated types into the outputs.  The shared type repository is
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 686951a9869..28b38c1d765 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -56,7 +56,7 @@  ctf_dump_append (ctf_dump_state_t *state, char *str)
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno_signed (state->cds_fp, ENOMEM));
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -261,7 +261,7 @@  ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump one section-offset field from the file header into the cds_items.  */
@@ -281,7 +281,7 @@  ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return 0;
 
  err:
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump the file header into the cds_items.  */
@@ -398,7 +398,7 @@  ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return 0;
  err:
   free (flagstr);
-  return (ctf_set_errno (fp, errno));
+  return (ctf_set_errno_signed (fp, errno));
 }
 
 /* Dump a single label into the cds_items.  */
@@ -412,7 +412,7 @@  ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_errno_signed (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -471,7 +471,7 @@  ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
       continue;
 
     oom:
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       ctf_next_destroy (i);
       return -1;
     }
@@ -487,7 +487,7 @@  ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   ctf_dump_state_t *state = arg;
 
   if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+    return (ctf_set_errno_signed (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
 				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
@@ -540,7 +540,7 @@  ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  return (ctf_set_errno_signed (state->cdm_fp, errno));
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -569,7 +569,7 @@  ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno_signed (state->cds_fp, ENOMEM));
 
   /* Dump the type itself.  */
   if ((str = ctf_dump_format_type (state->cds_fp, id,
@@ -654,7 +654,7 @@  ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  return ctf_set_errno_signed (state->cds_fp, ENOMEM);
 }
 
 /* Dump the string table into the cds_items.  */
@@ -671,7 +671,7 @@  ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
       if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       ctf_dump_append (state, str);
       s += strlen (s) + 1;
     }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index da687762c89..ff3d2bf1f01 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -742,6 +742,7 @@  extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
 extern unsigned long ctf_set_errno (ctf_dict_t *, int);
+extern int ctf_set_errno_signed (ctf_dict_t *, int);
 extern void ctf_flip_header (ctf_header_t *);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
 
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 16b111b14df..20d007d36d0 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -74,7 +74,7 @@  ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
     return -1;			/* errno is set for us.  */
 
   if (num_labels == 0)
-    return (ctf_set_errno (fp, ECTF_NOLABELDATA));
+    return (ctf_set_errno_signed (fp, ECTF_NOLABELDATA));
 
   for (i = 0; i < num_labels; i++, ctlp++)
     {
@@ -84,7 +84,7 @@  ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg)
 	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
 			"failed to decode label %u with type %u",
 			ctlp->ctl_label, ctlp->ctl_type);
-	  return (ctf_set_errno (fp, ECTF_CORRUPT));
+	  return (ctf_set_errno_signed (fp, ECTF_CORRUPT));
 	}
 
       linfo.ctb_type = ctlp->ctl_type;
@@ -134,7 +134,7 @@  ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo)
     return rc;
 
   if (rc != 1)
-    return (ctf_set_errno (fp, ECTF_NOLABEL));
+    return (ctf_set_errno_signed (fp, ECTF_NOLABEL));
 
   return 0;
 }
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 9babec2aa37..33c8cc0cdcc 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -142,7 +142,7 @@  ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
  oom1:
   free (filename);
  oom:
-  return ctf_set_errno (fp, ENOMEM);
+  return ctf_set_errno_signed (fp, ENOMEM);
 }
 
 /* Add a file, memory buffer, or unopened file (by name) to a link.
@@ -173,12 +173,12 @@  ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 	      void *buf _libctf_unused_, size_t n _libctf_unused_)
 {
   if (buf)
-    return (ctf_set_errno (fp, ECTF_NOTYET));
+    return (ctf_set_errno_signed (fp, ECTF_NOTYET));
 
   if (!((ctf && name && !buf)
 	|| (name && !buf && !ctf)
 	|| (buf && name && !ctf)))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   /* We can only lazily open files if libctf.so is in use rather than
      libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use
@@ -187,21 +187,21 @@  ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name,
 
 #if defined (PIC)
   if (!buf && !ctf && name && !ctf_open)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_errno_signed (fp, ECTF_NEEDSBFD));
 #elif NOBFD
   if (!buf && !ctf && name)
-    return (ctf_set_errno (fp, ECTF_NEEDSBFD));
+    return (ctf_set_errno_signed (fp, ECTF_NEEDSBFD));
 #endif
 
   if (fp->ctf_link_outputs)
-    return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+    return (ctf_set_errno_signed (fp, ECTF_LINKADDEDLATE));
   if (fp->ctf_link_inputs == NULL)
     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
 					      ctf_hash_eq_string, free,
 					      ctf_link_input_close);
 
   if (fp->ctf_link_inputs == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   return ctf_link_add_ctf_internal (fp, ctf, NULL, name);
 }
@@ -243,7 +243,7 @@  ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 #else
   ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
 		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
+  ctf_set_errno_signed (fp, ECTF_NEEDSBFD);
   return -1;
 #endif
 
@@ -257,7 +257,7 @@  ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
 
       ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
 		    input->clin_filename);
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
 
@@ -378,7 +378,7 @@  ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   /* Mappings cannot be set up if per-CU output dicts already exist.  */
   if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
-      return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
+      return (ctf_set_errno_signed (fp, ECTF_LINKADDEDLATE));
 
   if (fp->ctf_link_in_cu_mapping == NULL)
     fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
@@ -407,7 +407,7 @@  ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if ((err = ctf_dynhash_insert (fp->ctf_link_in_cu_mapping, f, t)) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       goto oom_noerrno;
     }
 
@@ -426,7 +426,7 @@  ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 				     t, one_out)) < 0)
 	{
 	  ctf_dynhash_destroy (one_out);
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto oom_noerrno;
 	}
     }
@@ -438,14 +438,14 @@  ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
 
   if (ctf_dynhash_insert (one_out, f, NULL) < 0)
     {
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       goto oom_noerrno;
     }
 
   return 0;
 
  oom:
-  ctf_set_errno (fp, errno);
+  ctf_set_errno_signed (fp, errno);
  oom_noerrno:
   free (f);
   free (t);
@@ -582,7 +582,7 @@  ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
 
   if (check_variable (name, per_cu_out_fp, dst_type, &dvd))
     if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0)
-      return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp)));
+      return (ctf_set_errno_signed (fp, ctf_errno (per_cu_out_fp)));
   return 0;
 }
 
@@ -680,7 +680,7 @@  ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
     {
       ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
 				  "CTF link inputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
 
@@ -877,7 +877,7 @@  ctf_link_deduplicating_close_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
 	{
 	  ctf_err_warn (fp, 0, err, _("iteration error in deduplicating link "
 				      "input freeing"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	}
     }
   else
@@ -915,7 +915,7 @@  ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
 
       /* Next the symbols.  We integrate data symbols even though the compiler
 	 is currently doing the same, to allow the compiler to stop in
@@ -930,7 +930,7 @@  ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
 
       /* Finally the function symbols.  */
 
@@ -943,7 +943,7 @@  ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
 	    }
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
-	return ctf_set_errno (fp, ctf_errno (inputs[i]));
+	return ctf_set_errno_signed (fp, ctf_errno (inputs[i]));
     }
   return 0;
 }
@@ -1070,12 +1070,12 @@  ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
 			_("symbol %s in input file %s found conflicting "
 			  "even when trying in per-CU dict."), name,
 			ctf_unnamed_cuname (input));
-	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
+	  return (ctf_set_errno_signed (fp, ECTF_DUPLICATE));
 	}
     }
   if (ctf_errno (input) != ECTF_NEXT_END)
     {
-      ctf_set_errno (fp, ctf_errno (input));
+      ctf_set_errno_signed (fp, ctf_errno (input));
       ctf_err_warn (fp, 0, ctf_errno (input),
 		    functions ? _("iterating over function symbols") :
 		    _("iterating over data symbols"));
@@ -1147,7 +1147,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	{
 	  ctf_err_warn (fp, 0, EFBIG, _("too many inputs in deduplicating "
 					"link: %li"), (long int) ninputs);
-	  ctf_set_errno (fp, EFBIG);
+	  ctf_set_errno_signed (fp, EFBIG);
 	  goto err_open_inputs;
 	}
 
@@ -1172,7 +1172,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	      ctf_err_warn (fp, 0, err, _("cannot open archive %s in "
 					  "CU-mapped CTF link"),
 			    only_input->clin_filename);
-	      ctf_set_errno (fp, err);
+	      ctf_set_errno_signed (fp, err);
 	      goto err_open_inputs;
 	    }
 	  ctf_next_destroy (ai);
@@ -1218,7 +1218,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive "
 				      "for %s"),
 			out_name);
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto err_inputs;
 	}
 
@@ -1233,7 +1233,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
 
       if (ctf_dedup (out, inputs, ninputs, parents, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplication failed for %s"),
 			out_name);
 	  goto err_inputs;
@@ -1242,7 +1242,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((outputs = ctf_dedup_emit (out, inputs, ninputs, parents,
 				     &noutputs, 1)) == NULL)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link type emission "
 				     "failed for %s"), out_name);
 	  goto err_inputs;
@@ -1258,7 +1258,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
 	  && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0)
 	{
-	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_set_errno_signed (fp, ctf_errno (out));
 	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link variable "
 				    "emission failed for %s"), out_name);
 	  goto err_inputs_outputs;
@@ -1291,7 +1291,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
       if ((in_arc = ctf_new_archive_internal (0, 0, NULL, outputs[0], NULL,
 					      NULL, &err)) == NULL)
 	{
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  goto err_outputs;
 	}
 
@@ -1330,7 +1330,7 @@  ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
     {
       ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
 				  "link"));
-      return ctf_set_errno (fp, err);
+      return ctf_set_errno_signed (fp, err);
     }
 
   return 0;
@@ -1355,7 +1355,7 @@  ctf_link_empty_outputs (ctf_dict_t *fp)
     {
       fp->ctf_flags &= ~LCTF_LINKING;
       ctf_err_warn (fp, 1, err, _("iteration error removing old outputs"));
-      ctf_set_errno (fp, err);
+      ctf_set_errno_signed (fp, err);
       return -1;
     }
   return 0;
@@ -1503,7 +1503,7 @@  ctf_link (ctf_dict_t *fp, int flags)
 					       ctf_dict_close);
 
   if (fp->ctf_link_outputs == NULL)
-    return ctf_set_errno (fp, ENOMEM);
+    return ctf_set_errno_signed (fp, ENOMEM);
 
   fp->ctf_flags |= LCTF_LINKING;
   ctf_link_deduplicating (fp);
@@ -1536,7 +1536,7 @@  ctf_link (ctf_dict_t *fp, int flags)
 	{
 	  fp->ctf_flags &= ~LCTF_LINKING;
 	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
-	  ctf_set_errno (fp, err);
+	  ctf_set_errno_signed (fp, err);
 	  return -1;
 	}
     }
@@ -1593,7 +1593,7 @@  ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string,
     }
 
   if (err)
-    ctf_set_errno (fp, err);
+    ctf_set_errno_signed (fp, err);
 
   return -err;
 }
@@ -1635,7 +1635,7 @@  ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
  oom:
   ctf_dynhash_destroy (fp->ctf_dynsyms);
   fp->ctf_dynsyms = NULL;
-  ctf_set_errno (fp, ENOMEM);
+  ctf_set_errno_signed (fp, ENOMEM);
   return -ENOMEM;
 }
 
@@ -1658,7 +1658,7 @@  ctf_link_shuffle_syms (ctf_dict_t *fp)
 					    NULL, free);
       if (!fp->ctf_dynsyms)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  ctf_set_errno_signed (fp, ENOMEM);
 	  return -ENOMEM;
 	}
     }
@@ -1758,7 +1758,7 @@  ctf_link_shuffle_syms (ctf_dict_t *fp)
   free (fp->ctf_dynsymidx);
   fp->ctf_dynsymidx = NULL;
   fp->ctf_dynsymmax = 0;
-  ctf_set_errno (fp, err);
+  ctf_set_errno_signed (fp, err);
   return -err;
 }
 
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c65849118cb..61cde7a041f 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -30,7 +30,7 @@  grow_pptrtab (ctf_dict_t *fp, size_t new_len)
 
   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
 			      * new_len)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   fp->ctf_pptrtab = new_pptrtab;
 
@@ -1046,7 +1046,7 @@  ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_info (fp, type, fip);
 }
@@ -1064,7 +1064,7 @@  ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
     return -1;					/* errno is set for us.  */
 
   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
-    return (ctf_set_errno (fp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (fp, ECTF_NOTFUNC));
 
   return ctf_func_type_args (fp, type, argc, argv);
 }
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 35f635b6559..4c60d62f648 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -159,7 +159,7 @@  get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
     case CTF_K_RESTRICT:
       return 0;
     default:
-      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_set_errno_signed (fp, ECTF_CORRUPT);
       ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
       return -1;
     }
@@ -1935,7 +1935,7 @@  ctf_parent_name_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dynparname);
 
   if ((fp->ctf_dynparname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
   fp->ctf_parname = fp->ctf_dynparname;
   return 0;
 }
@@ -1956,7 +1956,7 @@  ctf_cuname_set (ctf_dict_t *fp, const char *name)
     free (fp->ctf_dyncuname);
 
   if ((fp->ctf_dyncuname = strdup (name)) == NULL)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
   fp->ctf_cuname = fp->ctf_dyncuname;
   return 0;
 }
@@ -1969,10 +1969,10 @@  int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_errno_signed (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2008,10 +2008,10 @@  int
 ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
-    return (ctf_set_errno (fp, EINVAL));
+    return (ctf_set_errno_signed (fp, EINVAL));
 
   if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
-    return (ctf_set_errno (fp, ECTF_DMODEL));
+    return (ctf_set_errno_signed (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
     ctf_dict_close (fp->ctf_parent);
@@ -2052,7 +2052,7 @@  ctf_setmodel (ctf_dict_t *fp, int model)
 	}
     }
 
-  return (ctf_set_errno (fp, EINVAL));
+  return (ctf_set_errno_signed (fp, EINVAL));
 }
 
 /* Return the data model constant for the CTF dict.  */
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index ba830a2b095..e861ca0fcaf 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -123,7 +123,7 @@  symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 
       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
+	return (ctf_set_errno_signed (fp, ENOMEM));
 
       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
 				       &name, &ctf_sym)) == 0)
@@ -147,7 +147,7 @@  symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
 	    {
 	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
+	      return (ctf_set_errno_signed (fp, ENOMEM));
 	    }
 	}
       if (err != ECTF_NEXT_END)
@@ -155,7 +155,7 @@  symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
 				  "serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_errno_signed (fp, err));
 	}
     }
 
@@ -219,7 +219,7 @@  symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
 				  "serialization"));
       ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_errno_signed (fp, err));
     }
 
   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
@@ -236,7 +236,7 @@  symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
 				      "during CTF serialization"));
 	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
+	  return (ctf_set_errno_signed (fp, err));
 	}
     }
 
@@ -709,7 +709,7 @@  ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s,
   return 0;
 
  oom:
-  ctf_set_errno (fp, EAGAIN);
+  ctf_set_errno_signed (fp, EAGAIN);
   goto err;
 symerr:
   ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
@@ -970,7 +970,7 @@  ctf_serialize (ctf_dict_t *fp)
   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
 
   if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
+    return (ctf_set_errno_signed (fp, ECTF_RDONLY));
 
   /* Update required?  */
   if (!(fp->ctf_flags & LCTF_DIRTY))
@@ -1026,7 +1026,7 @@  ctf_serialize (ctf_dict_t *fp)
   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
 
   if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+    return (ctf_set_errno_signed (fp, EAGAIN));
 
   memcpy (buf, &hdr, sizeof (ctf_header_t));
   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
@@ -1106,7 +1106,7 @@  ctf_serialize (ctf_dict_t *fp)
 				       1, &err)) == NULL)
     {
       free (buf);
-      return (ctf_set_errno (fp, err));
+      return (ctf_set_errno_signed (fp, err));
     }
 
   (void) ctf_setmodel (nfp, ctf_getmodel (fp));
@@ -1221,7 +1221,7 @@  ctf_serialize (ctf_dict_t *fp)
 
 oom:
   free (buf);
-  return (ctf_set_errno (fp, EAGAIN));
+  return (ctf_set_errno_signed (fp, EAGAIN));
 err:
   free (buf);
   return -1;					/* errno is set for us.  */
@@ -1248,7 +1248,7 @@  ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1258,7 +1258,7 @@  ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	return (ctf_set_errno_signed (fp, errno));
       resid -= len;
       buf += len;
     }
@@ -1378,7 +1378,7 @@  ctf_compress_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_errno_signed (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
@@ -1412,7 +1412,7 @@  ctf_write (ctf_dict_t *fp, int fd)
     {
       if ((len = write (fd, bp, buf_len)) < 0)
 	{
-	  err = ctf_set_errno (fp, errno);
+	  err = ctf_set_errno_signed (fp, errno);
 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 911e94700f1..6cb994e0302 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -298,7 +298,7 @@  ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
     return 0;
 
   if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
-    return (ctf_set_errno (fp, ENOMEM));
+    return (ctf_set_errno_signed (fp, ENOMEM));
 
   ctf_dynset_remove (fp->ctf_str_pending_ref,
 		     (void *) ((signed char *) new_ref - bytes));
@@ -327,7 +327,7 @@  ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
 						 NULL, NULL);
   if (!fp->ctf_syn_ext_strtab)
     {
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return 0;
     }
 
@@ -338,7 +338,7 @@  ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
     {
       /* No need to bother freeing the syn_ext_strtab: it will get freed at
 	 ctf_str_write_strtab time if unreferenced.  */
-      ctf_set_errno (fp, ENOMEM);
+      ctf_set_errno_signed (fp, ENOMEM);
       return 0;
     }
 
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index c20ff825d9a..d94188bbc37 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -119,7 +119,7 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return -1;			/* errno is set for us.  */
 
       if ((i = ctf_next_create ()) == NULL)
-	return ctf_set_errno (ofp, ENOMEM);
+	return ctf_set_errno_signed (ofp, ENOMEM);
       i->cu.ctn_fp = ofp;
       i->ctn_tp = tp;
 
@@ -129,7 +129,7 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
 	{
 	  ctf_next_destroy (i);
-	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
+	  return (ctf_set_errno_signed (ofp, ECTF_NOTSOU));
 	}
 
       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -150,14 +150,14 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     }
 
   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));
+    return (ctf_set_errno_signed (ofp, ECTF_NEXT_WRONGFUN));
 
   if (ofp != i->cu.ctn_fp)
-    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));
+    return (ctf_set_errno_signed (ofp, ECTF_NEXT_WRONGFP));
 
   /* Resolve to the native dict of this type.  */
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
-    return (ctf_set_errno (ofp, ECTF_NOPARENT));
+    return (ctf_set_errno_signed (ofp, ECTF_NOPARENT));
 
   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
 
@@ -177,7 +177,7 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
 			     i->ctn_n) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -216,12 +216,12 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	  ctf_next_destroy (i);
 	  *it = NULL;
 	  i->ctn_type = 0;
-	  ctf_set_errno (ofp, ctf_errno (fp));
+	  ctf_set_errno_signed (ofp, ctf_errno (fp));
 	  return ret;
 	}
 
       if (!ctf_assert (fp, (i->ctn_next == NULL)))
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       i->ctn_type = 0;
       /* This sub-struct has ended: on to the next real member.  */
@@ -233,7 +233,7 @@  ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  end_iter:
   ctf_next_destroy (i);
   *it = NULL;
-  return ctf_set_errno (ofp, ECTF_NEXT_END);
+  return ctf_set_errno_signed (ofp, ECTF_NEXT_END);
 }
 
 /* Iterate over the members of an ENUM.  We pass the string name and associated
@@ -861,7 +861,7 @@  ctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len)
   free (str);
 
   if (slen >= len)
-    (void) ctf_set_errno (fp, ECTF_NAMELEN);
+    (void) ctf_set_errno_signed (fp, ECTF_NAMELEN);
 
   return slen;
 }
@@ -956,7 +956,7 @@  ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful size.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_errno_signed (ofp, ECTF_INCOMPLETE));
 
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1039,7 +1039,7 @@  ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
-      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+      return (ctf_set_errno_signed (ofp, ECTF_INCOMPLETE));
 
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
@@ -1235,7 +1235,7 @@  ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	break;
       }
     default:
-      return (ctf_set_errno (ofp, ECTF_NOTINTFP));
+      return (ctf_set_errno_signed (ofp, ECTF_NOTINTFP));
     }
 
   return 0;
@@ -1370,7 +1370,7 @@  ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM)
-    return (ctf_set_errno (ofp, ECTF_NOTSUE));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTSUE));
 
   return LCTF_INFO_VLEN (fp, tp->ctt_info);
 }
@@ -1398,7 +1398,7 @@  ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTSOU));
 
   n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
@@ -1418,7 +1418,7 @@  ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       const char *membname;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
@@ -1439,7 +1439,7 @@  ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 	}
     }
 
-  return (ctf_set_errno (ofp, ECTF_NOMEMBNAM));
+  return (ctf_set_errno_signed (ofp, ECTF_NOMEMBNAM));
 }
 
 /* Return the array type, index, and size information for the specified ARRAY.  */
@@ -1457,7 +1457,7 @@  ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     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));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTARRAY));
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
     ap = (const ctf_array_t *) dtd->dtd_vlen;
@@ -1536,7 +1536,7 @@  ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      (void) ctf_set_errno_signed (ofp, ECTF_NOTENUM);
       return -1;
     }
 
@@ -1557,7 +1557,7 @@  ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 	}
     }
 
-  ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno_signed (ofp, ECTF_NOENUMNAM);
   return -1;
 }
 
@@ -1584,7 +1584,7 @@  ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_FUNCTION)
-    return (ctf_set_errno (ofp, ECTF_NOTFUNC));
+    return (ctf_set_errno_signed (ofp, ECTF_NOTFUNC));
 
   fip->ctc_return = tp->ctt_type;
   fip->ctc_flags = 0;
@@ -1697,7 +1697,7 @@  ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
       ctf_lmember_t memb;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
-        return (ctf_set_errno (ofp, ctf_errno (fp)));
+        return (ctf_set_errno_signed (ofp, ctf_errno (fp)));
 
       if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
 				 func, arg, ctf_strptr (fp, memb.ctlm_name),
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index 9f83ab9ab0b..022ce785f95 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -265,6 +265,18 @@  ctf_set_errno (ctf_dict_t *fp, int err)
   return CTF_ERR;
 }
 
+/* Store the specified error code into the CTF dict, and then return -1
+   (CTF_ERR) for the benefit of the caller. */
+
+int
+ctf_set_errno_signed (ctf_dict_t *fp, int err)
+{
+  fp->ctf_errno = err;
+  /* Don't rely on CTF_ERR here as it will not properly sign extend on 64-bit
+     Windows ABI.  */
+  return -1;
+}
+
 /* Create a ctf_next_t.  */
 
 ctf_next_t *