public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/3] libctf: error handling improvements
@ 2020-07-31 19:16 Nick Alcock
  2020-07-31 19:16 ` [PATCH 1/3] libctf, binutils: initial work towards libctf gettextization Nick Alcock
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Nick Alcock @ 2020-07-31 19:16 UTC (permalink / raw)
  To: binutils

This does two interconnected things, done simultaneously because each touches
the same large set of source lines: gettextization, and transitioning of all
dprintfs used for error and warning handling to use the new ctf_errwarning_next
infrastructure added in the recent deduplicator series (which means changing a
lot of dprintfs into ctf_err_warns -- and also, because I changed the prototype
of ctf_err_warn, changing all the *existing* uses of that function, too).

All three patches contain a few little things that need review: the first, a
tiny reshuffling of readelf dependencies; the second, adaptation to a public API
change (of ctf_errwarning_next, which hasn't yet landed in a release, so can
change freely), some code motion allowing us to report CTF open errors, and a
bit of error-text adjustment; and the third, the removal of quote marks around
libctf API text in ld, objdump and readelf error messages, and adjustment of
testsuite output to match.

No new test failures, CTF-related test failures, or compilation warnings on
anything in the test matrix (all-targets built and tested on
x86_64-pc-linux-gnu, sparc64-unknown-linux-gnu, FreeBSD 12, Cygwin, mingw32,
mingw64). (All tested both with --disable-nls and without it.)

Nick Alcock (3):
  libctf, binutils: initial work towards libctf gettextization
  libctf, binutils, include, ld: gettextize and improve error handling
  binutils, ld: dequote libctf error messages

 binutils/Makefile.am                          |   2 +-
 binutils/Makefile.in                          |   2 +-
 binutils/objdump.c                            |  42 ++-
 binutils/readelf.c                            |  39 ++-
 include/ctf-api.h                             |   2 +-
 ld/ldlang.c                                   |  67 ++--
 ld/testsuite/ld-ctf/ctf.exp                   |  11 +
 ld/testsuite/ld-ctf/diag-ctf-version-f.d      |   2 +-
 ld/testsuite/ld-ctf/diag-cttname-invalid.d    |   2 +-
 .../ld-ctf/diag-decompression-failure.d       |   2 +-
 ld/testsuite/ld-ctf/diag-parname.d            |   2 +-
 ld/testsuite/ld-ctf/diag-unsupported-flag.d   |   2 +-
 .../ld-ctf/diag-wrong-magic-number-mixed.d    |   2 +-
 ld/testsuite/ld-ctf/diag-wrong-magic-number.d |   2 +-
 libctf/Makefile.am                            |   2 +-
 libctf/Makefile.in                            |   2 +-
 libctf/configure                              |  28 +-
 libctf/configure.ac                           |   2 +-
 libctf/ctf-archive.c                          |  63 ++--
 libctf/ctf-create.c                           |  90 ++++--
 libctf/ctf-dedup.c                            | 290 +++++++++---------
 libctf/ctf-dump.c                             |  27 +-
 libctf/ctf-error.c                            |   4 +-
 libctf/ctf-impl.h                             |  18 +-
 libctf/ctf-intl.h                             |  68 ++++
 libctf/ctf-labels.c                           |   6 +-
 libctf/ctf-link.c                             | 133 ++++----
 libctf/ctf-open-bfd.c                         |  31 +-
 libctf/ctf-open.c                             |  59 ++--
 libctf/ctf-string.c                           |   2 +-
 libctf/ctf-subr.c                             |  87 +++++-
 libctf/ctf-types.c                            |   3 +-
 32 files changed, 646 insertions(+), 448 deletions(-)
 create mode 100644 libctf/ctf-intl.h

-- 
2.28.0.248.gcf383e60c9


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

* [PATCH 1/3] libctf, binutils: initial work towards libctf gettextization
  2020-07-31 19:16 [PATCH 0/3] libctf: error handling improvements Nick Alcock
@ 2020-07-31 19:16 ` Nick Alcock
  2020-07-31 19:16 ` [PATCH 2/3] libctf, binutils, include, ld: gettextize and improve error handling Nick Alcock
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Nick Alcock @ 2020-07-31 19:16 UTC (permalink / raw)
  To: binutils

We gettextize under our package name, which we change to a more
reasonable 'libctf'.  Our internationalization support is mostly
provided by ctf-intl.h, which is a copy of opcodes/opintl.h with
the non-gettext_noop N_() expansion debracketed to avoid pedantic
compiler warnings.

The libctf error strings returned by ctf_errmsg are marked up for
internationalization.

(We also adjust binutils's Makefile a tiny bit to allow for the
fact that libctf now uses functions from libintl.)

binutils/ChangeLog
2020-07-29  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.am (readelf_LDADD): Move $(LIBINTL) after $(LIBCTF_NOBFD).
	* Makefile.in: Regenerated.

libctf/ChangeLog
2020-07-30  Nick Alcock  <nick.alcock@oracle.com>

	* configure.ac: Adjust package name to simply 'libctf': arbitrarily
	declare this to be version 1.2.0.
	* Makefile.am (AM_CPPFLAGS): Add @INCINTL@.
	* Makefile.in: Regenerated.
	* configure: Regenerated.
	* ctf-intl.h: New file, lightly modified from opcodes/opintl.h.
	* ctf-impl.h: Include it.
	* ctf-error.r (_ctf_errlist_t): Mark strings as noop-translatable.
	(ctf_errmsg): Actually translate them.
---
 binutils/Makefile.am |  2 +-
 binutils/Makefile.in |  2 +-
 libctf/Makefile.am   |  2 +-
 libctf/Makefile.in   |  2 +-
 libctf/configure     | 28 +++++++++---------
 libctf/configure.ac  |  2 +-
 libctf/ctf-error.c   |  4 +--
 libctf/ctf-impl.h    |  1 +
 libctf/ctf-intl.h    | 68 ++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 90 insertions(+), 21 deletions(-)
 create mode 100644 libctf/ctf-intl.h

diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index fb54653fd3a..e2ed6ff7080 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -252,7 +252,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS)
-readelf_LDADD   = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS)
+readelf_LDADD   = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS)
 
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 6b15696df62..3d9d6575b0d 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -718,7 +718,7 @@ size_SOURCES = size.c $(BULIBS)
 objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS)
-readelf_LDADD = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS)
+readelf_LDADD = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS)
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 8b8f0a8cf83..d762b0abf11 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -28,7 +28,7 @@ ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 
 INCDIR = $(srcdir)/../include
-AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd @INCINTL@
 AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
 
 if INSTALL_LIBBFD
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index 78de09ba10a..f43c0953e42 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -447,7 +447,7 @@ AUTOMAKE_OPTIONS = foreign no-texinfo.tex
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 INCDIR = $(srcdir)/../include
-AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd @INCINTL@
 AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
 @INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libctf.la libctf-nobfd.la
 @INSTALL_LIBBFD_FALSE@include_HEADERS = 
diff --git a/libctf/configure b/libctf/configure
index a1f5b7ff09f..b7ca7cd5003 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libctf library 1.2.0-pre.
+# Generated by GNU Autoconf 2.69 for libctf 1.2.0.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -585,10 +585,10 @@ MFLAGS=
 MAKEFLAGS=
 
 # Identity of this package.
-PACKAGE_NAME='libctf library'
-PACKAGE_TARNAME='libctf-library'
-PACKAGE_VERSION='1.2.0-pre'
-PACKAGE_STRING='libctf library 1.2.0-pre'
+PACKAGE_NAME='libctf'
+PACKAGE_TARNAME='libctf'
+PACKAGE_VERSION='1.2.0'
+PACKAGE_STRING='libctf 1.2.0'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1349,7 +1349,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libctf library 1.2.0-pre to adapt to many kinds of systems.
+\`configure' configures libctf 1.2.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1397,7 +1397,7 @@ Fine tuning of the installation directories:
   --infodir=DIR           info documentation [DATAROOTDIR/info]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
   --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/libctf-library]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/libctf]
   --htmldir=DIR           html documentation [DOCDIR]
   --dvidir=DIR            dvi documentation [DOCDIR]
   --pdfdir=DIR            pdf documentation [DOCDIR]
@@ -1419,7 +1419,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libctf library 1.2.0-pre:";;
+     short | recursive ) echo "Configuration of libctf 1.2.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1532,7 +1532,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libctf library configure 1.2.0-pre
+libctf configure 1.2.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1943,7 +1943,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libctf library $as_me 1.2.0-pre, which was
+It was created by libctf $as_me 1.2.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4185,8 +4185,8 @@ fi
 
 
 # Define the identity of the package.
- PACKAGE='libctf-library'
- VERSION='1.2.0-pre'
+ PACKAGE='libctf'
+ VERSION='1.2.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -13944,7 +13944,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libctf library $as_me 1.2.0-pre, which was
+This file was extended by libctf $as_me 1.2.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14010,7 +14010,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libctf library config.status 1.2.0-pre
+libctf config.status 1.2.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/libctf/configure.ac b/libctf/configure.ac
index f5ed973b10d..575da4677f3 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -19,7 +19,7 @@ dnl <http://www.gnu.org/licenses/>.
 dnl
 
 AC_PREREQ(2.64)
-AC_INIT([libctf library], 1.2.0-pre)
+AC_INIT([libctf], 1.2.0)
 AC_CONFIG_SRCDIR(ctf-impl.h)
 AC_CONFIG_MACRO_DIR(../config)
 AC_CONFIG_MACRO_DIR(../bfd)
diff --git a/libctf/ctf-error.c b/libctf/ctf-error.c
index 20971f4275b..9611e367fde 100644
--- a/libctf/ctf-error.c
+++ b/libctf/ctf-error.c
@@ -45,7 +45,7 @@ static const union _ctf_errlist_t
 } _ctf_errlist =
   {
    {
-#define _CTF_STR(n, s) s,
+#define _CTF_STR(n, s) N_(s),
 #include "ctf-error.h"
 #undef _CTF_STR
    }
@@ -70,7 +70,7 @@ ctf_errmsg (int error)
   else
     str = (const char *) strerror (error);
 
-  return (str ? str : "Unknown error");
+  return (str ? gettext (str) : _("Unknown error"));
 }
 
 int
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 35320d46f66..faee039adc8 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -36,6 +36,7 @@
 #include <elf.h>
 #include <bfd.h>
 #include "hashtab.h"
+#include "ctf-intl.h"
 
 #ifdef	__cplusplus
 extern "C"
diff --git a/libctf/ctf-intl.h b/libctf/ctf-intl.h
new file mode 100644
index 00000000000..af74872544a
--- /dev/null
+++ b/libctf/ctf-intl.h
@@ -0,0 +1,68 @@
+/* ctf-intl.h - libctf specific header for gettext code.
+   Copyright (C) 1998-2020 Free Software Foundation, Inc.
+
+   Written by Tom Tromey <tromey@cygnus.com>
+
+   This file is part of libctf.
+
+   This library 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.
+
+   It 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 file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#ifndef _CTF_INTL_H
+#define _CTF_INTL_H
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+/* Note the redefinition of gettext and ngettext here to use PACKAGE.
+
+   This is because the code in this directory is used to build a
+   library which will be linked with code in other directories to form
+   programs.  We want to maintain a separate translation file for this
+   directory however, rather than being forced to merge it with that
+   of any program linked to libopcodes.  This is a library, so it
+   cannot depend on the catalog currently loaded.
+
+   In order to do this, we have to make sure that when we extract
+   messages we use the LIBCTF domain rather than the domain of the
+   program that included the opcodes library, (eg OBJDUMP).  Hence we
+   use dgettext (PACKAGE, String) and define PACKAGE to be 'libctf'.
+   (See the code in configure).  */
+# undef gettext
+# define gettext(Msgid) dgettext (PACKAGE, Msgid)
+# undef ngettext
+# define ngettext(Msgid1, Msgid2, n) dngettext (PACKAGE, Msgid1, Msgid2, n)
+# define _(String) gettext (String)
+# ifdef gettext_noop
+#  define N_(String) gettext_noop (String)
+# else
+#  define N_(String) String
+# endif
+#else
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define ngettext(Msgid1, Msgid2, n) \
+  (n == 1 ? Msgid1 : Msgid2)
+# define dngettext(Domainname, Msgid1, Msgid2, n) \
+  (n == 1 ? Msgid1 : Msgid2)
+# define dcngettext(Domainname, Msgid1, Msgid2, n, Category) \
+  (n == 1 ? Msgid1 : Msgid2)
+# define textdomain(Domainname) do {} while (0)
+# define bindtextdomain(Domainname, Dirname) do {} while (0)
+# define _(String) (String)
+# define N_(String) String
+#endif
+
+#endif /* _CTF_INTL_H */
-- 
2.28.0.248.gcf383e60c9


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

* [PATCH 2/3] libctf, binutils, include, ld: gettextize and improve error handling
  2020-07-31 19:16 [PATCH 0/3] libctf: error handling improvements Nick Alcock
  2020-07-31 19:16 ` [PATCH 1/3] libctf, binutils: initial work towards libctf gettextization Nick Alcock
