+2020-08-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.
+
 2020-08-27  Nick Alcock  <nick.alcock@oracle.com>
 
        * Makefile.am (readelf_LDADD): Move $(LIBINTL) after $(LIBCTF_NOBFD).
 
   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
                          "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.
        }
     }
 
-  /* 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;
 }
   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));
     }
       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));
        }
      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));
     }
 
   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
                          "Function objects", "Variables", "Types", "Strings",
                          ""};
   const char **thing;
-  ctf_next_t *it = NULL;
-  char *errtext;
-  int is_warning;
   size_t i;
   int err = 0;
 
     }
 
  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;
 }
 
 
   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;
     }
       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;
        }
      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;
     }
 
+2020-08-27  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-api.h (ctf_errwarning_next): New err parameter.
+
 2020-08-26  Nick Clifton  <nickc@redhat.com>
 
        PR 26405
 
    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 *);
 
+2020-08-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.
+
 2020-08-27  Jeremy Drake  <sourceware-bugzilla@jdrake.com>
 
        PR 19011
 
 }
 
 #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.  */
       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;
        }
 
     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.  */
 
 
   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)));
          output_sect->flags |= SEC_EXCLUDE;
        }
     }
+  /* Output any lingering errors that didn't come from ctf_link.  */
   lang_ctf_errs_warnings (ctf_output);
 }
 
       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; "
          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.  */
 
     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 {
     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)
+}
 
+2020-08-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).
+
 2020-08-27  Nick Alcock  <nick.alcock@oracle.com>
 
        * configure.ac: Adjust package name to simply 'libctf': arbitrarily
 
   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;
     }
 
   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;
     }
 
       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;
        }
 
   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);
       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;
 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;
 }
 
 
    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;
 
   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;
     }
 
     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:
       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;
        }
     }
   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;
     }
 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;
 }
 
     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;
   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;
   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;
     }
 
       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)
 
   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)
 {
 
   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;
 
   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;
          || (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));
        }
     }
 
          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));
            }
        }
            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));
              }
 
          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));
            }
        }
   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;
     }
 
       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;
       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;
                     + 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;
     }
 
       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;
        }
   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;
     }
   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;
     }
 
 #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,         \
 
       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
                            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",
                                       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",
                                         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",
 
        if (ctf_array_info (input, type, &ar) < 0)
          {
-           whaterr = "array info";
+           whaterr = N_("error getting array info");
            goto err;
          }
 
                                         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",
                                         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",
 
        if (ctf_func_type_info (input, type, &fi) < 0)
          {
-           whaterr = "func type info";
+           whaterr = N_("error getting func type info");
            goto err;
          }
 
                                         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",
 
        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++)
                                             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",
          }
        if (ctf_errno (input) != ECTF_NEXT_END)
          {
-           whaterr = "enum member iteration";
+           whaterr = N_("error doing enum member iteration");
            goto err;
          }
        break;
                                             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;
              }
 
          }
        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)
     {
   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;
 }
 
 
   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.  */
     }
 
 
       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. */
        }
     }
  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;
 }
 
          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,
   void *k;
   void *v;
   int err;
-  const char *erm;
+  const char *whaterr;
 
   /* Go through cd_name_counts for all CTF namespaces in turn.  */
 
                }
              if (err != ECTF_NEXT_END)
                {
-                 erm = "marking conflicting structs/unions";
+                 whaterr = N_("error marking conflicting structs/unions");
                  goto iterr;
                }
            }
            }
          if (err != ECTF_NEXT_END)
            {
-             erm = "finding commonest conflicting type";
+             whaterr = N_("error finding commonest conflicting type");
              goto iterr;
            }
 
                           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;
     }
 
 
  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:
   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);
 }
 
     }
   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)
   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
        }
       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;
        }
     }
 
     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,        \
     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:
 
        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;
       }
 
 
        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;
 
         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,
 
  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;
 }
   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);
     }
 
       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);
        }
     }
     }
   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);
     }
 
     }
   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;
     }
       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;
        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;
        }
   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.  */
 
          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);
   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);
       /* 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)
 
     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))
     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.  */
 
          {
            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));
              }
       }
 
     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,
     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,
       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.  */
       {
        ctf_arinfo_t ar;
 
-       erm = "array info";
+       errtype = _("array info");
        if (ctf_array_info (input, type, &ar) < 0)
          goto err_input;
 
        ctf_id_t *args;
        uint32_t j;
 
-       erm = "function";
+       errtype = _("function");
        if (ctf_func_type_info (input, type, &fi) < 0)
          goto err_input;
 
            goto err_input;
          }
 
-       erm = "function args";
+       errtype = _("function args");
        if (ctf_func_type_args (input, type, fi.ctc_argc, args) < 0)
          {
            free (args);
        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
        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
       && 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);
     }
 
   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
   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
   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);
 }
 
 
   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.  */
     }
 
     {
       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]));
        }
     }
 
   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;
     }
 
  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);
     {
       char *str;
       char *bit = NULL;
-      const char *err;
       const char *sym_name;
       ctf_funcinfo_t fi;
       ctf_id_t type;
       /* 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.  */
       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));
 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)
          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;
     }
 
   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.  */
 }
 
   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
   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.  */
 #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 */
 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 *);
 
     {
       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));
        }
 
 
 
       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;
        }
 
   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);
     }
 
       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.  */
 
   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
 
       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;
 #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
       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;
     }
                                                 &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;
       }
 
   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
     }
   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;
     }
  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;
 }
 
        }
       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);
        }
     }
 
       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;
        }
 
                                                  &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;
            }
                                             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;
 
       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;
        }
 
       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))
       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;
        }
 
       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;
        }
 
     }
   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);
     }
 
 
   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.  */
     }
 
 
   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;
     }
 
       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++)
   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;
        }
       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;
        }
        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;
 }
 
 {
   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.  */
 
   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));
     }
 
       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;
        }
 
       free (isymbuf);
       if (isymbuf == NULL)
        {
-         bfderrstr = "Cannot read symbol table";
+         bfderrstr = N_("cannot read symbol table");
          goto err_free_sym;
        }
 
            {
              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;
                }
            }
 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);
     }
 
   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
   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;
 
 }
 
 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)
     {
     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)
     {
        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)
     {
        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[] = {
       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;
       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);
        }
 
       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
 
       (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)
            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;
        }
 
    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;
 
       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))
        {
            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;
        }
 
    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);
   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
         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));
     }
 
 
       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;
        }
   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
 
 bad:
   ctf_set_open_errno (errp, err);
+  ctf_err_warn_to_open (fp);
   ctf_file_close (fp);
   return NULL;
 }
 
   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;
     }
 
     }
 }
 
-/* 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;
     }
   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;
        }
 
 
   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;
 }
 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);
 }
 
          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;