@ 2020-07-31 19:16 ` Nick Alcock
  2020-07-31 19:16 ` [PATCH 3/3] binutils, ld: dequote libctf error messages Nick Alcock
  2020-08-20 15:15 ` [PATCH 0/3] libctf: error handling improvements Nick Alcock
  3 siblings, 0 replies; 9+ messages in thread
From: Nick Alcock @ 2020-07-31 19:16 UTC (permalink / raw)
  To: binutils

This commit follows on from the earlier commit "libctf, ld, binutils:
add textual error/warning reporting for libctf" and converts every error
in libctf that was reported using ctf_dprintf to use ctf_err_warn
instead, gettextizing them in the process, using N_() where necessary to
avoid doing gettext calls unless an error message is actually generated,
and rephrasing some error messages for ease of translation.

This requires a slight change in the ctf_errwarning_next API: this API
is public but has not been in a release yet, so can still change freely.
The problem is that many errors are emitted at open time (whether
opening of a CTF dict, or opening of a CTF archive): the former of these
throws away its incompletely-initialized ctf_file_t rather than return
it, and the latter has no ctf_file_t at all. So errors and warnings
emitted at open time cannot be stored in the ctf_file_t, and have to go
elsewhere.

We put them in a static local in ctf-subr.c (which is not very
thread-safe: a later commit will improve things here): ctf_err_warn with
a NULL fp adds to this list, and the public interface
ctf_errwarning_next with a NULL fp retrieves from it.

We need a slight exception from the usual iterator rules in this case:
with a NULL fp, there is nowhere to store the ECTF_NEXT_END "error"
which signifies the end of iteration, so we add a new err parameter to
ctf_errwarning_next which is used to report such iteration-related
errors.  (If an fp is provided -- i.e., if not reporting open errors --
this is optional, but even if it's optional it's still an API change.
This is actually useful from a usability POV as well, since
ctf_errwarning_next is usually called when there's been an error, so
overwriting the error code with ECTF_NEXT_END is not very helpful!
So, unusually, ctf_errwarning_next now uses the passed fp for its
error code *only* if no errp pointer is passed in, and leaves it
untouched otherwise.)

ld, objdump and readelf are adapted to call ctf_errwarning_next with a
NULL fp to report open errors where appropriate.

The ctf_err_warn API also has to change, gaining a new error-number
parameter which is used to add the error message corresponding to that
error number into the debug stream when LIBCTF_DEBUG is enabled:
changing this API is easy at this point since we are already touching
all existing calls to gettextize them.  We need this because the debug
stream should contain the errno's message, but the error reported in the
error/warning stream should *not*, because the caller will probably
report it themselves at failure time regardless, and reporting it in
every error message that leads up to it leads to a ridiculous chattering
on failure, which is likely to end up as ridiculous chattering on stderr
(trimmed a bit):

CTF error: `ld/testsuite/ld-ctf/A.c (0): lookup failure for type 3: flags 1: The parent CTF dictionary is unavailable'
CTF error: `ld/testsuite/ld-ctf/A.c (0): struct/union member type hashing error during type hashing for type 80000001, kind 6: The parent CTF dictionary is unavailable'
CTF error: `deduplicating link variable emission failed for ld/testsuite/ld-ctf/A.c: The parent CTF dictionary is unavailable'
ld/.libs/lt-ld-new: warning: CTF linking failed; output will have no CTF section: `The parent CTF dictionary is unavailable'

We only need to be told that the parent CTF dictionary is unavailable
*once*, not over and over again!

errmsgs are still emitted on warning generation, because warnings do not
usually lead to a failure propagated up to the caller and reported
there.

Debug-stream messages are not translated.  If translation is turned on,
there will be a mixture of English and translated messages in the debug
stream, but rather that than burden the translators with debug-only
output.

binutils/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* objdump.c (dump_ctf_archive_member): Move error-
	reporting...
	(dump_ctf_errs): ... into this separate function.
	(dump_ctf): Call it on open errors.
	* readelf.c (dump_ctf_archive_member): Move error-
	reporting...
	(dump_ctf_errs): ... into this separate function.  Support
	calls with NULL fp. Adjust for new err parameter to
	ctf_errwarning_next.
	(dump_section_as_ctf): Call it on open errors.

include/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-api.h (ctf_errwarning_next): New err parameter.

ld/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* ldlang.c (lang_ctf_errs_warnings): Support calls with NULL fp.
	Adjust for new err parameter to ctf_errwarning_next.  Only
	check for assertion failures when fp is non-NULL.
	(ldlang_open_ctf): Call it on open errors.
	* testsuite/ld-ctf/ctf.exp: Always use the C locale to avoid
	breaking the diags tests.

libctf/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-subr.c (open_errors): New list.
	(ctf_err_warn): Calls with NULL fp append to open_errors.  Add err
	parameter, and use it to decorate the debug stream with errmsgs.
	(ctf_err_warn_to_open): Splice errors from a CTF dict into the
	open_errors.
	(ctf_errwarning_next): Calls with NULL fp report from open_errors.
	New err param to report iteration errors (including end-of-iteration)
	when fp is NULL.
	(ctf_assert_fail_internal): Adjust ctf_err_warn call for new err
	parameter: gettextize.
	* ctf-impl.h (ctfo_get_vbytes): Add ctf_file_t parameter.
	(LCTF_VBYTES): Adjust.
	(ctf_err_warn_to_open): New.
	(ctf_err_warn): Adjust.
	(ctf_bundle): Used in only one place: move...
	* ctf-create.c: ... here.
	(enumcmp): Use ctf_err_warn, not ctf_dprintf, passing the err number
	down as needed.  Don't emit the errmsg.  Gettextize.
	(membcmp): Likewise.
	(ctf_add_type_internal): Likewise.
	(ctf_write_mem): Likewise.
	(ctf_compress_write): Likewise.  Report errors writing the header or
	body.
	(ctf_write): Likewise.
	* ctf-archive.c (ctf_arc_write_fd): Use ctf_err_warn, not
	ctf_dprintf, and gettextize, as above.
	(ctf_arc_write): Likewise.
	(ctf_arc_bufopen): Likewise.
	(ctf_arc_open_internal): Likewise.
	* ctf-labels.c (ctf_label_iter): Likewise.
	* ctf-open-bfd.c (ctf_bfdclose): Likewise.
	(ctf_bfdopen): Likewise.
	(ctf_bfdopen_ctfsect): Likewise.
	(ctf_fdopen): Likewise.
	* ctf-string.c (ctf_str_write_strtab): Likewise.
	* ctf-types.c (ctf_type_resolve): Likewise.
	* ctf-open.c (get_vbytes_common): Likewise. Pass down the ctf dict.
	(get_vbytes_v1): Pass down the ctf dict.
	(get_vbytes_v2): Likewise.
	(flip_ctf): Likewise.
	(flip_types): Likewise. Use ctf_err_warn, not ctf_dprintf, and
	gettextize, as above.
	(upgrade_types_v1): Adjust calls.
	(init_types): Use ctf_err_warn, not ctf_dprintf, as above.
	(ctf_bufopen_internal): Likewise. Adjust calls. Transplant errors
	emitted into individual dicts into the open errors if this turns
	out to be a failed open in the end.
	* ctf-dump.c (ctf_dump_format_type): Adjust ctf_err_warn for new err
	argument.  Gettextize.  Don't emit the errmsg.
	(ctf_dump_funcs): Likewise.  Collapse err label into its only case.
	(ctf_dump_type): Likewise.
	* ctf-link.c (ctf_create_per_cu): Adjust ctf_err_warn for new err
	argument.  Gettextize.  Don't emit the errmsg.
	(ctf_link_one_type): Likewise.
	(ctf_link_lazy_open): Likewise.
	(ctf_link_one_input_archive): Likewise.
	(ctf_link_deduplicating_count_inputs): Likewise.
	(ctf_link_deduplicating_open_inputs): Likewise.
	(ctf_link_deduplicating_close_inputs): Likewise.
	(ctf_link_deduplicating): Likewise.
	(ctf_link): Likewise.
	(ctf_link_deduplicating_per_cu): Likewise. Add some missed
	ctf_set_errnos to obscure error cases.
	* ctf-dedup.c (ctf_dedup_rhash_type): Adjust ctf_err_warn for new
	err argument.  Gettextize.  Don't emit the errmsg.
	(ctf_dedup_populate_mappings): Likewise.
	(ctf_dedup_detect_name_ambiguity): Likewise.
	(ctf_dedup_init): Likewise.
	(ctf_dedup_multiple_input_dicts): Likewise.
	(ctf_dedup_conflictify_unshared): Likewise.
	(ctf_dedup): Likewise.
	(ctf_dedup_rwalk_one_output_mapping): Likewise.
	(ctf_dedup_id_to_target): Likewise.
	(ctf_dedup_emit_type): Likewise.
	(ctf_dedup_emit_struct_members): Likewise.
	(ctf_dedup_populate_type_mapping): Likewise.
	(ctf_dedup_populate_type_mappings): Likewise.
	(ctf_dedup_emit): Likewise.
	(ctf_dedup_hash_type): Likewise. Fix a bit of messed-up error
	status setting.
	(ctf_dedup_rwalk_one_output_mapping): Likewise. Don't hide
	unknown-type-kind messages (which signify file corruption).
---
 binutils/objdump.c          |  42 ++++--
 binutils/readelf.c          |  39 +++--
 include/ctf-api.h           |   2 +-
 ld/ldlang.c                 |  63 ++++----
 ld/testsuite/ld-ctf/ctf.exp |  11 ++
 libctf/ctf-archive.c        |  63 ++++----
 libctf/ctf-create.c         |  90 +++++++----
 libctf/ctf-dedup.c          | 290 ++++++++++++++++++------------------
 libctf/ctf-dump.c           |  27 ++--
 libctf/ctf-impl.h           |  17 +--
 libctf/ctf-labels.c         |   6 +-
 libctf/ctf-link.c           | 133 +++++++++--------
 libctf/ctf-open-bfd.c       |  31 ++--
 libctf/ctf-open.c           |  59 ++++----
 libctf/ctf-string.c         |   2 +-
 libctf/ctf-subr.c           |  87 +++++++++--
 libctf/ctf-types.c          |   3 +-
 17 files changed, 547 insertions(+), 418 deletions(-)

diff --git a/binutils/objdump.c b/binutils/objdump.c
index 79ef0518563..c1848961416 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -4071,6 +4071,29 @@ make_ctfsect (const char *name, bfd_byte *data,
   return ctfsect;
 }
 
+/* Dump CTF errors/warnings.  */
+static void
+dump_ctf_errs (ctf_file_t *fp)
+{
+  ctf_next_t *it = NULL;
+  char *errtext;
+  int is_warning;
+  int err;
+
+  /* Dump accumulated errors and warnings.  */
+  while ((errtext = ctf_errwarning_next (fp, &it, &is_warning, &err)) != NULL)
+    {
+      non_fatal (_("%s: `%s'"), is_warning ? _("warning"): _("error"),
+		 errtext);
+      free (errtext);
+    }
+  if (err != ECTF_NEXT_END)
+    {
+      non_fatal (_("CTF error: cannot get CTF errors: `%s'"),
+		 ctf_errmsg (err));
+    }
+}
+
 /* Dump one CTF archive member.  */
 
 static int
@@ -4081,9 +4104,6 @@ dump_ctf_archive_member (ctf_file_t *ctf, const char *name, void *arg)
 			  "Function objects", "Variables", "Types", "Strings",
 			  ""};
   const char **thing;
-  ctf_next_t *it = NULL;
-  char *errtext;
-  int is_warning;
   size_t i;
 
   /* Only print out the name of non-default-named archive members.
@@ -4121,18 +4141,7 @@ dump_ctf_archive_member (ctf_file_t *ctf, const char *name, void *arg)
 	}
     }
 
-  /* Dump accumulated errors and warnings.  */
-  while ((errtext = ctf_errwarning_next (ctf, &it, &is_warning)) != NULL)
-    {
-      non_fatal (_("%s: `%s'"), is_warning ? _("warning"): _("error"),
-		 errtext);
-      free (errtext);
-    }
-  if (ctf_errno (ctf) != ECTF_NEXT_END)
-    {
-      non_fatal (_("CTF error: cannot get CTF errors: `%s'"),
-		 ctf_errmsg (ctf_errno (ctf)));
-    }
+  dump_ctf_errs (ctf);
 
   return 0;
 }
@@ -4162,6 +4171,7 @@ dump_ctf (bfd *abfd, const char *sect_name, const char *parent_name)
   ctfsect = make_ctfsect (sect_name, ctfdata, ctfsize);
   if ((ctfa = ctf_bfdopen_ctfsect (abfd, &ctfsect, &err)) == NULL)
     {
+      dump_ctf_errs (NULL);
       non_fatal (_("CTF open failure: %s"), ctf_errmsg (err));
       bfd_fatal (bfd_get_filename (abfd));
     }
@@ -4171,6 +4181,7 @@ dump_ctf (bfd *abfd, const char *sect_name, const char *parent_name)
       ctfsect = make_ctfsect (parent_name, parentdata, parentsize);
       if ((parenta = ctf_bfdopen_ctfsect (abfd, &ctfsect, &err)) == NULL)
 	{
+	  dump_ctf_errs (NULL);
 	  non_fatal (_("CTF open failure: %s"), ctf_errmsg (err));
 	  bfd_fatal (bfd_get_filename (abfd));
 	}
@@ -4185,6 +4196,7 @@ dump_ctf (bfd *abfd, const char *sect_name, const char *parent_name)
      put CTFs and their parents in archives together.)  */
   if ((parent = ctf_arc_open_by_name (lookparent, NULL, &err)) == NULL)
     {
+      dump_ctf_errs (NULL);
       non_fatal (_("CTF open failure: %s"), ctf_errmsg (err));
       bfd_fatal (bfd_get_filename (abfd));
     }
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 421992d12d9..1466f7519aa 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -14205,6 +14205,26 @@ dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
   return new_s;
 }
 
+/* Dump CTF errors/warnings.  */
+static void
+dump_ctf_errs (ctf_file_t *fp)
+{
+  ctf_next_t *it = NULL;
+  char *errtext;
+  int is_warning;
+  int err;
+
+  /* Dump accumulated errors and warnings.  */
+  while ((errtext = ctf_errwarning_next (fp, &it, &is_warning, &err)) != NULL)
+    {
+      error (_("%s: `%s'"), is_warning ? _("warning"): _("error"),
+	     errtext);
+      free (errtext);
+    }
+  if (err != ECTF_NEXT_END)
+    error (_("CTF error: cannot get CTF errors: `%s'"), ctf_errmsg (err));
+}
+
 /* Dump one CTF archive member.  */
 
 static int
@@ -14215,9 +14235,6 @@ dump_ctf_archive_member (ctf_file_t *ctf, const char *name, void *arg)
 			  "Function objects", "Variables", "Types", "Strings",
 			  ""};
   const char **thing;
-  ctf_next_t *it = NULL;
-  char *errtext;
-  int is_warning;
   size_t i;
   int err = 0;
 
@@ -14258,18 +14275,7 @@ dump_ctf_archive_member (ctf_file_t *ctf, const char *name, void *arg)
     }
 
  out:
-  /* Dump accumulated errors and warnings.  */
-  while ((errtext = ctf_errwarning_next (ctf, &it, &is_warning)) != NULL)
-    {
-      error (_("%s: `%s'\n"), is_warning ? _("warning"): _("error"),
-	     errtext);
-      free (errtext);
-    }
-  if (ctf_errno (ctf) != ECTF_NEXT_END)
-    {
-      error (_("CTF error: cannot get CTF errors: `%s'\n"),
-	     ctf_errmsg (ctf_errno (ctf)));
-    }
+  dump_ctf_errs (ctf);
   return err;
 }
 
@@ -14356,6 +14362,7 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
 
   if ((ctfa = ctf_arc_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
     {
+      dump_ctf_errs (NULL);
       error (_("CTF open failure: %s\n"), ctf_errmsg (err));
       goto fail;
     }
@@ -14365,6 +14372,7 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
       if ((parenta = ctf_arc_bufopen (&parentsect, symsectp, strsectp,
 				      &err)) == NULL)
 	{
+	  dump_ctf_errs (NULL);
 	  error (_("CTF open failure: %s\n"), ctf_errmsg (err));
 	  goto fail;
 	}
@@ -14378,6 +14386,7 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
      put CTFs and their parents in archives together.)  */
   if ((parent = ctf_arc_open_by_name (lookparent, NULL, &err)) == NULL)
     {
+      dump_ctf_errs (NULL);
       error (_("CTF open failure: %s\n"), ctf_errmsg (err));
       goto fail;
     }
diff --git a/include/ctf-api.h b/include/ctf-api.h
index 77ea5cd0ef8..3a8e942f0d8 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -411,7 +411,7 @@ extern char *ctf_dump (ctf_file_t *, ctf_dump_state_t **state,
    the error/warning list, in order of emission.  Errors and warnings are popped
    after return: the caller must free the returned error-text pointer.  */
 extern char *ctf_errwarning_next (ctf_file_t *, ctf_next_t **,
-				  int *is_warning);
+				  int *is_warning, int *errp);
 
 extern ctf_id_t ctf_add_array (ctf_file_t *, uint32_t,
 			       const ctf_arinfo_t *);
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 1dd17ffff22..dc6f1b40399 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3671,6 +3671,34 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 }
 
 #ifdef ENABLE_LIBCTF
+/* Emit CTF errors and warnings.  fp can be NULL to report errors/warnings
+   that happened specifically at CTF open time.  */
+static void
+lang_ctf_errs_warnings (ctf_file_t *fp)
+{
+  ctf_next_t *i = NULL;
+  char *text;
+  int is_warning;
+  int err;
+
+  while ((text = ctf_errwarning_next (fp, &i, &is_warning, &err)) != NULL)
+    {
+      einfo (_("%s: `%s'\n"), is_warning ? _("CTF warning"): _("CTF error"),
+	     text);
+      free (text);
+    }
+  if (err != ECTF_NEXT_END)
+    {
+      einfo (_("CTF error: cannot get CTF errors: `%s'\n"),
+	     ctf_errmsg (err));
+    }
+
+  /* `err' returns errors from the error/warning iterator in particular.
+     These never assert.  But if we have an fp, that could have recorded
+     an assertion failure: assert if it has done so.  */
+  ASSERT (!fp || ctf_errno (fp) != ECTF_INTERNAL);
+}
+
 /* Open the CTF sections in the input files with libctf: if any were opened,
    create a fake input file that we'll write the merged CTF data to later
    on.  */
@@ -3693,9 +3721,12 @@ ldlang_open_ctf (void)
       if ((file->the_ctf = ctf_bfdopen (file->the_bfd, &err)) == NULL)
 	{
 	  if (err != ECTF_NOCTFDATA)
-	    einfo (_("%P: warning: CTF section in %pB not loaded; "
-		     "its types will be discarded: `%s'\n"), file->the_bfd,
+	    {
+	      lang_ctf_errs_warnings (NULL);
+	      einfo (_("%P: warning: CTF section in %pB not loaded; "
+		       "its types will be discarded: `%s'\n"), file->the_bfd,
 		     ctf_errmsg (err));
+	    }
 	  continue;
 	}
 
@@ -3728,29 +3759,6 @@ ldlang_open_ctf (void)
     ctf_close (errfile->the_ctf);
 }
 
-/* Emit CTF errors and warnings.  */
-static void
-lang_ctf_errs_warnings (ctf_file_t *fp)
-{
-  ctf_next_t *i = NULL;
-  char *text;
-  int is_warning;
-
-  while ((text = ctf_errwarning_next (fp, &i, &is_warning)) != NULL)
-    {
-      einfo (_("%s: `%s'\n"), is_warning ? _("CTF warning"): _("CTF error"),
-	     text);
-      free (text);
-    }
-  if (ctf_errno (fp) != ECTF_NEXT_END)
-    {
-      einfo (_("CTF error: cannot get CTF errors: `%s'\n"),
-	     ctf_errmsg (ctf_errno (fp)));
-    }
-
-  ASSERT (ctf_errno (fp) != ECTF_INTERNAL);
-}
-
 /* Merge together CTF sections.  After this, only the symtab-dependent
    function and data object sections need adjustment.  */
 
@@ -3804,6 +3812,7 @@ lang_merge_ctf (void)
 
   if (ctf_link (ctf_output, flags) < 0)
     {
+      lang_ctf_errs_warnings (ctf_output);
       einfo (_("%P: warning: CTF linking failed; "
 	       "output will have no CTF section: `%s'\n"),
 	     ctf_errmsg (ctf_errno (ctf_output)));
@@ -3813,6 +3822,7 @@ lang_merge_ctf (void)
 	  output_sect->flags |= SEC_EXCLUDE;
 	}
     }
+  /* Output any lingering errors that didn't come from ctf_link.  */
   lang_ctf_errs_warnings (ctf_output);
 }
 
@@ -3860,6 +3870,7 @@ lang_write_ctf (int late)
       output_sect->size = output_size;
       output_sect->flags |= SEC_IN_MEMORY | SEC_KEEP;
 
+      lang_ctf_errs_warnings (ctf_output);
       if (!output_sect->contents)
 	{
 	  einfo (_("%P: warning: CTF section emission failed; "
@@ -3868,8 +3879,6 @@ lang_write_ctf (int late)
 	  output_sect->size = 0;
 	  output_sect->flags |= SEC_EXCLUDE;
 	}
-
-      lang_ctf_errs_warnings (ctf_output);
     }
 
   /* This also closes every CTF input file used in the link.  */
diff --git a/ld/testsuite/ld-ctf/ctf.exp b/ld/testsuite/ld-ctf/ctf.exp
index be4c6ed3d6e..6893365f30f 100644
--- a/ld/testsuite/ld-ctf/ctf.exp
+++ b/ld/testsuite/ld-ctf/ctf.exp
@@ -28,6 +28,11 @@ if ![is_elf_format] {
     return 0
 }
 
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
 set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 
 foreach ctf_test $ctf_test_list {
@@ -39,3 +44,9 @@ foreach ctf_test $ctf_test_list {
     verbose [file rootname $ctf_test]
     run_dump_test [file rootname $ctf_test] { { cc "-gt -fPIC" } }
 }
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index 87e682c3943..799c3fbf26c 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -82,19 +82,19 @@ ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
   ctf_startoffs = headersz;
   if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
     {
-      errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
+      errmsg = N_("ctf_arc_write(): cannot extend file while writing");
       goto err;
     }
 
   if (write (fd, &dummy, 1) < 0)
     {
-      errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
+      errmsg = N_("ctf_arc_write(): cannot extend file while writing");
       goto err;
     }
 
   if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
     {
-      errmsg = "ctf_arc_write(): Cannot mmap(): %s\n";
+      errmsg = N_("ctf_arc_write(): cannot mmap");
       goto err;
     }
 
@@ -128,7 +128,7 @@ ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
   nametbl = malloc (namesz);
   if (nametbl == NULL)
     {
-      errmsg = "Error writing named CTF to archive: %s\n";
+      errmsg = N_("ctf_arc_write(): error writing named CTF to archive");
       goto err_unmap;
     }
 
@@ -144,13 +144,13 @@ ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
       off = arc_write_one_ctf (ctf_files[i], fd, threshold);
       if ((off < 0) && (off > -ECTF_BASE))
 	{
-	  errmsg = "ctf_arc_write(): Cannot determine file "
-	    "position while writing to archive: %s";
+	  errmsg = N_("ctf_arc_write(): cannot determine file "
+		      "position while writing to archive");
 	  goto err_free;
 	}
       if (off < 0)
 	{
-	  errmsg = "ctf_arc_write(): Cannot write CTF file to archive: %s\n";
+	  errmsg = N_("ctf_arc_write(): cannot write CTF file to archive");
 	  errno = off * -1;
 	  goto err_free;
 	}
@@ -171,8 +171,8 @@ ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
 
   if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
     {
-      errmsg = "ctf_arc_write(): Cannot get current file position "
-	"in archive: %s\n";
+      errmsg = N_("ctf_arc_write(): cannot get current file position "
+		  "in archive");
       goto err_free;
     }
   archdr->ctfa_names = htole64 (nameoffs);
@@ -182,7 +182,7 @@ ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
       ssize_t len;
       if ((len = write (fd, np, namesz)) < 0)
 	{
-	  errmsg = "ctf_arc_write(): Cannot write name table to archive: %s\n";
+	  errmsg = N_("ctf_arc_write(): cannot write name table to archive");
 	  goto err_free;
 	}
       namesz -= len;
@@ -201,8 +201,11 @@ err_free:
 err_unmap:
   arc_mmap_unmap (archdr, headersz, NULL);
 err:
-  ctf_dprintf (errmsg, errno < ECTF_BASE ? strerror (errno) :
-	       ctf_errmsg (errno));
+  /* We report errors into the first file in the archive, if any: if this is a
+     zero-file archive, put it in the open-errors stream for lack of anywhere
+     else for it to go.  */
+  ctf_err_warn (ctf_file_cnt > 0 ? ctf_files[0] : NULL, 0, errno, "%s",
+		gettext (errmsg));
   return errno;
 }
 
@@ -213,7 +216,7 @@ err:
 
    Returns 0 on success, or an errno, or an ECTF_* value.  */
 int
-ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
+ctf_arc_write (const char *file, ctf_file_t **ctf_files, size_t ctf_file_cnt,
 	       const char **names, size_t threshold)
 {
   int err;
@@ -221,8 +224,8 @@ ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
 
   if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
     {
-      ctf_dprintf ("ctf_arc_write(): cannot create %s: %s\n", file,
-		   strerror (errno));
+      ctf_err_warn (ctf_file_cnt > 0 ? ctf_files[0] : NULL, 0, errno,
+		    _("ctf_arc_write(): cannot create %s"), file);
       return errno;
     }
 
@@ -231,8 +234,8 @@ ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
     goto err_close;
 
   if ((err = close (fd)) < 0)
-    ctf_dprintf ("ctf_arc_write(): Cannot close after writing to archive: "
-		 "%s\n", strerror (errno));
+    ctf_err_warn (ctf_file_cnt > 0 ? ctf_files[0] : NULL, 0, errno,
+		  _("ctf_arc_write(): cannot close after writing to archive"));
   goto err;
 
  err_close:
@@ -404,8 +407,7 @@ ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
       is_archive = 0;
       if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL)
 	{
-	  ctf_dprintf ("ctf_arc_bufopen(): cannot open CTF: %s\n",
-		       ctf_errmsg (*errp));
+	  ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF"));
 	  return NULL;
 	}
     }
@@ -426,24 +428,24 @@ ctf_arc_open_internal (const char *filename, int *errp)
   libctf_init_debug();
   if ((fd = open (filename, O_RDONLY)) < 0)
     {
-      errmsg = "ctf_arc_open(): cannot open %s: %s\n";
+      errmsg = N_("ctf_arc_open(): cannot open %s");
       goto err;
     }
   if (fstat (fd, &s) < 0)
     {
-      errmsg = "ctf_arc_open(): cannot stat %s: %s\n";
+      errmsg = N_("ctf_arc_open(): cannot stat %s");
       goto err_close;
     }
 
   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
     {
-      errmsg = "ctf_arc_open(): Cannot read in %s: %s\n";
+      errmsg = N_("ctf_arc_open(): cannot read in %s");
       goto err_close;
     }
 
   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
     {
-      errmsg = "ctf_arc_open(): Invalid magic number";
+      errmsg = N_("ctf_arc_open(): %s: invalid magic number");
       errno = ECTF_FMT;
       goto err_unmap;
     }
@@ -462,8 +464,7 @@ err_close:
 err:
   if (errp)
     *errp = errno;
-  ctf_dprintf (errmsg, filename, errno < ECTF_BASE ? strerror (errno) :
-	       ctf_errmsg (errno));
+  ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename);
   return NULL;
 }
 
@@ -872,7 +873,8 @@ static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
     if (msync (header, headersz, MS_ASYNC) < 0)
     {
       if (errmsg)
-	*errmsg = "arc_mmap_writeout(): Cannot sync after writing to %s: %s\n";
+	*errmsg = N_("arc_mmap_writeout(): cannot sync after writing "
+		     "to %s: %s");
       return -1;
     }
     return 0;
@@ -884,7 +886,8 @@ static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
   if (munmap (header, headersz) < 0)
     {
       if (errmsg)
-	*errmsg = "arc_mmap_munmap(): Cannot unmap after writing to %s: %s\n";
+	*errmsg = N_("arc_mmap_munmap(): cannot unmap after writing "
+		     "to %s: %s");
       return -1;
     }
     return 0;
@@ -928,8 +931,8 @@ static int arc_mmap_writeout (int fd, void *header, size_t headersz,
   if ((lseek (fd, 0, SEEK_SET)) < 0)
     {
       if (errmsg)
-	*errmsg = "arc_mmap_writeout(): Cannot seek while writing header to "
-	  "%s: %s\n";
+	*errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to "
+		     "%s: %s");
       return -1;
     }
 
@@ -938,7 +941,7 @@ static int arc_mmap_writeout (int fd, void *header, size_t headersz,
       if ((len = write (fd, data, count)) < 0)
 	{
 	  if (errmsg)
-	    *errmsg = "arc_mmap_writeout(): Cannot write header to %s: %s\n";
+	    *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s");
 	  return len;
 	}
       if (len == EINTR)
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index b319476c168..e236606a249 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1596,6 +1596,13 @@ ctf_add_variable (ctf_file_t *fp, const char *name, ctf_id_t ref)
   return 0;
 }
 
+typedef struct ctf_bundle
+{
+  ctf_file_t *ctb_file;		/* CTF container handle.  */
+  ctf_id_t ctb_type;		/* CTF type identifier.  */
+  ctf_dtdef_t *ctb_dtd;		/* CTF dynamic type definition (if any).  */
+} ctf_bundle_t;
+
 static int
 enumcmp (const char *name, int value, void *arg)
 {
@@ -1604,14 +1611,15 @@ enumcmp (const char *name, int value, void *arg)
 
   if (ctf_enum_value (ctb->ctb_file, ctb->ctb_type, name, &bvalue) < 0)
     {
-      ctf_dprintf ("Conflict due to member %s iteration error: %s.\n", name,
-		   ctf_errmsg (ctf_errno (ctb->ctb_file)));
+      ctf_err_warn (ctb->ctb_file, 0, 0,
+		    _("conflict due to enum %s iteration error"), name);
       return 1;
     }
   if (value != bvalue)
     {
-      ctf_dprintf ("Conflict due to value change: %i versus %i\n",
-		   value, bvalue);
+      ctf_err_warn (ctb->ctb_file, 1, ECTF_CONFLICT,
+		    _("conflict due to enum value change: %i versus %i"),
+		    value, bvalue);
       return 1;
     }
   return 0;
@@ -1640,14 +1648,17 @@ membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset,
 
   if (ctf_member_info (ctb->ctb_file, ctb->ctb_type, name, &ctm) < 0)
     {
-      ctf_dprintf ("Conflict due to member %s iteration error: %s.\n", name,
-		   ctf_errmsg (ctf_errno (ctb->ctb_file)));
+      ctf_err_warn (ctb->ctb_file, 0, 0,
+		    _("conflict due to struct member %s iteration error"),
+		    name);
       return 1;
     }
   if (ctm.ctm_offset != offset)
     {
-      ctf_dprintf ("Conflict due to member %s offset change: "
-		   "%lx versus %lx\n", name, ctm.ctm_offset, offset);
+      ctf_err_warn (ctb->ctb_file, 1, ECTF_CONFLICT,
+		    _("conflict due to struct member %s offset change: "
+		      "%lx versus %lx"),
+		    name, ctm.ctm_offset, offset);
       return 1;
     }
   return 0;
@@ -1791,8 +1802,10 @@ ctf_add_type_internal (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type
 	  || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
 	      && kind != CTF_K_UNION))
 	{
-	  ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
-		       "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
+	  ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+			_("ctf_add_file(): conflict for type %s: "
+			  "kinds differ, new: %i; old (ID %lx): %i"),
+			name, kind, dst_type, dst_kind);
 	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
 	}
     }
@@ -1937,12 +1950,13 @@ ctf_add_type_internal (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type
 
 	  if (memcmp (&src_ar, &dst_ar, sizeof (ctf_arinfo_t)))
 	    {
-	      ctf_dprintf ("Conflict for type %s against ID %lx: "
-			   "array info differs, old %lx/%lx/%x; "
-			   "new: %lx/%lx/%x\n", name, dst_type,
-			   src_ar.ctr_contents, src_ar.ctr_index,
-			   src_ar.ctr_nelems, dst_ar.ctr_contents,
-			   dst_ar.ctr_index, dst_ar.ctr_nelems);
+	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+			    _("conflict for type %s against ID %lx: array info "
+			      "differs, old %lx/%lx/%x; new: %lx/%lx/%x"),
+			    name, dst_type, src_ar.ctr_contents,
+			    src_ar.ctr_index, src_ar.ctr_nelems,
+			    dst_ar.ctr_contents, dst_ar.ctr_index,
+			    dst_ar.ctr_nelems);
 	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
@@ -1986,18 +2000,19 @@ ctf_add_type_internal (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type
 	    if (ctf_type_size (src_fp, src_type) !=
 		ctf_type_size (dst_fp, dst_type))
 	      {
-		ctf_dprintf ("Conflict for type %s against ID %lx: "
-			     "union size differs, old %li, new %li\n",
-			     name, dst_type,
-			     (long) ctf_type_size (src_fp, src_type),
-			     (long) ctf_type_size (dst_fp, dst_type));
+		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+			      _("conflict for type %s against ID %lx: union "
+				"size differs, old %li, new %li"), name,
+			      dst_type, (long) ctf_type_size (src_fp, src_type),
+			      (long) ctf_type_size (dst_fp, dst_type));
 		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
 	      {
-		ctf_dprintf ("Conflict for type %s against ID %lx: "
-			     "members differ, see above\n", name, dst_type);
+		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+			      _("conflict for type %s against ID %lx: members "
+				"differ, see above"), name, dst_type);
 		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
 	      }
 
@@ -2076,8 +2091,9 @@ ctf_add_type_internal (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type
 	  if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
 	      || ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
 	    {
-	      ctf_dprintf ("Conflict for enum %s against ID %lx: "
-			   "members differ, see above\n", name, dst_type);
+	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+			    _("conflict for enum %s against ID %lx: members "
+			      "differ, see above"), name, dst_type);
 	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
 	    }
 	}
@@ -2200,13 +2216,17 @@ ctf_compress_write (ctf_file_t *fp, int fd)
   compress_len = compressBound (fp->ctf_size);
 
   if ((buf = malloc (compress_len)) == NULL)
-    return (ctf_set_errno (fp, ECTF_ZALLOC));
+    {
+      ctf_err_warn (fp, 0, 0, _("ctf_compress_write: cannot allocate %li bytes"),
+		    (unsigned long) compress_len);
+      return (ctf_set_errno (fp, ECTF_ZALLOC));
+    }
 
   if ((rc = compress (buf, (uLongf *) &compress_len,
 		      fp->ctf_buf, fp->ctf_size)) != Z_OK)
     {
-      ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
       err = ctf_set_errno (fp, ECTF_COMPRESS);
+      ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
       goto ret;
     }
 
@@ -2215,6 +2235,7 @@ ctf_compress_write (ctf_file_t *fp, int fd)
       if ((len = write (fd, hp, header_len)) < 0)
 	{
 	  err = ctf_set_errno (fp, errno);
+	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing header"));
 	  goto ret;
 	}
       header_len -= len;
@@ -2227,6 +2248,7 @@ ctf_compress_write (ctf_file_t *fp, int fd)
       if ((len = write (fd, bp, compress_len)) < 0)
 	{
 	  err = ctf_set_errno (fp, errno);
+	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
 	  goto ret;
 	}
       compress_len -= len;
@@ -2260,6 +2282,8 @@ ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold)
 		     + sizeof (struct ctf_header))) == NULL)
     {
       ctf_set_errno (fp, ENOMEM);
+      ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
+		    (unsigned long) (compress_len + sizeof (struct ctf_header)));
       return NULL;
     }
 
@@ -2280,8 +2304,8 @@ ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold)
       if ((rc = compress (bp, (uLongf *) &compress_len,
 			  fp->ctf_buf, fp->ctf_size)) != Z_OK)
 	{
-	  ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
 	  ctf_set_errno (fp, ECTF_COMPRESS);
+	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
 	  free (buf);
 	  return NULL;
 	}
@@ -2306,7 +2330,10 @@ ctf_write (ctf_file_t *fp, int fd)
   while (resid != 0)
     {
       if ((len = write (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing header"));
+	  return (ctf_set_errno (fp, errno));
+	}
       resid -= len;
       buf += len;
     }
@@ -2316,7 +2343,10 @@ ctf_write (ctf_file_t *fp, int fd)
   while (resid != 0)
     {
       if ((len = write (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
+	{
+	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing"));
+	  return (ctf_set_errno (fp, errno));
+	}
       resid -= len;
       buf += len;
     }
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 77b34f4539d..b58b815b84d 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -581,7 +581,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 #define ADD_CITER(citers, hval)						\
   do									\
     {									\
-      whaterr = "updating citers";					\
+      whaterr = N_("error updating citers");				\
       if (!citers)							\
 	if ((citers = ctf_dynset_create (htab_hash_string,		\
 					  ctf_dynset_eq_string,		\
@@ -610,14 +610,13 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 
       if ((hval = intern (fp, strdup (hashbuf))) == NULL)
 	{
-	  ctf_err_warn (fp, 0, "%s (%i): out of memory during forwarding-stub "
-			"hashing for type with GID %p; errno: %s",
-			ctf_link_input_name (input), input_num, type_id,
-			strerror (errno));
+	  ctf_err_warn (fp, 0, 0, _("%s (%i): out of memory during forwarding-"
+				    "stub hashing for type with GID %p"),
+			ctf_link_input_name (input), input_num, type_id);
 	  return NULL;				/* errno is set for us.  */
 	}
 
-      /* In share--duplicated link mode, make sure the origin of this type is
+      /* In share-duplicated link mode, make sure the origin of this type is
 	 recorded, even if this is a type in a parent dict which will not be
 	 directly traversed.  */
       if (d->cd_link_flags & CTF_LINK_SHARE_DUPLICATED
@@ -680,7 +679,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 			    depth);
 	if (ctf_type_encoding (input, type, &ep) < 0)
 	  {
-	    whaterr = "encoding";
+	    whaterr = N_("error getting encoding");
 	    goto err;
 	  }
 	ctf_dedup_sha1_add (&hash, &ep, sizeof (ctf_encoding_t), "encoding",
@@ -699,7 +698,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 				       child_type, flags, depth,
 				       populate_fun)) == NULL)
 	{
-	  whaterr = "referenced type hashing";
+	  whaterr = N_("error doing referenced type hashing");
 	  goto err;
 	}
       ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "referenced type",
@@ -728,7 +727,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					 child_type, flags, depth,
 					 populate_fun)) == NULL)
 	  {
-	    whaterr = "slice-referenced type hashing";
+	    whaterr = N_("error doing slice-referenced type hashing");
 	    goto err;
 	  }
 	ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "sliced type",
@@ -753,7 +752,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 
 	if (ctf_array_info (input, type, &ar) < 0)
 	  {
-	    whaterr = "array info";
+	    whaterr = N_("error getting array info");
 	    goto err;
 	  }
 
@@ -761,7 +760,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					 ar.ctr_contents, flags, depth,
 					 populate_fun)) == NULL)
 	  {
-	    whaterr = "array contents type hashing";
+	    whaterr = N_("error doing array contents type hashing");
 	    goto err;
 	  }
 	ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "array contents",
@@ -772,7 +771,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					 ar.ctr_index, flags, depth,
 					 populate_fun)) == NULL)
 	  {
-	    whaterr = "array index type hashing";
+	    whaterr = N_("error doing array index type hashing");
 	    goto err;
 	  }
 	ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "array index",
@@ -791,7 +790,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 
 	if (ctf_func_type_info (input, type, &fi) < 0)
 	  {
-	    whaterr = "func type info";
+	    whaterr = N_("error getting func type info");
 	    goto err;
 	  }
 
@@ -799,7 +798,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					 fi.ctc_return, flags, depth,
 					 populate_fun)) == NULL)
 	  {
-	    whaterr = "func return type";
+	    whaterr = N_("error getting func return type");
 	    goto err;
 	  }
 	ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "func return",
@@ -812,14 +811,14 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
-	    whaterr = "memory allocation";
+	    whaterr = N_("error doing memory allocation");
 	    goto err;
 	  }
 
 	if (ctf_func_type_args (input, type, fi.ctc_argc, args) < 0)
 	  {
 	    free (args);
-	    whaterr = "func arg type";
+	    whaterr = N_("error getting func arg type");
 	    goto err;
 	  }
 	for (j = 0; j < fi.ctc_argc; j++)
@@ -829,7 +828,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					     populate_fun)) == NULL)
 	      {
 		free (args);
-		whaterr = "func arg type hashing";
+		whaterr = N_("error doing func arg type hashing");
 		goto err;
 	      }
 	    ctf_dedup_sha1_add (&hash, hval, strlen (hval) + 1, "func arg type",
@@ -854,7 +853,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
 	  {
-	    whaterr = "enum member iteration";
+	    whaterr = N_("error doing enum member iteration");
 	    goto err;
 	  }
 	break;
@@ -887,7 +886,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 					     input_num, membtype, flags, depth,
 					     populate_fun)) == NULL)
 	      {
-		whaterr = "struct/union member type hashing";
+		whaterr = N_("error doing struct/union member type hashing");
 		goto iterr;
 	      }
 
@@ -899,26 +898,26 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 	  }
 	if (ctf_errno (input) != ECTF_NEXT_END)
 	  {
-	    whaterr = "struct/union member iteration";
+	    whaterr = N_("error doing struct/union member iteration");
 	    goto err;
 	  }
 	break;
       }
     default:
-      whaterr = "unknown type kind";
+      whaterr = N_("error: unknown type kind");
       goto err;
     }
   ctf_sha1_fini (&hash, hashbuf);
 
   if ((hval = intern (fp, strdup (hashbuf))) == NULL)
     {
-      whaterr = "hash internment";
+      whaterr = N_("cannot intern hash");
       goto oom;
     }
 
   /* Populate the citers for this type's subtypes, now the hash for the type
      itself is known.  */
-  whaterr = "citer tracking";
+  whaterr = N_("error tracking citers");
 
   if (citer)
     {
@@ -957,17 +956,15 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
   ctf_next_destroy (i);
  err:
   ctf_sha1_fini (&hash, NULL);
-  ctf_err_warn (fp, 0, "%s (%i): %s error during type hashing for "
-		"type %lx, kind %i: CTF error: %s; errno: %s",
-		ctf_link_input_name (input), input_num, whaterr, type,
-		kind, ctf_errmsg (ctf_errno (fp)), strerror (errno));
+  ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
+			    "kind %i"), ctf_link_input_name (input),
+		input_num, gettext (whaterr), type, kind);
   return NULL;
  oom:
   ctf_set_errno (fp, errno);
-  ctf_err_warn (fp, 0, "%s (%i): %s error during type hashing for "
-		"type %lx, kind %i: CTF error: %s; errno: %s",
-		ctf_link_input_name (input), input_num, whaterr, type,
-		kind, ctf_errmsg (ctf_errno (fp)), strerror (errno));
+  ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
+			    "kind %i"), ctf_link_input_name (input),
+		input_num, gettext (whaterr), type, kind);
   return NULL;
 }
 
@@ -1034,8 +1031,10 @@ ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
 
   if ((tp = ctf_lookup_by_id (&input, type)) == NULL)
     {
-      ctf_err_warn (fp, 0, "%s (%i): lookup failure for type %lx: flags %x",
-		    ctf_link_input_name (input), input_num, type, flags);
+      ctf_set_errno (fp, ctf_errno (input));
+      ctf_err_warn (fp, 0, 0, _("%s (%i): lookup failure for type %lx: "
+				"flags %x"), ctf_link_input_name (input),
+		    input_num, type, flags);
       return NULL;		/* errno is set for us.  */
     }
 
@@ -1106,14 +1105,14 @@ ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
 
       if (ctf_dynhash_cinsert (d->cd_type_hashes, type_id, hval) < 0)
 	{
-	  whaterr = "hash caching";
+	  whaterr = N_("error hash caching");
 	  goto oom;
 	}
 
       if (populate_fun (fp, input, inputs, input_num, type, type_id,
 			decorated, hval) < 0)
 	{
-	  whaterr = "population function";
+	  whaterr = N_("error calling population function");
 	  goto err;				/* errno is set for us. */
 	}
     }
@@ -1127,11 +1126,10 @@ ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
  oom:
   ctf_set_errno (fp, errno);
  err:
-  ctf_err_warn (fp, 0, "%s (%i): %s error during type hashing, type %lx, "
-		"kind %i: CTF errno: %s; errno: %s",
-		ctf_link_input_name (input), input_num, whaterr, type,
-		kind, ctf_errmsg (ctf_errno (fp)),
-		strerror (errno));
+  ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing, "
+			    "type %lx, kind %i"),
+		ctf_link_input_name (input), input_num,
+		gettext (whaterr), type, kind);
   return NULL;
 }
 
@@ -1218,7 +1216,7 @@ ctf_dedup_populate_mappings (ctf_file_t *fp, ctf_file_t *input _libctf_unused_,
 	  ctf_id_t bar = CTF_DEDUP_GID_TO_TYPE (one_id);
 	  if (ctf_type_kind_unsliced (foo, bar) != orig_kind)
 	    {
-	      ctf_err_warn (fp, 1, "added wrong kind to output mapping "
+	      ctf_err_warn (fp, 1, 0, "added wrong kind to output mapping "
 			    "for hash %s named %s: %p/%lx from %s is "
 			    "kind %i, but newly-added %p/%lx from %s is "
 			    "kind %i", hval,
@@ -1410,7 +1408,7 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
   void *k;
   void *v;
   int err;
-  const char *erm;
+  const char *whaterr;
 
   /* Go through cd_name_counts for all CTF namespaces in turn.  */
 
@@ -1474,7 +1472,7 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
 		}
 	      if (err != ECTF_NEXT_END)
 		{
-		  erm = "marking conflicting structs/unions";
+		  whaterr = N_("error marking conflicting structs/unions");
 		  goto iterr;
 		}
 	    }
@@ -1511,7 +1509,7 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
 	    }
 	  if (err != ECTF_NEXT_END)
 	    {
-	      erm = "finding commonest conflicting type";
+	      whaterr = N_("error finding commonest conflicting type");
 	      goto iterr;
 	    }
 
@@ -1526,20 +1524,20 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
 			   hval, (const char *) k);
 	      if (ctf_dedup_mark_conflicting_hash (fp, hval) < 0)
 		{
-		  erm = "marking hashes as conflicting";
+		  whaterr = N_("error marking hashes as conflicting");
 		  goto err;
 		}
 	    }
 	  if (err != ECTF_NEXT_END)
 	    {
-	      erm = "marking uncommon conflicting types";
+	      whaterr = N_("marking uncommon conflicting types");
 	      goto iterr;
 	    }
 	}
     }
   if (err != ECTF_NEXT_END)
     {
-      erm = "scanning for ambiguous names";
+      whaterr = N_("scanning for ambiguous names");
       goto iterr;
     }
 
@@ -1547,11 +1545,11 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
 
  err:
   ctf_next_destroy (i);
-  ctf_err_warn (fp, 0, "%s: %s", erm, ctf_errmsg (ctf_errno (fp)));
-  return -1;
+  ctf_err_warn (fp, 0, 0, "%s", gettext (whaterr));
+  return -1;					/* errno is set for us.  */
 
  iterr:
-  ctf_err_warn (fp, 0, "iteration failed %s: %s", erm, ctf_errmsg (err));
+  ctf_err_warn (fp, 0, err, _("iteration failed: %s"), gettext (whaterr));
   return ctf_set_errno (fp, err);
 
  assert_err:
@@ -1642,8 +1640,8 @@ ctf_dedup_init (ctf_file_t *fp)
   return 0;
 
  oom:
-  ctf_err_warn (fp, 0, "ctf_dedup_init: cannot initialize: "
-		"out of memory.");
+  ctf_err_warn (fp, 0, ENOMEM, _("ctf_dedup_init: cannot initialize: "
+				 "out of memory"));
   return ctf_set_errno (fp, ENOMEM);
 }
 
@@ -1740,10 +1738,9 @@ ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
     }
   if ((err != ECTF_NEXT_END) && (err != 0))
     {
-      ctf_err_warn (output, 0, "propagating conflictedness: %s",
-		    ctf_errmsg (err));
-      ctf_set_errno (output, err);
-      return -1;
+      ctf_err_warn (output, 0, err, _("iteration error "
+				      "propagating conflictedness"));
+      return ctf_set_errno (output, err);
     }
 
   if (multiple)
@@ -1836,11 +1833,9 @@ ctf_dedup_conflictify_unshared (ctf_file_t *output, ctf_file_t **inputs)
   err = ctf_errno (output);
   ctf_next_destroy (i);
  iterr:
-  ctf_set_errno (output, err);
   ctf_dynset_destroy (to_mark);
-  ctf_err_warn (output, 0, "conflictifying unshared types: %s",
-		ctf_errmsg (ctf_errno (output)));
-  return -1;
+  ctf_err_warn (output, 0, err, _("conflictifying unshared types"));
+  return ctf_set_errno (output, err);
 }
 
 /* The core deduplicator.  Populate cd_output_mapping in the output ctf_dedup
@@ -1899,9 +1894,10 @@ ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
 	}
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
 	{
-	  ctf_err_warn (output, 0, "iteration failure computing type "
-			"hashes: %s", ctf_errmsg (ctf_errno (inputs[i])));
-	  return ctf_set_errno (output, ctf_errno (inputs[i]));
+	  ctf_set_errno (output, ctf_errno (inputs[i]));
+	  ctf_err_warn (output, 0, 0, _("iteration failure "
+					"computing type hashes"));
+	  return -1;
 	}
     }
 
@@ -2013,7 +2009,7 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
     hashval = ctf_dynhash_lookup (d->cd_type_hashes, type_id);		\
     if (!ctf_assert (output, hashval))					\
       {									\
-	whaterr = "looking up ID in type hashes";			\
+	whaterr = N_("error looking up ID in type hashes");		\
 	goto errlabel;							\
       }									\
     ctf_dprintf ("ID %i/%lx has hash %s\n", cited_type_input_num, type,	\
@@ -2048,7 +2044,7 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
     case CTF_K_POINTER:
     case CTF_K_SLICE:
       CTF_TYPE_WALK (ctf_type_reference (fp, type), err,
-		     "Referenced type walk");
+		     N_("error during referenced type walk"));
       break;
 
     case CTF_K_ARRAY:
@@ -2057,12 +2053,14 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
 
 	if (ctf_array_info (fp, type, &ar) < 0)
 	  {
-	    whaterr = "array info lookup";
+	    whaterr = N_("error during array info lookup");
 	    goto err_msg;
 	  }
 
-	CTF_TYPE_WALK (ar.ctr_contents, err, "Array contents type walk");
-	CTF_TYPE_WALK (ar.ctr_index, err, "Array index type walk");
+	CTF_TYPE_WALK (ar.ctr_contents, err,
+		       N_("error during array contents type walk"));
+	CTF_TYPE_WALK (ar.ctr_index, err,
+		       N_("error during array index type walk"));
 	break;
       }
 
@@ -2074,27 +2072,29 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
 
 	if (ctf_func_type_info (fp, type, &fi) < 0)
 	  {
-	    whaterr = "func type info lookup";
+	    whaterr = N_("error during func type info lookup");
 	    goto err_msg;
 	  }
 
-	CTF_TYPE_WALK (fi.ctc_return, err, "Func return type walk");
+	CTF_TYPE_WALK (fi.ctc_return, err,
+		       N_("error during func return type walk"));
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
-	    whaterr = "memory allocation";
+	    whaterr = N_("error doing memory allocation");
 	    goto err_msg;
 	  }
 
 	if (ctf_func_type_args (fp, type, fi.ctc_argc, args) < 0)
 	  {
-	    whaterr = "func arg type lookup";
+	    whaterr = N_("error doing func arg type lookup");
 	    free (args);
 	    goto err_msg;
 	  }
 
 	for (j = 0; j < fi.ctc_argc; j++)
-	  CTF_TYPE_WALK (args[j], err_free_args, "Func arg type walk");
+	  CTF_TYPE_WALK (args[j], err_free_args,
+			 N_("error during Func arg type walk"));
 	free (args);
 	break;
 
@@ -2108,8 +2108,8 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
 	 emitted later, in a separate pass.  */
 	break;
     default:
-      whaterr = "unknown type kind";
-      goto err;
+      whaterr = N_("CTF dict corruption: unknown type kind");
+      goto err_msg;
     }
 
   return visit_fun (hval, output, inputs, ninputs, parents, visited, fp, type,
@@ -2117,8 +2117,8 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
 
  err_msg:
   ctf_set_errno (output, ctf_errno (fp));
-  ctf_err_warn (fp, 0, "%s during type walking in %s at ID %lx: %s", whaterr,
-	       ctf_link_input_name (fp), type, ctf_errmsg (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:
   return -1;
 }
@@ -2157,8 +2157,8 @@ ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
   type_ids = ctf_dynhash_lookup (d->cd_output_mapping, hval);
   if (!type_ids)
     {
-      ctf_err_warn (output, 0, "looked up type kind by nonexistent "
-		    "hash %s.", hval);
+      ctf_err_warn (output, 0, ECTF_INTERNAL,
+		    _("looked up type kind by nonexistent hash %s"), hval);
       return ctf_set_errno (output, ECTF_INTERNAL);
     }
 
@@ -2175,8 +2175,8 @@ ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
       visited = 0;
       if (ctf_dynset_cinsert (already_visited, hval) < 0)
 	{
-	  ctf_err_warn (output, 0, "out of memory tracking already-visited "
-			"types.");
+	  ctf_err_warn (output, 0, ENOMEM,
+			_("out of memory tracking already-visited types"));
 	  return ctf_set_errno (output, ENOMEM);
 	}
     }
@@ -2213,8 +2213,7 @@ ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
     }
   if (err != ECTF_NEXT_END)
     {
-      ctf_err_warn (output, 0, "walking many types with one hash: %s",
-		    ctf_errmsg (err));
+      ctf_err_warn (output, 0, err, _("cannot walk conflicted type"));
       return ctf_set_errno (output, err);
     }
 
@@ -2336,8 +2335,7 @@ ctf_dedup_walk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
     }
   if (err != ECTF_NEXT_END)
     {
-      ctf_err_warn (output, 0, "recursing over output mapping: %s",
-		    ctf_errmsg (err));
+      ctf_err_warn (output, 0, err, _("cannot recurse over output mapping"));
       ctf_set_errno (output, err);
       goto err;
     }
@@ -2490,8 +2488,8 @@ ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
       break;
     case -1:
       ctf_set_errno (err_fp, ctf_errno (output));
-      ctf_err_warn (err_fp, 0, "adding synthetic forward for type %i/%lx: "
-		    "%s", input_num, id, ctf_errmsg (ctf_errno (err_fp)));
+      ctf_err_warn (err_fp, 0, 0, _("cannot add synthetic forward for type "
+				    "%i/%lx"), input_num, id);
       return -1;
     default:
       return emitted_forward;
@@ -2518,10 +2516,10 @@ ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
 	case 0: /* No forward needed.  */
 	  break;
 	case -1:
-	  ctf_set_errno (err_fp, ctf_errno (output));
-	  ctf_err_warn (err_fp, 0, "adding synthetic forward for type %i/%lx: "
-			"%s", input_num, id, ctf_errmsg (ctf_errno (err_fp)));
-	  return -1;
+	  ctf_err_warn (err_fp, 0, ctf_errno (output),
+			_("cannot add synthetic forward for type %i/%lx"),
+			input_num, id);
+	  return ctf_set_errno (err_fp, ctf_errno (output));
 	default:
 	  return emitted_forward;
 	}
@@ -2570,7 +2568,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
   ctf_id_t ref;
   ctf_id_t maybe_dup = 0;
   ctf_encoding_t ep;
-  const char *erm;
+  const char *errtype;
   int emission_hashed = 0;
 
   /* We don't want to re-emit something we've already emitted.  */
@@ -2600,10 +2598,10 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 
 	  if ((target = ctf_create (&err)) == NULL)
 	    {
-	      ctf_err_warn (output, 0, "cannot create per-CU CTF archive "
-			    "for CU %s: %s", ctf_link_input_name (input),
-			    ctf_errmsg (err)); ctf_set_errno (output, err);
-	      return -1;
+	      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);
 	    }
 
 	  ctf_import_unref (target, output);
@@ -2621,11 +2619,10 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
   real_input = input;
   if ((tp = ctf_lookup_by_id (&real_input, type)) == NULL)
     {
-      ctf_err_warn (output, 0, "%s: lookup failure for type %lx: %s",
-		    ctf_link_input_name (real_input), type,
-		    ctf_errmsg (ctf_errno (input)));
-      ctf_set_errno (output, ctf_errno (input));
-      return -1;		/* errno is set for us.  */
+      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));
     }
 
   name = ctf_strraw (real_input, tp->ctt_name);
@@ -2667,7 +2664,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
       /* This will do nothing if the type to which this forwards already exists,
 	 and will be replaced with such a type if it appears later.  */
 
-      erm = "forward";
+      errtype = _("forward");
       if ((new_type = ctf_add_forward (target, isroot, name,
 				       ctf_type_kind_forwarded (input, type)))
 	  == CTF_ERR)
@@ -2676,7 +2673,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 
     case CTF_K_FLOAT:
     case CTF_K_INTEGER:
-      erm = "float/int";
+      errtype = _("float/int");
       if (ctf_type_encoding (input, type, &ep) < 0)
 	goto err_input;				/* errno is set for us.  */
       if ((new_type = ctf_add_encoded (target, isroot, name, &ep, kind))
@@ -2687,7 +2684,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
     case CTF_K_ENUM:
       {
 	int val;
-	erm = "enum";
+	errtype = _("enum");
 	if ((new_type = ctf_add_enum (target, isroot, name)) == CTF_ERR)
 	  goto err_input;				/* errno is set for us.  */
 
@@ -2695,10 +2692,11 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 	  {
 	    if (ctf_add_enumerator (target, new_type, name, val) < 0)
 	      {
-		ctf_err_warn (target, 0, "%s (%i): cannot add enumeration "
-			      "value %s from input type %lx: %s",
+		ctf_err_warn (target, 0, ctf_errno (target),
+			      _("%s (%i): cannot add enumeration value %s "
+				"from input type %lx"),
 			      ctf_link_input_name (input), input_num, name,
-			      type, ctf_errmsg (ctf_errno (target)));
+			      type);
 		ctf_next_destroy (i);
 		return ctf_set_errno (output, ctf_errno (target));
 	      }
@@ -2709,7 +2707,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
       }
 
     case CTF_K_TYPEDEF:
-      erm = "typedef";
+      errtype = _("typedef");
 
       ref = ctf_type_reference (input, type);
       if ((ref = ctf_dedup_id_to_target (output, target, inputs, ninputs,
@@ -2725,7 +2723,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
     case CTF_K_CONST:
     case CTF_K_RESTRICT:
     case CTF_K_POINTER:
-      erm = "pointer or cvr-qual";
+      errtype = _("pointer or cvr-qual");
 
       ref = ctf_type_reference (input, type);
       if ((ref = ctf_dedup_id_to_target (output, target, inputs, ninputs,
@@ -2738,7 +2736,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
       break;
 
     case CTF_K_SLICE:
-      erm = "slice";
+      errtype = _("slice");
 
       if (ctf_type_encoding (input, type, &ep) < 0)
 	goto err_input;				/* errno is set for us.  */
@@ -2757,7 +2755,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
       {
 	ctf_arinfo_t ar;
 
-	erm = "array info";
+	errtype = _("array info");
 	if (ctf_array_info (input, type, &ar) < 0)
 	  goto err_input;
 
@@ -2783,7 +2781,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 	ctf_id_t *args;
 	uint32_t j;
 
-	erm = "function";
+	errtype = _("function");
 	if (ctf_func_type_info (input, type, &fi) < 0)
 	  goto err_input;
 
@@ -2799,7 +2797,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 	    goto err_input;
 	  }
 
-	erm = "function args";
+	errtype = _("function args");
 	if (ctf_func_type_args (input, type, fi.ctc_argc, args) < 0)
 	  {
 	    free (args);
@@ -2832,7 +2830,7 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 	void *out_id;
 	/* Insert the structure itself, so other types can refer to it.  */
 
-	erm = "structure/union";
+	errtype = _("structure/union");
 	if (kind == CTF_K_STRUCT)
 	  new_type = ctf_add_struct_sized (target, isroot, name, size);
 	else
@@ -2850,9 +2848,10 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
 	break;
       }
     default:
-      ctf_err_warn (output, 0, "%s: unknown type kind for input type %lx",
+      ctf_err_warn (output, 0, ECTF_CORRUPT, _("%s: unknown type kind for "
+					       "input type %lx"),
 		    ctf_link_input_name (input), type);
-      return -1;
+      return ctf_set_errno (output, ECTF_CORRUPT);
     }
 
   if (!emission_hashed
@@ -2860,8 +2859,8 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
       && ctf_dynhash_cinsert (target->ctf_dedup.cd_output_emission_hashes,
 			      hval, (void *) (uintptr_t) new_type) < 0)
     {
-      ctf_err_warn (output, 0, "out of memory tracking deduplicated "
-		    "global type IDs");
+      ctf_err_warn (output, 0, ENOMEM, _("out of memory tracking deduplicated "
+					 "global type IDs"));
 	return ctf_set_errno (output, ENOMEM);
     }
 
@@ -2873,22 +2872,23 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
   return 0;
 
  oom_hash:
-  ctf_err_warn (output, 0, "out of memory creating emission-tracking hashes");
+  ctf_err_warn (output, 0, ENOMEM, _("out of memory creating emission-tracking "
+				     "hashes"));
   return ctf_set_errno (output, ENOMEM);
 
  err_input:
-  ctf_err_warn (output, 0, "%s (%i): while emitting deduplicated %s, error "
-		"getting input type %lx: %s", ctf_link_input_name (input),
-		input_num,erm, type, ctf_errmsg (ctf_errno (input)));
-  ctf_set_errno (output, ctf_errno (input));
-  return -1;
+  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));
  err_target:
-  ctf_err_warn (output, 0, "%s (%i): while emitting deduplicated %s, error "
-		"emitting target type from input type %lx: %s",
-		ctf_link_input_name (input), input_num, erm, type,
-		ctf_errmsg (ctf_errno (target)));
-  ctf_set_errno (output, ctf_errno (target));
-  return -1;
+  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));
 }
 
 /* Traverse the cd_emission_struct_members and emit the members of all
@@ -2978,16 +2978,14 @@ ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
   return 0;
  err_target:
   ctf_next_destroy (i);
-  ctf_err_warn (output, 0, "%s (%i): error emitting members for structure "
-		"type %lx: %s", ctf_link_input_name (input_fp), input_num,
-		err_type, ctf_errmsg (ctf_errno (err_fp)));
-  ctf_set_errno (output, ctf_errno (err_fp));
-  return -1;
+  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));
  iterr:
-  ctf_err_warn (output, 0, "iteration failure emitting structure members: %s",
-		ctf_errmsg (err));
-  ctf_set_errno (output, err);
-  return -1;
+  ctf_err_warn (output, 0, err, _("iteration failure emitting "
+				  "structure members"));
+  return ctf_set_errno (output, err);
 }
 
 /* Populate the type mapping used by the types in one FP (which must be an input
@@ -3052,8 +3050,7 @@ ctf_dedup_populate_type_mapping (ctf_file_t *shared, ctf_file_t *fp,
   return 0;
 
  err:
-  ctf_err_warn (shared, 0, "iteration error populating the type mapping: %s",
-		ctf_errmsg (err));
+  ctf_err_warn (shared, 0, err, _("iteration error populating the type mapping"));
   return ctf_set_errno (shared, err);
 }
 
@@ -3067,8 +3064,8 @@ ctf_dedup_populate_type_mappings (ctf_file_t *output, ctf_file_t **inputs,
 
   if (ctf_dedup_populate_type_mapping (output, output, inputs) < 0)
     {
-      ctf_err_warn (output, 0, "cannot populate type mappings for shared "
-		    "CTF dict: %s", ctf_errmsg (ctf_errno (output)));
+      ctf_err_warn (output, 0, 0, _("cannot populate type mappings for shared "
+				    "CTF dict"));
       return -1;				/* errno is set for us.  */
     }
 
@@ -3076,8 +3073,8 @@ ctf_dedup_populate_type_mappings (ctf_file_t *output, ctf_file_t **inputs,
     {
       if (ctf_dedup_populate_type_mapping (output, inputs[i], inputs) < 0)
 	{
-	  ctf_err_warn (output, 0, "cannot populate type mappings for per-CU "
-			"CTF dict: %s", ctf_errmsg (ctf_errno (inputs[i])));
+	  ctf_err_warn (output, 0, ctf_errno (inputs[i]),
+			_("cannot populate type mappings for per-CU CTF dict"));
 	  return ctf_set_errno (output, ctf_errno (inputs[i]));
 	}
     }
@@ -3129,7 +3126,8 @@ ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
 
   if ((outputs = calloc (num_outputs, sizeof (ctf_file_t *))) == NULL)
     {
-      ctf_err_warn (output, 0, "out of memory allocating link outputs array");
+      ctf_err_warn (output, 0, ENOMEM,
+		    _("out of memory allocating link outputs array"));
       ctf_set_errno (output, ENOMEM);
       return NULL;
     }
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 94d6bc6f018..ba358a21b07 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -174,8 +174,7 @@ ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id, int flag)
  oom:
   ctf_set_errno (fp, errno);
  err:
-  ctf_err_warn (fp, 1, "Cannot format name dumping type 0x%lx: %s", id,
-		ctf_errmsg (ctf_errno (fp)));
+  ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
   free (buf);
   free (str);
   free (bit);
@@ -405,7 +404,6 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
     {
       char *str;
       char *bit = NULL;
-      const char *err;
       const char *sym_name;
       ctf_funcinfo_t fi;
       ctf_id_t type;
@@ -427,8 +425,11 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
       /* Return type and all args.  */
       if ((bit = ctf_type_aname (state->cds_fp, type)) == NULL)
 	{
-	  err = "look up return type";
-	  goto err;
+	  ctf_err_warn (fp, 1, ctf_errno (state->cds_fp),
+			_("cannot look up return type dumping function type "
+			  "for symbol 0x%li"), (unsigned long) i);
+	  free (bit);
+	  return -1;			/* errno is set for us.  */
 	}
 
       /* Replace in the returned string, dropping in the function name.  */
@@ -469,13 +470,6 @@ ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
       ctf_dump_append (state, str);
       continue;
 
-    err:
-      ctf_err_warn (fp, 1, "Cannot %s dumping function type for "
-		    "symbol 0x%li: %s", err, (unsigned long) i,
-		    ctf_errmsg (ctf_errno (state->cds_fp)));
-      free (bit);
-      return -1;		/* errno is set for us.  */
-
     oom:
       free (bit);
       return (ctf_set_errno (fp, errno));
@@ -597,13 +591,12 @@ static int
 ctf_dump_type (ctf_id_t id, int flag, void *arg)
 {
   char *str;
-  const char *err;
   ctf_dump_state_t *state = arg;
   ctf_dump_membstate_t membstate = { &str, state->cds_fp };
   size_t len;
 
   if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
-    goto err_nomsg;		/* Error already logged for us.  */
+    goto err;
 
   str = str_append (str, "\n");
   if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
@@ -613,7 +606,8 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 	  ctf_dump_append (state, str);
 	  return 0;
 	}
-      err = "visit members";
+      ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
+		    _("cannot visit members dumping type 0x%lx"), id);
       goto err;
     }
 
@@ -626,9 +620,6 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
   return 0;
 
  err:
-  ctf_err_warn (state->cds_fp, 1, "Cannot %s dumping type 0x%lx: %s",
-		err, id, ctf_errmsg (ctf_errno (state->cds_fp)));
- err_nomsg:
   free (str);
   return 0;				/* Swallow the error.  */
 }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index faee039adc8..ecd0ef21188 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -130,7 +130,7 @@ typedef struct ctf_fileops
   uint32_t (*ctfo_get_vlen) (uint32_t);
   ssize_t (*ctfo_get_ctt_size) (const ctf_file_t *, const ctf_type_t *,
 				ssize_t *, ssize_t *);
-  ssize_t (*ctfo_get_vbytes) (unsigned short, ssize_t, size_t);
+  ssize_t (*ctfo_get_vbytes) (ctf_file_t *, unsigned short, ssize_t, size_t);
 } ctf_fileops_t;
 
 typedef struct ctf_list
@@ -199,13 +199,6 @@ typedef struct ctf_dvdef
   unsigned long dvd_snapshots;	/* Snapshot count when inserted.  */
 } ctf_dvdef_t;
 
-typedef struct ctf_bundle
-{
-  ctf_file_t *ctb_file;		/* CTF container handle.  */
-  ctf_id_t ctb_type;		/* CTF type identifier.  */
-  ctf_dtdef_t *ctb_dtd;		/* CTF dynamic type definition (if any).  */
-} ctf_bundle_t;
-
 typedef struct ctf_err_warning
 {
   ctf_list_t cew_list;		/* List forward/back pointers.  */
@@ -546,7 +539,7 @@ struct ctf_next
 #define LCTF_INFO_ISROOT(fp, info)	((fp)->ctf_fileops->ctfo_get_root(info))
 #define LCTF_INFO_VLEN(fp, info)	((fp)->ctf_fileops->ctfo_get_vlen(info))
 #define LCTF_VBYTES(fp, kind, size, vlen) \
-  ((fp)->ctf_fileops->ctfo_get_vbytes(kind, size, vlen))
+  ((fp)->ctf_fileops->ctfo_get_vbytes(fp, kind, size, vlen))
 
 #define LCTF_CHILD	0x0001	/* CTF container is a child */
 #define LCTF_RDWR	0x0002	/* CTF container is writable */
@@ -718,8 +711,10 @@ _libctf_printflike_ (1, 2)
 extern void ctf_dprintf (const char *, ...);
 extern void libctf_init_debug (void);
 
-_libctf_printflike_ (3, 4)
-extern void ctf_err_warn (ctf_file_t *, int is_warning, const char *, ...);
+_libctf_printflike_ (4, 5)
+extern void ctf_err_warn (ctf_file_t *, int is_warning, int err,
+			  const char *, ...);
+extern void ctf_err_warn_to_open (ctf_file_t *);
 extern void ctf_assert_fail_internal (ctf_file_t *, const char *,
 				      size_t, const char *);
 extern const char *ctf_link_input_name (ctf_file_t *);
diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c
index 53fbdb2dfe0..014a9933e64 100644
--- a/libctf/ctf-labels.c
+++ b/libctf/ctf-labels.c
@@ -80,8 +80,10 @@ ctf_label_iter (ctf_file_t *fp, ctf_label_f *func, void *arg)
     {
       if ((lname = ctf_strraw (fp, ctlp->ctl_label)) == NULL)
 	{
-	  ctf_dprintf ("failed to decode label %u with "
-		       "type %u\n", ctlp->ctl_label, ctlp->ctl_type);
+	  /* Not marked for translation: label code not used yet.  */
+	  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));
 	}
 
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index f269fe7ac0e..1cda324e65e 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -314,9 +314,9 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
 
       if ((cu_fp = ctf_create (&err)) == NULL)
 	{
-	  ctf_err_warn (fp, 0, "Cannot create per-CU CTF archive for "
-			"CU %s from input file %s: %s", cuname, filename,
-			ctf_errmsg (err));
+	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive for "
+				      "CU %s from input file %s"),
+			cuname, filename);
 	  ctf_set_errno (fp, err);
 	  return NULL;
 	}
@@ -477,7 +477,8 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_)
 
   if (arg->in_fp->ctf_link_flags != CTF_LINK_SHARE_UNCONFLICTED)
     {
-      ctf_err_warn (arg->out_fp, 0, "Share-duplicated mode not yet implemented");
+      ctf_err_warn (arg->out_fp, 0, ECTF_NOTYET,
+		    _("share-duplicated mode not yet implemented"));
       return ctf_set_errno (arg->out_fp, ECTF_NOTYET);
     }
 
@@ -495,9 +496,10 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_)
       if (err != ECTF_CONFLICT)
 	{
 	  if (err != ECTF_NONREPRESENTABLE)
-	    ctf_err_warn (arg->out_fp, 1, "Cannot link type %lx from input file %s, "
-			  "CU %s into output link: %s", type, arg->cu_name,
-			 arg->in_file_name, ctf_errmsg (err));
+	    ctf_err_warn (arg->out_fp, 1, 0,
+			  _("cannot link type %lx from input file %s, CU %s "
+			    "into output link"), type, arg->cu_name,
+			  arg->in_file_name);
 	  /* We must ignore this problem or we end up losing future types, then
 	     trying to link the variables in, then exploding.  Better to link as
 	     much as possible.  */
@@ -515,10 +517,11 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_)
 
   err = ctf_errno (per_cu_out_fp);
   if (err != ECTF_NONREPRESENTABLE)
-    ctf_err_warn (arg->out_fp, 1, "Cannot link type %lx from input file %s, CU %s "
-		 "into output per-CU CTF archive member %s: %s: skipped", type,
-		 ctf_link_input_name (arg->in_fp), arg->in_file_name,
-		 ctf_link_input_name (per_cu_out_fp), ctf_errmsg (err));
+    ctf_err_warn (arg->out_fp, 1, 0,
+		  _("cannot link type %lx from input file %s, CU %s "
+		    "into output per-CU CTF archive member %s: %s: skipped"),
+		  type, ctf_link_input_name (arg->in_fp), arg->in_file_name,
+		  ctf_link_input_name (per_cu_out_fp), ctf_errmsg (err));
   if (err == ECTF_CONFLICT)
       /* Conflicts are possible at this stage only if a non-ld user has combined
 	 multiple TUs into a single output dictionary.  Even in this case we do not
@@ -633,8 +636,9 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_)
 
       if (dst_type == 0)
 	{
-	  ctf_err_warn (arg->out_fp, 1, "Type %lx for variable %s in input "
-			"file %s not found: skipped", type, name,
+	  ctf_err_warn (arg->out_fp, 1, 0,
+			_("type %lx for variable %s in input file %s "
+			  "not found: skipped"), type, name,
 			arg->in_file_name);
 	  /* Do not terminate the link: just skip the variable.  */
 	  return 0;
@@ -727,8 +731,8 @@ ctf_link_lazy_open (ctf_file_t *fp, ctf_link_input_t *input)
 #if defined (PIC) || !NOBFD
   input->clin_arc = ctf_open (input->clin_filename, NULL, &err);
 #else
-  ctf_err_warn (fp, 0, "Cannot open %s lazily: %s", input->clin_filename,
-		ctf_errmsg (ECTF_NEEDSBFD));
+  ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
+		input->clin_filename);
   ctf_set_errno (fp, ECTF_NEEDSBFD);
   return -1;
 #endif
@@ -741,8 +745,8 @@ ctf_link_lazy_open (ctf_file_t *fp, ctf_link_input_t *input)
       if (err == ECTF_NOCTFDATA)
 	return 0;
 
-      ctf_err_warn (fp, 0, "Opening CTF %s failed: %s",
-		    input->clin_filename, ctf_errmsg (err));
+      ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
+		    input->clin_filename);
       ctf_set_errno (fp, err);
       return -1;
     }
@@ -789,9 +793,10 @@ ctf_link_one_input_archive (void *key, void *value, void *arg_)
 						 &err)) == NULL)
     if (err != ECTF_ARNNAME)
       {
-	ctf_err_warn (arg->out_fp, 0, "Cannot open main archive member in "
-		      "input file %s in the link: skipping: %s",
-		      arg->in_file_name, ctf_errmsg (err));
+	ctf_err_warn (arg->out_fp, 1, 0,
+		      _("cannot open main archive member in input file %s "
+			"in the link: skipping: %s"), arg->in_file_name,
+		      ctf_errmsg (err));
 	goto out;
       }
 
@@ -804,9 +809,9 @@ ctf_link_one_input_archive (void *key, void *value, void *arg_)
   arg->done_parent = 1;
   if (ctf_archive_iter (input->clin_arc, ctf_link_one_input_archive_member,
 			arg) < 0)
-    ctf_err_warn (arg->out_fp, 0, "Cannot traverse archive in input file %s: "
-		  "link cannot continue: %s", arg->in_file_name,
-		  ctf_errmsg (ctf_errno (arg->out_fp)));
+    ctf_err_warn (arg->out_fp, 0, 0, _("cannot traverse archive in input file "
+				       "%s: link cannot continue"),
+		  arg->in_file_name);
   else
     {
       /* The only error indication to the caller is the errno: so ensure that it
@@ -911,8 +916,8 @@ ctf_link_deduplicating_count_inputs (ctf_file_t *fp, ctf_dynhash_t *cu_names,
     }
   if (err != ECTF_NEXT_END)
     {
-      ctf_err_warn (fp, 0, "Iteration error counting deduplicating CTF link "
-		    "inputs: %s", ctf_errmsg (err));
+      ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating "
+				  "CTF link inputs"));
       ctf_set_errno (fp, err);
       return -1;
     }
@@ -1073,8 +1078,8 @@ ctf_link_deduplicating_open_inputs (ctf_file_t *fp, ctf_dynhash_t *cu_names,
  err:
   free (dedup_inputs);
   free (parents_);
-  ctf_err_warn (fp, 0, "Error in deduplicating CTF link input allocation: %s",
-		ctf_errmsg (ctf_errno (fp)));
+  ctf_err_warn (fp, 0, 0, _("error in deduplicating CTF link "
+			    "input allocation"));
   return NULL;
 }
 
@@ -1108,8 +1113,8 @@ ctf_link_deduplicating_close_inputs (ctf_file_t *fp, ctf_dynhash_t *cu_names,
 	}
       if (err != ECTF_NEXT_END)
 	{
-	  ctf_err_warn (fp, 0, "Iteration error in deduplicating link input "
-			"freeing: %s", ctf_errmsg (err));
+	  ctf_err_warn (fp, 0, err, _("iteration error in deduplicating link "
+				      "input freeing"));
 	  ctf_set_errno (fp, err);
 	}
     }
@@ -1186,8 +1191,9 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
 
       if (labs ((long int) ninputs) > 0xfffffffe)
 	{
-	  ctf_err_warn (fp, 0, "Too many inputs in deduplicating link: %li",
-			(long int) ninputs);
+	  ctf_err_warn (fp, 0, EFBIG, _("too many inputs in deduplicating "
+					"link: %li"), (long int) ninputs);
+	  ctf_set_errno (fp, EFBIG);
 	  goto err_open_inputs;
 	}
 
@@ -1209,9 +1215,9 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
 						  &ai, NULL, 0, &err);
 	  if (!only_input->clin_fp)
 	    {
-	      ctf_err_warn (fp, 0, "Cannot open archive %s in CU-mapped CTF "
-			    "link: %s", only_input->clin_filename,
-			    ctf_errmsg (err));
+	      ctf_err_warn (fp, 0, err, _("cannot open archive %s in "
+					  "CU-mapped CTF link"),
+			    only_input->clin_filename);
 	      ctf_set_errno (fp, err);
 	      goto err_open_inputs;
 	    }
@@ -1231,8 +1237,8 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
 					     only_input->clin_fp,
 					     out_name) < 0)
 		{
-		  ctf_err_warn (fp, 0, "Cannot add intermediate files "
-				"to link: %s", ctf_errmsg (ctf_errno (fp)));
+		  ctf_err_warn (fp, 0, 0, _("cannot add intermediate files "
+					    "to link"));
 		  goto err_open_inputs;
 		}
 	      only_input->clin_arc = NULL;
@@ -1255,8 +1261,9 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
 
       if ((out = ctf_create (&err)) == NULL)
 	{
-	  ctf_err_warn (fp, 0, "Cannot create per-CU CTF archive for %s: %s",
-		       out_name, ctf_errmsg (err));
+	  ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive "
+				      "for %s"),
+			out_name);
 	  ctf_set_errno (fp, err);
 	  goto err_inputs;
 	}
@@ -1272,17 +1279,18 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
 
       if (ctf_dedup (out, inputs, ninputs, parents, 1) < 0)
 	{
-	  ctf_err_warn (fp, 0, "CU-mapped deduplication failed for %s: %s",
-		       out_name, ctf_errmsg (ctf_errno (out)));
+	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplication failed for %s"),
+			out_name);
 	  goto err_inputs;
 	}
 
       if ((outputs = ctf_dedup_emit (out, inputs, ninputs, parents,
 				     &noutputs, 1)) == NULL)
 	{
-	  ctf_err_warn (fp, 0, "CU-mapped deduplicating link type emission "
-			"failed for %s: %s", out_name,
-			ctf_errmsg (ctf_errno (out)));
+	  ctf_set_errno (fp, ctf_errno (out));
+	  ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link type emission "
+				     "failed for %s"), out_name);
 	  goto err_inputs;
 	}
       if (!ctf_assert (fp, noutputs == 1))
@@ -1291,9 +1299,9 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
       if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
 	  && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0)
 	{
-	  ctf_err_warn (fp, 0, "CU-mapped deduplicating link variable "
-			"emission failed for %s: %s", out_name,
-			ctf_errmsg (ctf_errno (out)));
+	  ctf_set_errno (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;
 	}
 
@@ -1324,8 +1332,7 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
       if (ctf_link_add_ctf_internal (fp, in_arc, NULL,
 				     ctf_cuname (outputs[0])) < 0)
 	{
-	  ctf_err_warn (fp, 0, "Cannot add intermediate files to link: %s",
-			ctf_errmsg (ctf_errno (fp)));
+	  ctf_err_warn (fp, 0, 0, _("cannot add intermediate files to link"));
 	  goto err_outputs;
 	}
 
@@ -1355,8 +1362,8 @@ ctf_link_deduplicating_per_cu (ctf_file_t *fp)
     }
   if (err != ECTF_NEXT_END)
     {
-      ctf_err_warn (fp, 0, "Iteration error in CU-mapped deduplicating "
-		    "link: %s", ctf_errmsg (err));
+      ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating "
+				  "link"));
       return ctf_set_errno (fp, err);
     }
 
@@ -1375,8 +1382,7 @@ ctf_link_deduplicating (ctf_file_t *fp)
 
   if (ctf_dedup_atoms_init (fp) < 0)
     {
-      ctf_err_warn (fp, 0, "%s allocating CTF dedup atoms table",
-		    ctf_errmsg (ctf_errno (fp)));
+      ctf_err_warn (fp, 0, 0, _("allocating CTF dedup atoms table"));
       return;					/* Errno is set for us.  */
     }
 
@@ -1396,17 +1402,16 @@ ctf_link_deduplicating (ctf_file_t *fp)
 
   if (ctf_dedup (fp, inputs, ninputs, parents, 0) < 0)
     {
-      ctf_err_warn (fp, 0, "Deduplication failed for %s: %s",
-		    ctf_link_input_name (fp), ctf_errmsg (ctf_errno (fp)));
+      ctf_err_warn (fp, 0, 0, _("deduplication failed for %s"),
+		    ctf_link_input_name (fp));
       goto err;
     }
 
   if ((outputs = ctf_dedup_emit (fp, inputs, ninputs, parents, &noutputs,
 				 0)) == NULL)
     {
-      ctf_err_warn (fp, 0, "Deduplicating link type emission failed "
-		    "for %s: %s", ctf_link_input_name (fp),
-		    ctf_errmsg (ctf_errno (fp)));
+      ctf_err_warn (fp, 0, 0, _("deduplicating link type emission failed "
+				"for %s"), ctf_link_input_name (fp));
       goto err;
     }
 
@@ -1433,8 +1438,8 @@ ctf_link_deduplicating (ctf_file_t *fp)
       continue;
 
     oom_one_output:
-      ctf_err_warn (fp, 0, "Out of memory allocating link outputs");
       ctf_set_errno (fp, ENOMEM);
+      ctf_err_warn (fp, 0, 0, _("out of memory allocating link outputs"));
       free (dynname);
 
       for (; i < noutputs; i++)
@@ -1445,9 +1450,8 @@ ctf_link_deduplicating (ctf_file_t *fp)
   if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION)
       && ctf_link_deduplicating_variables (fp, inputs, ninputs, 0) < 0)
     {
-      ctf_err_warn (fp, 0, "Deduplicating link variable emission failed for "
-		    "%s: %s", ctf_link_input_name (fp),
-		    ctf_errmsg (ctf_errno (fp)));
+      ctf_err_warn (fp, 0, 0, _("deduplicating link variable emission failed for "
+				"%s"), ctf_link_input_name (fp));
       for (i = 1; i < noutputs; i++)
 	ctf_file_close (outputs[i]);
       goto err;
@@ -1517,8 +1521,7 @@ ctf_link (ctf_file_t *fp, int flags)
 	}
       if (err != ECTF_NEXT_END)
 	{
-	  ctf_err_warn (fp, 1, "Iteration error creating empty CUs: %s",
-			ctf_errmsg (err));
+	  ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs"));
 	  ctf_set_errno (fp, err);
 	  return -1;
 	}
@@ -1823,7 +1826,7 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
 	free (arg.dynames[i]);
       free (arg.dynames);
     }
-  ctf_err_warn (fp, 0, "Cannot write archive in link: %s failure: %s", errloc,
-		ctf_errmsg (ctf_errno (fp)));
+  ctf_err_warn (fp, 0, 0, _("cannot write archive in link: %s failure"),
+		errloc);
   return NULL;
 }
diff --git a/libctf/ctf-open-bfd.c b/libctf/ctf-open-bfd.c
index 9fcce2fa9cd..5541c9dd4dc 100644
--- a/libctf/ctf-open-bfd.c
+++ b/libctf/ctf-open-bfd.c
@@ -40,7 +40,8 @@ ctf_bfdclose (struct ctf_archive_internal *arci)
 {
   if (arci->ctfi_abfd != NULL)
     if (!bfd_close_all_done (arci->ctfi_abfd))
-      ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error()));
+      ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"),
+		    bfd_errmsg (bfd_get_error ()));
 }
 
 /* Open a CTF file given the specified BFD.  */
@@ -62,8 +63,9 @@ ctf_bfdopen (struct bfd *abfd, int *errp)
 
   if (!bfd_malloc_and_get_section (abfd, ctf_asect, &contents))
     {
-      ctf_dprintf ("ctf_bfdopen(): cannot malloc CTF section: %s\n",
-		   bfd_errmsg (bfd_get_error()));
+      ctf_err_warn (NULL, 0, 0, _("ctf_bfdopen(): cannot malloc "
+				  "CTF section: %s"),
+		    bfd_errmsg (bfd_get_error ()));
       return (ctf_set_open_errno (errp, ECTF_FMT));
     }
 
@@ -112,7 +114,7 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
       symcount = symhdr->sh_size / symhdr->sh_entsize;
       if ((symtab = malloc (symhdr->sh_size)) == NULL)
 	{
-	  bfderrstr = "Cannot malloc symbol table";
+	  bfderrstr = N_("cannot malloc symbol table");
 	  goto err;
 	}
 
@@ -121,7 +123,7 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
       free (isymbuf);
       if (isymbuf == NULL)
 	{
-	  bfderrstr = "Cannot read symbol table";
+	  bfderrstr = N_("cannot read symbol table");
 	  goto err_free_sym;
 	}
 
@@ -135,7 +137,7 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
 	    {
 	      if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL)
 		{
-		  bfderrstr = "Cannot read string table";
+		  bfderrstr = N_("cannot read string table");
 		  goto err_free_sym;
 		}
 	    }
@@ -199,7 +201,7 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
 err: _libctf_unused_;
   if (bfderrstr)
     {
-      ctf_dprintf ("ctf_bfdopen(): %s: %s\n", bfderrstr,
+      ctf_err_warn (NULL, 0, 0, "ctf_bfdopen(): %s: %s", gettext (bfderrstr),
 		   bfd_errmsg (bfd_get_error()));
       ctf_set_open_errno (errp, ECTF_FMT);
     }
@@ -283,18 +285,18 @@ ctf_fdopen (int fd, const char *filename, const char *target, int *errp)
 
   if ((abfd = bfd_fdopenr (filename, target, nfd)) == NULL)
     {
-      ctf_dprintf ("Cannot open BFD from %s: %s\n",
-		   filename ? filename : "(unknown file)",
-		   bfd_errmsg (bfd_get_error()));
+      ctf_err_warn (NULL, 0, 0, _("cannot open BFD from %s: %s"),
+		    filename ? filename : _("(unknown file)"),
+		    bfd_errmsg (bfd_get_error ()));
       return (ctf_set_open_errno (errp, ECTF_FMT));
     }
   bfd_set_cacheable (abfd, 1);
 
   if (!bfd_check_format (abfd, bfd_object))
     {
-      ctf_dprintf ("BFD format problem in %s: %s\n",
-		   filename ? filename : "(unknown file)",
-		   bfd_errmsg (bfd_get_error()));
+      ctf_err_warn (NULL, 0, 0, _("BFD format problem in %s: %s"),
+		    filename ? filename : _("(unknown file)"),
+		    bfd_errmsg (bfd_get_error ()));
       if (bfd_get_error() == bfd_error_file_ambiguously_recognized)
 	return (ctf_set_open_errno (errp, ECTF_BFD_AMBIGUOUS));
       else
@@ -304,7 +306,8 @@ ctf_fdopen (int fd, const char *filename, const char *target, int *errp)
   if ((arci = ctf_bfdopen (abfd, errp)) == NULL)
     {
       if (!bfd_close_all_done (abfd))
-	ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error()));
+	ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"),
+		      bfd_errmsg (bfd_get_error ()));
       return NULL;			/* errno is set for us.  */
     }
   arci->ctfi_bfd_close = ctf_bfdclose;
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index fee7789a308..8c301826167 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -141,8 +141,8 @@ get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp,
 }
 
 static ssize_t
-get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_,
-		   size_t vlen)
+get_vbytes_common (ctf_file_t *fp, unsigned short kind,
+		   ssize_t size _libctf_unused_, size_t vlen)
 {
   switch (kind)
     {
@@ -162,13 +162,14 @@ get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_,
     case CTF_K_RESTRICT:
       return 0;
     default:
-      ctf_dprintf ("detected invalid CTF kind -- %x\n", kind);
-      return ECTF_CORRUPT;
+      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
+      return -1;
     }
 }
 
 static ssize_t
-get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v1 (ctf_file_t *fp, unsigned short kind, ssize_t size, size_t vlen)
 {
   switch (kind)
     {
@@ -184,11 +185,11 @@ get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen)
 	return (sizeof (ctf_lmember_v1_t) * vlen);
     }
 
-  return (get_vbytes_common (kind, size, vlen));
+  return (get_vbytes_common (fp, kind, size, vlen));
 }
 
 static ssize_t
-get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v2 (ctf_file_t *fp, unsigned short kind, ssize_t size, size_t vlen)
 {
   switch (kind)
     {
@@ -204,7 +205,7 @@ get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen)
 	return (sizeof (ctf_lmember_t) * vlen);
     }
 
-  return (get_vbytes_common (kind, size, vlen));
+  return (get_vbytes_common (fp, kind, size, vlen));
 }
 
 static const ctf_fileops_t ctf_fileops[] = {
@@ -428,11 +429,11 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
       unsigned long vlen = CTF_V1_INFO_VLEN (tp->ctt_info);
 
       size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
-      vbytes = get_vbytes_v1 (kind, size, vlen);
+      vbytes = get_vbytes_v1 (fp, kind, size, vlen);
 
       get_ctt_size_v2_unconverted (fp, (const ctf_type_t *) tp, NULL,
 				   &v2increment);
-      v2bytes = get_vbytes_v2 (kind, size, vlen);
+      v2bytes = get_vbytes_v2 (fp, kind, size, vlen);
 
       if ((vbytes < 0) || (size < 0))
 	return ECTF_CORRUPT;
@@ -485,7 +486,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
       void *vdata, *v2data;
 
       size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
-      vbytes = get_vbytes_v1 (kind, size, vlen);
+      vbytes = get_vbytes_v1 (fp, kind, size, vlen);
 
       t2p->ctt_name = tp->ctt_name;
       t2p->ctt_info = CTF_TYPE_INFO (kind, isroot, vlen);
@@ -519,7 +520,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
 	}
 
       v2size = get_ctt_size_v2 (fp, t2p, NULL, &v2increment);
-      v2bytes = get_vbytes_v2 (kind, v2size, vlen);
+      v2bytes = get_vbytes_v2 (fp, kind, v2size, vlen);
 
       /* Catch out-of-sync get_ctt_size_*().  The count goes wrong if
 	 these are not identical (and having them different makes no
@@ -767,6 +768,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
 
       (void) ctf_get_ctt_size (fp, tp, &size, &increment);
       name = ctf_strptr (fp, tp->ctt_name);
+      /* Cannot fail: shielded by call in loop above.  */
       vbytes = LCTF_VBYTES (fp, kind, size, vlen);
 
       switch (kind)
@@ -905,8 +907,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
 	    return err;
 	  break;
 	default:
-	  ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n",
-		       kind);
+	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
+			_("init_types(): unhandled CTF kind: %x"), kind);
 	  return ECTF_CORRUPT;
 	}
 
@@ -1043,7 +1045,7 @@ flip_vars (void *start, size_t len)
    ctf_stype followed by variable data.  */
 
 static int
-flip_types (void *start, size_t len)
+flip_types (ctf_file_t *fp, void *start, size_t len)
 {
   ctf_type_t *t = start;
 
@@ -1056,7 +1058,7 @@ flip_types (void *start, size_t len)
       uint32_t kind = CTF_V2_INFO_KIND (t->ctt_info);
       size_t size = t->ctt_size;
       uint32_t vlen = CTF_V2_INFO_VLEN (t->ctt_info);
-      size_t vbytes = get_vbytes_v2 (kind, size, vlen);
+      size_t vbytes = get_vbytes_v2 (fp, kind, size, vlen);
 
       if (_libctf_unlikely_ (size == CTF_LSIZE_SENT))
 	{
@@ -1181,8 +1183,9 @@ flip_types (void *start, size_t len)
 	    break;
 	  }
 	default:
-	  ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n",
-		       kind);
+	  ctf_err_warn (fp, 0, ECTF_CORRUPT,
+			_("unhandled CTF kind in endianness conversion: %x"),
+			kind);
 	  return ECTF_CORRUPT;
 	}
 
@@ -1200,7 +1203,7 @@ flip_types (void *start, size_t len)
    data, this is no real loss.  */
 
 static int
-flip_ctf (ctf_header_t *cth, unsigned char *buf)
+flip_ctf (ctf_file_t *fp, ctf_header_t *cth, unsigned char *buf)
 {
   flip_lbls (buf + cth->cth_lbloff, cth->cth_objtoff - cth->cth_lbloff);
   flip_objts (buf + cth->cth_objtoff, cth->cth_funcoff - cth->cth_objtoff);
@@ -1208,7 +1211,7 @@ flip_ctf (ctf_header_t *cth, unsigned char *buf)
   flip_objts (buf + cth->cth_objtidxoff, cth->cth_funcidxoff - cth->cth_objtidxoff);
   flip_objts (buf + cth->cth_funcidxoff, cth->cth_varoff - cth->cth_funcidxoff);
   flip_vars (buf + cth->cth_varoff, cth->cth_typeoff - cth->cth_varoff);
-  return flip_types (buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff);
+  return flip_types (fp, buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff);
 }
 
 /* Set up the ctl hashes in a ctf_file_t.  Called by both writable and
@@ -1376,8 +1379,8 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 	 info.  We do not support dynamically upgrading such entries (none
 	 should exist in any case, since dwarf2ctf does not create them).  */
 
-      ctf_dprintf ("ctf_bufopen: CTF version %d symsect not "
-		   "supported\n", pp->ctp_version);
+      ctf_err_warn (NULL, 0, 0, _("ctf_bufopen: CTF version %d symsect not "
+				  "supported"), pp->ctp_version);
       return (ctf_set_open_errno (errp, ECTF_NOTSUP));
     }
 
@@ -1470,16 +1473,17 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
       if ((rc = uncompress (fp->ctf_base, &dstlen, src, srclen)) != Z_OK)
 	{
-	  ctf_dprintf ("zlib inflate err: %s\n", zError (rc));
+	  ctf_err_warn (NULL, 0, ECTF_DECOMPRESS, _("zlib inflate err: %s"),
+			zError (rc));
 	  err = ECTF_DECOMPRESS;
 	  goto bad;
 	}
 
       if ((size_t) dstlen != fp->ctf_size)
 	{
-	  ctf_dprintf ("zlib inflate short -- got %lu of %lu "
-		       "bytes\n", (unsigned long) dstlen,
-		       (unsigned long) fp->ctf_size);
+	  ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+			_("zlib inflate short: got %lu of %lu bytes"),
+			(unsigned long) dstlen, (unsigned long) fp->ctf_size);
 	  err = ECTF_CORRUPT;
 	  goto bad;
 	}
@@ -1559,7 +1563,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
   fp->ctf_syn_ext_strtab = syn_strtab;
 
   if (foreign_endian &&
-      (err = flip_ctf (hp, fp->ctf_buf)) != 0)
+      (err = flip_ctf (fp, hp, fp->ctf_buf)) != 0)
     {
       /* We can be certain that flip_ctf() will have endian-flipped everything
 	 other than the types table when we return.  In particular the header
@@ -1619,6 +1623,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
 bad:
   ctf_set_open_errno (errp, err);
+  ctf_err_warn_to_open (fp);
   ctf_file_close (fp);
   return NULL;
 }
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 583679defb4..837f66433c9 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -427,7 +427,7 @@ ctf_str_write_strtab (ctf_file_t *fp)
   nullstr = ctf_dynhash_lookup (fp->ctf_str_atoms, "");
   if (!nullstr)
     {
-      ctf_dprintf ("Internal error: null string not found in strtab.\n");
+      ctf_err_warn (fp, 0, ECTF_INTERNAL, _("null string not found in strtab"));
       strtab.cts_strs = NULL;
       return strtab;
     }
diff --git a/libctf/ctf-subr.c b/libctf/ctf-subr.c
index 15865706437..431b6d849f8 100644
--- a/libctf/ctf-subr.c
+++ b/libctf/ctf-subr.c
@@ -193,10 +193,16 @@ void ctf_dprintf (const char *format, ...)
     }
 }
 
-/* Errors and warnings.  */
-_libctf_printflike_ (3, 4)
+/* This needs more attention to thread-safety later on.  */
+static ctf_list_t open_errors;
+
+/* Errors and warnings.  Report the warning or error to the list in FP (or the
+   open errors list if NULL): if ERR is nonzero it is the errno to report to the
+   debug stream instead of that recorded on fp.  */
+_libctf_printflike_ (4, 5)
 extern void
-ctf_err_warn (ctf_file_t *fp, int is_warning, const char *format, ...)
+ctf_err_warn (ctf_file_t *fp, int is_warning, int err,
+	      const char *format, ...)
 {
   va_list alist;
   ctf_err_warning_t *cew;
@@ -219,26 +225,68 @@ ctf_err_warn (ctf_file_t *fp, int is_warning, const char *format, ...)
     }
   va_end (alist);
 
-  ctf_dprintf ("%s: %s\n", is_warning ? "error" : "warning", cew->cew_text);
+  /* Include the error code only if there is one, and if this is not a warning.
+     (Warnings may not have a meaningful error code, since the warning may not
+     lead to unwinding up to the user.)  */
+  if (!is_warning && (err != 0 || (fp && ctf_errno (fp) != 0)))
+    ctf_dprintf ("%s: %s (%s)\n", is_warning ? _("error") : _("warning"),
+		 cew->cew_text, err != 0 ? ctf_errmsg (err)
+		 : ctf_errmsg (ctf_errno (fp)));
+  else
+    ctf_dprintf ("%s: %s\n", is_warning ? _("error") : _("warning"),
+		 cew->cew_text);
+
+  if (fp != NULL)
+    ctf_list_append (&fp->ctf_errs_warnings, cew);
+  else
+    ctf_list_append (&open_errors, cew);
+}
 
-  ctf_list_append (&fp->ctf_errs_warnings, cew);
+/* Move all the errors/warnings from an fp into the open_errors.  */
+void
+ctf_err_warn_to_open (ctf_file_t *fp)
+{
+  ctf_list_splice (&open_errors, &fp->ctf_errs_warnings);
 }
 
 /* Error-warning reporting: an 'iterator' that returns errors and warnings from
    the error/warning list, in order of emission.  Errors and warnings are popped
-   after return: the caller must free the returned error-text pointer.  */
+   after return: the caller must free the returned error-text pointer.
+
+   An fp of NULL returns CTF-open-time errors from the open_errors variable
+   above.
+
+   The treatment of errors from this function itself is somewhat unusual: it
+   will often be called on an error path, so we don't want to overwrite the
+   ctf_errno unless we have no choice.  So, like ctf_bufopen et al, this
+   function takes an errp pointer where errors are reported.  The pointer is
+   optional: if not set, errors are reported via the fp (if non-NULL).  Calls
+   with neither fp nor errp set are mildly problematic because there is no clear
+   way to report end-of-iteration: you just have to assume that a NULL return
+   means the end, and not an iterator error.  */
+
 char *
-ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning)
+ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning,
+		     int *errp)
 {
   ctf_next_t *i = *it;
   char *ret;
+  ctf_list_t *errlist;
   ctf_err_warning_t *cew;
 
+  if (fp)
+    errlist = &fp->ctf_errs_warnings;
+  else
+    errlist = &open_errors;
+
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
 	{
-	  ctf_set_errno (fp, ENOMEM);
+	  if (errp)
+	    *errp = ENOMEM;
+	  else if (fp)
+	    ctf_set_errno (fp, ENOMEM);
 	  return NULL;
 	}
 
@@ -249,30 +297,39 @@ ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning)
 
   if ((void (*) (void)) ctf_errwarning_next != i->ctn_iter_fun)
     {
-      ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+      if (errp)
+	*errp = ECTF_NEXT_WRONGFUN;
+      else if (fp)
+	ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
       return NULL;
     }
 
   if (fp != i->cu.ctn_fp)
     {
-      ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+      if (errp)
+	*errp = ECTF_NEXT_WRONGFP;
+      else if (fp)
+	ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
       return NULL;
     }
 
-  cew = ctf_list_next (&fp->ctf_errs_warnings);
+  cew = ctf_list_next (errlist);
 
   if (!cew)
     {
       ctf_next_destroy (i);
       *it = NULL;
-      ctf_set_errno (fp, ECTF_NEXT_END);
+      if (errp)
+	*errp = ECTF_NEXT_END;
+      else if (fp)
+	ctf_set_errno (fp, ECTF_NEXT_END);
       return NULL;
     }
 
   if (is_warning)
     *is_warning = cew->cew_is_warning;
   ret = cew->cew_text;
-  ctf_list_delete (&fp->ctf_errs_warnings, cew);
+  ctf_list_delete (errlist, cew);
   free (cew);
   return ret;
 }
@@ -281,7 +338,7 @@ void
 ctf_assert_fail_internal (ctf_file_t *fp, const char *file, size_t line,
 			  const char *exprstr)
 {
-  ctf_err_warn (fp, 0, "%s: %lu: libctf assertion failed: %s", file,
-		(long unsigned int) line, exprstr);
+  ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
+		file, (long unsigned int) line, exprstr);
   ctf_set_errno (fp, ECTF_INTERNAL);
 }
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 4843de38d92..c9fed1558dd 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -606,7 +606,8 @@ ctf_type_resolve (ctf_file_t *fp, ctf_id_t type)
 	  if (tp->ctt_type == type || tp->ctt_type == otype
 	      || tp->ctt_type == prev)
 	    {
-	      ctf_dprintf ("type %ld cycle detected\n", otype);
+	      ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"),
+			    otype);
 	      return (ctf_set_errno (ofp, ECTF_CORRUPT));
 	    }
 	  prev = type;
-- 
2.28.0.248.gcf383e60c9


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

* [PATCH 3/3] binutils, ld: dequote libctf error messages
  2020-07-31 19:16 [PATCH 0/3] libctf: error handling improvements Nick Alcock
  2020-07-31 19:16 ` [PATCH 1/3] libctf, binutils: initial work towards libctf gettextization Nick Alcock
  2020-07-31 19:16 ` [PATCH 2/3] libctf, binutils, include, ld: gettextize and improve error handling Nick Alcock
@ 2020-07-31 19:16 ` Nick Alcock
  2020-08-20 15:15 ` [PATCH 0/3] libctf: error handling improvements Nick Alcock
  3 siblings, 0 replies; 9+ messages in thread
From: Nick Alcock @ 2020-07-31 19:16 UTC (permalink / raw)
  To: binutils

These are not identifiers and should not be quoted.  (Also, quoting them
just looks odd.)

Adjust diagnostics tests accordingly.

binutils/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* objdump.c (dump_ctf_errs): Unquote CTF error messages.
	* readelf.c (dump_ctf_errs): Likewise.

ld/ChangeLog
2020-07-27  Nick Alcock  <nick.alcock@oracle.com>

	* ldlang.c (dump_ctf_errs): Unquote CTF error messages.
	(ldlang_open_ctf): Likewise.
	(lang_merge_ctf): Likewise.
	(lang_write_ctf): Likewise.
	* testsuite/ld-ctf/diag-ctf-version-f.d: Adjust.
	* testsuite/ld-ctf/diag-cttname-invalid.d: Adjust.
	* testsuite/ld-ctf/diag-decompression-failure.d: Adjust.
	* testsuite/ld-ctf/diag-parname.d: Adjust.
	* testsuite/ld-ctf/diag-unsupported-flag.d: Adjust.
	* testsuite/ld-ctf/diag-wrong-magic-number-mixed.d: Adjust.
	* testsuite/ld-ctf/diag-wrong-magic-number.d: Adjust.
---
 binutils/objdump.c                                  | 2 +-
 binutils/readelf.c                                  | 2 +-
 ld/ldlang.c                                         | 8 ++++----
 ld/testsuite/ld-ctf/diag-ctf-version-f.d            | 2 +-
 ld/testsuite/ld-ctf/diag-cttname-invalid.d          | 2 +-
 ld/testsuite/ld-ctf/diag-decompression-failure.d    | 2 +-
 ld/testsuite/ld-ctf/diag-parname.d                  | 2 +-
 ld/testsuite/ld-ctf/diag-unsupported-flag.d         | 2 +-
 ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d | 2 +-
 ld/testsuite/ld-ctf/diag-wrong-magic-number.d       | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/binutils/objdump.c b/binutils/objdump.c
index c1848961416..c7ad51e41eb 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -4083,7 +4083,7 @@ dump_ctf_errs (ctf_file_t *fp)
   /* Dump accumulated errors and warnings.  */
   while ((errtext = ctf_errwarning_next (fp, &it, &is_warning, &err)) != NULL)
     {
-      non_fatal (_("%s: `%s'"), is_warning ? _("warning"): _("error"),
+      non_fatal (_("%s: %s"), is_warning ? _("warning"): _("error"),
 		 errtext);
       free (errtext);
     }
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 1466f7519aa..5e38b43312b 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -14217,7 +14217,7 @@ dump_ctf_errs (ctf_file_t *fp)
   /* Dump accumulated errors and warnings.  */
   while ((errtext = ctf_errwarning_next (fp, &it, &is_warning, &err)) != NULL)
     {
-      error (_("%s: `%s'"), is_warning ? _("warning"): _("error"),
+      error (_("%s: %s"), is_warning ? _("warning"): _("error"),
 	     errtext);
       free (errtext);
     }
diff --git a/ld/ldlang.c b/ld/ldlang.c
index dc6f1b40399..4249b3a045d 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3683,7 +3683,7 @@ lang_ctf_errs_warnings (ctf_file_t *fp)
 
   while ((text = ctf_errwarning_next (fp, &i, &is_warning, &err)) != NULL)
     {
-      einfo (_("%s: `%s'\n"), is_warning ? _("CTF warning"): _("CTF error"),
+      einfo (_("%s: %s\n"), is_warning ? _("CTF warning"): _("CTF error"),
 	     text);
       free (text);
     }
@@ -3724,7 +3724,7 @@ ldlang_open_ctf (void)
 	    {
 	      lang_ctf_errs_warnings (NULL);
 	      einfo (_("%P: warning: CTF section in %pB not loaded; "
-		       "its types will be discarded: `%s'\n"), file->the_bfd,
+		       "its types will be discarded: %s\n"), file->the_bfd,
 		     ctf_errmsg (err));
 	    }
 	  continue;
@@ -3814,7 +3814,7 @@ lang_merge_ctf (void)
     {
       lang_ctf_errs_warnings (ctf_output);
       einfo (_("%P: warning: CTF linking failed; "
-	       "output will have no CTF section: `%s'\n"),
+	       "output will have no CTF section: %s\n"),
 	     ctf_errmsg (ctf_errno (ctf_output)));
       if (output_sect)
 	{
@@ -3874,7 +3874,7 @@ lang_write_ctf (int late)
       if (!output_sect->contents)
 	{
 	  einfo (_("%P: warning: CTF section emission failed; "
-		   "output will have no CTF section: `%s'\n"),
+		   "output will have no CTF section: %s\n"),
 		 ctf_errmsg (ctf_errno (ctf_output)));
 	  output_sect->size = 0;
 	  output_sect->flags |= SEC_EXCLUDE;
diff --git a/ld/testsuite/ld-ctf/diag-ctf-version-f.d b/ld/testsuite/ld-ctf/diag-ctf-version-f.d
index 860aae92a32..811ed5b017b 100644
--- a/ld/testsuite/ld-ctf/diag-ctf-version-f.d
+++ b/ld/testsuite/ld-ctf/diag-ctf-version-f.d
@@ -2,4 +2,4 @@
 #source: diag-ctf-version-f.s
 #ld: -shared
 #name: Diagnostics - Unsupported CTF version
-#warning: CTF section .* not loaded; its types will be discarded: .CTF dict version is too new for libctf.
+#warning: CTF section .* not loaded; its types will be discarded: CTF dict version is too new for libctf
diff --git a/ld/testsuite/ld-ctf/diag-cttname-invalid.d b/ld/testsuite/ld-ctf/diag-cttname-invalid.d
index de4aedc8842..8755c7e6664 100644
--- a/ld/testsuite/ld-ctf/diag-cttname-invalid.d
+++ b/ld/testsuite/ld-ctf/diag-cttname-invalid.d
@@ -2,4 +2,4 @@
 #source: diag-cttname-invalid.s
 #ld: -shared
 #name: Diagnostics - Invalid type name.
-#warning: CTF section in .*not loaded; its types will be discarded: .String name offset is corrupt.
+#warning: CTF section in .*not loaded; its types will be discarded: String name offset is corrupt
diff --git a/ld/testsuite/ld-ctf/diag-decompression-failure.d b/ld/testsuite/ld-ctf/diag-decompression-failure.d
index c4567e10919..1deeea18044 100644
--- a/ld/testsuite/ld-ctf/diag-decompression-failure.d
+++ b/ld/testsuite/ld-ctf/diag-decompression-failure.d
@@ -2,4 +2,4 @@
 #source: diag-decompression-failure.s
 #ld: -shared
 #name: Diagnostics - Decompression failure
-#warning: CTF section.* not loaded; its types will be discarded: .Failed to decompress CTF data.
+#warning: CTF section.* not loaded; its types will be discarded: Failed to decompress CTF data
diff --git a/ld/testsuite/ld-ctf/diag-parname.d b/ld/testsuite/ld-ctf/diag-parname.d
index d2ce9aac81f..f8fcd683a9d 100644
--- a/ld/testsuite/ld-ctf/diag-parname.d
+++ b/ld/testsuite/ld-ctf/diag-parname.d
@@ -2,4 +2,4 @@
 #source: diag-parname.s
 #ld: -shared --ctf-variables
 #name: Diagnostics - No parent dictionary
-#warning: CTF linking failed; output will have no CTF section: .The parent CTF dictionary is unavailable.
+#warning: CTF linking failed; output will have no CTF section: The parent CTF dictionary is unavailable
diff --git a/ld/testsuite/ld-ctf/diag-unsupported-flag.d b/ld/testsuite/ld-ctf/diag-unsupported-flag.d
index 879781772aa..6b7a359e78c 100644
--- a/ld/testsuite/ld-ctf/diag-unsupported-flag.d
+++ b/ld/testsuite/ld-ctf/diag-unsupported-flag.d
@@ -2,4 +2,4 @@
 #source: diag-unsupported-flag.s
 #ld: -shared
 #name: Diagnostics - Unsupported flag
-#warning: CTF section.* not loaded; its types will be discarded: .CTF header contains flags unknown to libctf.
+#warning: CTF section.* not loaded; its types will be discarded: CTF header contains flags unknown to libctf
diff --git a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
index 5415c131940..1e3344750c9 100644
--- a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
+++ b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
@@ -3,7 +3,7 @@
 #source: B.c
 #ld: -shared --ctf-variables
 #name: Diagnostics - Wrong magic number mixed with valid CTF sections
-#warning: CTF section in .* not loaded; its types will be discarded: .Buffer does not contain CTF data.
+#warning: CTF section in .* not loaded; its types will be discarded: Buffer does not contain CTF data
 
 .*: +file format .*
 
diff --git a/ld/testsuite/ld-ctf/diag-wrong-magic-number.d b/ld/testsuite/ld-ctf/diag-wrong-magic-number.d
index 847bbf87240..0c27b0c996e 100644
--- a/ld/testsuite/ld-ctf/diag-wrong-magic-number.d
+++ b/ld/testsuite/ld-ctf/diag-wrong-magic-number.d
@@ -2,4 +2,4 @@
 #source: diag-wrong-magic-number.s
 #ld: -shared
 #name: Diagnostics - Wrong magic number
-#warning: CTF section in .* not loaded; its types will be discarded: .Buffer does not contain CTF data.
+#warning: CTF section in .* not loaded; its types will be discarded: Buffer does not contain CTF data
-- 
2.28.0.248.gcf383e60c9


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

* Re: [PATCH 0/3] libctf: error handling improvements
  2020-07-31 19:16 [PATCH 0/3] libctf: error handling improvements Nick Alcock
                   ` (2 preceding siblings ...)
  2020-07-31 19:16 ` [PATCH 3/3] binutils, ld: dequote libctf error messages Nick Alcock
@ 2020-08-20 15:15 ` Nick Alcock
  2020-08-21 13:15   ` Nick Clifton
  3 siblings, 1 reply; 9+ messages in thread
From: Nick Alcock @ 2020-08-20 15:15 UTC (permalink / raw)
  To: binutils

On 31 Jul 2020, Nick Alcock via Binutils outgrape:

> This does two interconnected things, done simultaneously because each touches
> the same large set of source lines: gettextization, and transitioning of all
> dprintfs used for error and warning handling to use the new ctf_errwarning_next
> infrastructure added in the recent deduplicator series (which means changing a
> lot of dprintfs into ctf_err_warns -- and also, because I changed the prototype
> of ctf_err_warn, changing all the *existing* uses of that function, too).

Ping?

These do need a bit of review here and there (there are a few changes
outside libctf/).

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

* Re: [PATCH 0/3] libctf: error handling improvements
  2020-08-20 15:15 ` [PATCH 0/3] libctf: error handling improvements Nick Alcock
@ 2020-08-21 13:15   ` Nick Clifton
  2020-08-25 22:57     ` Nick Alcock
  0 siblings, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2020-08-21 13:15 UTC (permalink / raw)
  To: Nick Alcock, binutils

Hi Nick,

>> This does two interconnected things, done simultaneously because each touches
>> the same large set of source lines: gettextization, and transitioning of all
>> dprintfs used for error and warning handling to use the new ctf_errwarning_next
>> infrastructure added in the recent deduplicator series (which means changing a
>> lot of dprintfs into ctf_err_warns -- and also, because I changed the prototype
>> of ctf_err_warn, changing all the *existing* uses of that function, too).
> 
> Ping?
> 
> These do need a bit of review here and there (there are a few changes
> outside libctf/).

Uh - can you point me at the original patch please ?
(I loose track of these things.  It must be my age).

Cheers
  Nick



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

* Re: [PATCH 0/3] libctf: error handling improvements
  2020-08-21 13:15   ` Nick Clifton
@ 2020-08-25 22:57     ` Nick Alcock
  2020-08-26  9:59       ` Nick Clifton
  0 siblings, 1 reply; 9+ messages in thread
From: Nick Alcock @ 2020-08-25 22:57 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 21 Aug 2020, Nick Clifton via Binutils told this:

> Uh - can you point me at the original patch please ?
> (I loose track of these things.  It must be my age).

Sure!

<https://sourceware.org/pipermail/binutils/2020-July/112674.html> and
followups. Message-ID of thread root: <20200731191617.148993-1-nick.alcock@oracle.com>

(I can resend if you'd rather.)

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

* Re: [PATCH 0/3] libctf: error handling improvements
  2020-08-25 22:57     ` Nick Alcock
@ 2020-08-26  9:59       ` Nick Clifton
  2020-08-31 22:07         ` Nick Alcock
  0 siblings, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2020-08-26  9:59 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

Hi Nick,

>> Uh - can you point me at the original patch please ?
>> (I loose track of these things.  It must be my age).
> 
> Sure!
> 
> <https://sourceware.org/pipermail/binutils/2020-July/112674.html> and

Thanks - that was exactly what I needed.

Patch series approved - please apply the lot! :-)

Cheers
  Nick



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

* Re: [PATCH 0/3] libctf: error handling improvements
  2020-08-26  9:59       ` Nick Clifton
@ 2020-08-31 22:07         ` Nick Alcock
  0 siblings, 0 replies; 9+ messages in thread
From: Nick Alcock @ 2020-08-31 22:07 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On 26 Aug 2020, Nick Clifton via Binutils spake thusly:

> Hi Nick,
>
>>> Uh - can you point me at the original patch please ?
>>> (I loose track of these things.  It must be my age).
>> 
>> Sure!
>> 
>> <https://sourceware.org/pipermail/binutils/2020-July/112674.html> and
>
> Thanks - that was exactly what I needed.
>
> Patch series approved - please apply the lot! :-)

(FYI: thank you, pushed. And then forgot to hit send on the email saying
as much and left it languishing unsent for days! sorry.)

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

end of thread, other threads:[~2020-08-31 22:07 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-31 19:16 [PATCH 0/3] libctf: error handling improvements Nick Alcock
2020-07-31 19:16 ` [PATCH 1/3] libctf, binutils: initial work towards libctf gettextization Nick Alcock
2020-07-31 19:16 ` [PATCH 2/3] libctf, binutils, include, ld: gettextize and improve error handling Nick Alcock
2020-07-31 19:16 ` [PATCH 3/3] binutils, ld: dequote libctf error messages Nick Alcock
2020-08-20 15:15 ` [PATCH 0/3] libctf: error handling improvements Nick Alcock
2020-08-21 13:15   ` Nick Clifton
2020-08-25 22:57     ` Nick Alcock
2020-08-26  9:59       ` Nick Clifton
2020-08-31 22:07         ` Nick Alcock

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