+2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-api.h (ECTF_*): Improve comments.
+       (ECTF_NERR): New.
+
 2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-api.h: Fix typos in comments.
 
 
 enum
   {
-   ECTF_FMT = ECTF_BASE,       /* File is not in CTF or ELF format.  */
-   ECTF_BFDERR,                        /* BFD error.  */
-   ECTF_CTFVERS,               /* CTF version is more recent than libctf.  */
-   ECTF_BFD_AMBIGUOUS,         /* Ambiguous BFD target.  */
-   ECTF_SYMTAB,                        /* Symbol table uses invalid entry size.  */
-   ECTF_SYMBAD,                        /* Symbol table data buffer invalid.  */
-   ECTF_STRBAD,                        /* String table data buffer invalid.  */
-   ECTF_CORRUPT,               /* File data corruption detected.  */
-   ECTF_NOCTFDATA,             /* ELF file does not contain CTF data.  */
-   ECTF_NOCTFBUF,              /* Buffer does not contain CTF data.  */
-   ECTF_NOSYMTAB,              /* Symbol table data is not available.  */
-   ECTF_NOPARENT,              /* Parent CTF container is not available.  */
-   ECTF_DMODEL,                        /* Data model mismatch.  */
-   ECTF_LINKADDEDLATE,         /* File added to link too late.  */
-   ECTF_ZALLOC,                        /* Failed to allocate (de)compression buffer.  */
-   ECTF_DECOMPRESS,            /* Failed to decompress CTF data.  */
-   ECTF_STRTAB,                        /* String table for this string is missing.  */
-   ECTF_BADNAME,               /* String offset is corrupt w.r.t. strtab.  */
-   ECTF_BADID,                 /* Invalid type ID number.  */
-   ECTF_NOTSOU,                        /* Type is not a struct or union.  */
-   ECTF_NOTENUM,               /* Type is not an enum.  */
-   ECTF_NOTSUE,                        /* Type is not a struct, union, or enum.  */
-   ECTF_NOTINTFP,              /* Type is not an integer, float, or enum.  */
-   ECTF_NOTARRAY,              /* Type is not an array.  */
-   ECTF_NOTREF,                        /* Type does not reference another type.  */
-   ECTF_NAMELEN,               /* Buffer is too small to hold type name.  */
-   ECTF_NOTYPE,                        /* No type found corresponding to name.  */
-   ECTF_SYNTAX,                        /* Syntax error in type name.  */
-   ECTF_NOTFUNC,               /* Symbol entry or type is not a function.  */
-   ECTF_NOFUNCDAT,             /* No func info available for function.  */
-   ECTF_NOTDATA,               /* Symtab entry does not refer to a data obj.  */
-   ECTF_NOTYPEDAT,             /* No type info available for object.  */
-   ECTF_NOLABEL,               /* No label found corresponding to name.  */
-   ECTF_NOLABELDATA,           /* File does not contain any labels.  */
-   ECTF_NOTSUP,                        /* Feature not supported.  */
-   ECTF_NOENUMNAM,             /* Enum element name not found.  */
-   ECTF_NOMEMBNAM,             /* Member name not found.  */
-   ECTF_RDONLY,                        /* CTF container is read-only.  */
-   ECTF_DTFULL,                        /* CTF type is full (no more members allowed).  */
-   ECTF_FULL,                  /* CTF container is full.  */
-   ECTF_DUPLICATE,             /* Duplicate member or variable name.  */
-   ECTF_CONFLICT,              /* Conflicting type definition present.  */
-   ECTF_OVERROLLBACK,          /* Attempt to roll back past a ctf_update.  */
-   ECTF_COMPRESS,              /* Failed to compress CTF data.  */
-   ECTF_ARCREATE,              /* Error creating CTF archive.  */
-   ECTF_ARNNAME,               /* Name not found in CTF archive.  */
-   ECTF_SLICEOVERFLOW,         /* Overflow of type bitness or offset in slice.  */
-   ECTF_DUMPSECTUNKNOWN,       /* Unknown section number in dump.  */
-   ECTF_DUMPSECTCHANGED,       /* Section changed in middle of dump.  */
-   ECTF_NOTYET,                        /* Feature not yet implemented.  */
-   ECTF_INTERNAL,              /* Internal error in link.  */
-   ECTF_NONREPRESENTABLE       /* Type not representable in CTF.  */
+   ECTF_FMT = ECTF_BASE, /* File is not in CTF or ELF format.  */
+   ECTF_BFDERR,                /* BFD error.  */
+   ECTF_CTFVERS,       /* CTF dict version is too new for libctf.  */
+   ECTF_BFD_AMBIGUOUS, /* Ambiguous BFD target.  */
+   ECTF_SYMTAB,                /* Symbol table uses invalid entry size.  */
+   ECTF_SYMBAD,                /* Symbol table data buffer is not valid.  */
+   ECTF_STRBAD,                /* String table data buffer is not valid.  */
+   ECTF_CORRUPT,       /* File data structure corruption detected.  */
+   ECTF_NOCTFDATA,     /* File does not contain CTF data.  */
+   ECTF_NOCTFBUF,      /* Buffer does not contain CTF data.  */
+   ECTF_NOSYMTAB,      /* Symbol table information is not available.  */
+   ECTF_NOPARENT,      /* The parent CTF dictionary is unavailable.  */
+   ECTF_DMODEL,                /* Data model mismatch.  */
+   ECTF_LINKADDEDLATE, /* File added to link too late.  */
+   ECTF_ZALLOC,                /* Failed to allocate (de)compression buffer.  */
+   ECTF_DECOMPRESS,    /* Failed to decompress CTF data.  */
+   ECTF_STRTAB,                /* External string table is not available.  */
+   ECTF_BADNAME,       /* String name offset is corrupt.  */
+   ECTF_BADID,         /* Invalid type identifier.  */
+   ECTF_NOTSOU,                /* Type is not a struct or union.  */
+   ECTF_NOTENUM,       /* Type is not an enum.  */
+   ECTF_NOTSUE,                /* Type is not a struct, union, or enum.  */
+   ECTF_NOTINTFP,      /* Type is not an integer, float, or enum.  */
+   ECTF_NOTARRAY,      /* Type is not an array.  */
+   ECTF_NOTREF,                /* Type does not reference another type.  */
+   ECTF_NAMELEN,       /* Buffer is too small to hold type name.  */
+   ECTF_NOTYPE,                /* No type found corresponding to name.  */
+   ECTF_SYNTAX,                /* Syntax error in type name.  */
+   ECTF_NOTFUNC,       /* Symbol table entry or type is not a function.  */
+   ECTF_NOFUNCDAT,     /* No function information available for function.  */
+   ECTF_NOTDATA,       /* Symbol table entry does not refer to a data object.  */
+   ECTF_NOTYPEDAT,     /* No type information available for symbol.  */
+   ECTF_NOLABEL,       /* No label found corresponding to name.  */
+   ECTF_NOLABELDATA,   /* File does not contain any labels.  */
+   ECTF_NOTSUP,                /* Feature not supported.  */
+   ECTF_NOENUMNAM,     /* Enum element name not found.  */
+   ECTF_NOMEMBNAM,     /* Member name not found.  */
+   ECTF_RDONLY,                /* CTF container is read-only.  */
+   ECTF_DTFULL,                /* CTF type is full (no more members allowed).  */
+   ECTF_FULL,          /* CTF container is full.  */
+   ECTF_DUPLICATE,     /* Duplicate member or variable name.  */
+   ECTF_CONFLICT,      /* Conflicting type is already defined.  */
+   ECTF_OVERROLLBACK,  /* Attempt to roll back past a ctf_update.  */
+   ECTF_COMPRESS,      /* Failed to compress CTF data.  */
+   ECTF_ARCREATE,      /* Error creating CTF archive.  */
+   ECTF_ARNNAME,       /* Name not found in CTF archive.  */
+   ECTF_SLICEOVERFLOW, /* Overflow of type bitness or offset in slice.  */
+   ECTF_DUMPSECTUNKNOWN, /* Unknown section number in dump.  */
+   ECTF_DUMPSECTCHANGED, /* Section changed in middle of dump.  */
+   ECTF_NOTYET,                /* Feature not yet implemented.  */
+   ECTF_INTERNAL,      /* Internal error in link.  */
+   ECTF_NONREPRESENTABLE /* Type not representable in CTF.  */
   };
 
+#define ECTF_NERR (ECTF_NONREPRESENTABLE - ECTF_BASE + 1)      /* Count of CTF errors.  */
+
 /* The CTF data model is inferred to be the caller's data model or the data
    model of the given object, unless ctf_setmodel() is explicitly called.  */
 #define        CTF_MODEL_ILP32 1       /* Object data model is ILP32.  */
 
--- /dev/null
+ctf-error.h
 
+2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-error.c: Include <stddef.h>, for offsetof.
+       (_ctf_errlist): Migrate to...
+       (_ctf_errlist_t): ... this.
+       (_ctf_erridx): New, indexes into _ctf_errlist_t.
+       (_ctf_nerr): Remove.
+       (ctf_errmsg): Adjust accordingly.
+       * Makefile.am (BUILT_SOURCES): Note...
+       (ctf-error.h): ... this new rule.
+       * Makefile.in: Regenerate.
+       * mkerrors.sed: New, process ctf-api.h to generate ctf-error.h.
+       * .gitignore: New, ignore ctf-error.h.
+
 2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-impl.h: Fix typos in comments.
 
 libctf_la_DEPENDENCIES = @BFD_DEPENDENCIES@
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
+
+BUILT_SOURCES = ctf-error.h
+
+ctf-error.h: $(srcdir)/mkerrors.sed $(srcdir)/../include/ctf-api.h
+       sed -nf $(srcdir)/mkerrors.sed < $(srcdir)/../include/ctf-api.h > $@
 
 libctf_la_DEPENDENCIES = @BFD_DEPENDENCIES@
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
-all: config.h
+BUILT_SOURCES = ctf-error.h
+all: $(BUILT_SOURCES) config.h
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
               $(distcleancheck_listfiles) ; \
               exit 1; } >&2
 check-am: all-am
-check: check-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
 all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
 installdirs:
        for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
          test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
-install: install-am
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
 install-exec: install-exec-am
 install-data: install-data-am
 uninstall: uninstall-am
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-am
 
 clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
 
 uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
 
-.MAKE: all install-am install-strip
+.MAKE: all check install install-am install-strip
 
 .PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
        clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
 .PRECIOUS: Makefile
 
 
+ctf-error.h: $(srcdir)/mkerrors.sed $(srcdir)/../include/ctf-api.h
+       sed -nf $(srcdir)/mkerrors.sed < $(srcdir)/../include/ctf-api.h > $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
 
    <http://www.gnu.org/licenses/>.  */
 
 #include <ctf-impl.h>
+#include <stddef.h>
 
-static const char *const _ctf_errlist[] = {
-  "File is not in CTF or ELF format",               /* ECTF_FMT */
-  "BFD error",                                      /* ECTF_BFDERR */
-  "File uses more recent CTF version than libctf",   /* ECTF_CTFVERS */
-  "Ambiguous BFD target",                           /* ECTF_BFD_AMBIGUOUS */
-  "Symbol table uses invalid entry size",           /* ECTF_SYMTAB */
-  "Symbol table data buffer is not valid",          /* ECTF_SYMBAD */
-  "String table data buffer is not valid",          /* ECTF_STRBAD */
-  "File data structure corruption detected",        /* ECTF_CORRUPT */
-  "File does not contain CTF data",                 /* ECTF_NOCTFDATA */
-  "Buffer does not contain CTF data",               /* ECTF_NOCTFBUF */
-  "Symbol table information is not available",      /* ECTF_NOSYMTAB */
-  "Type information is in parent and unavailable",   /* ECTF_NOPARENT */
-  "Cannot import types with different data model",   /* ECTF_DMODEL */
-  "File added to link too late",                    /* ECTF_LINKADDEDLATE */
-  "Failed to allocate (de)compression buffer",      /* ECTF_ZALLOC */
-  "Failed to decompress CTF data",                  /* ECTF_DECOMPRESS */
-  "External string table is not available",         /* ECTF_STRTAB */
-  "String name offset is corrupt",                  /* ECTF_BADNAME */
-  "Invalid type identifier",                        /* ECTF_BADID */
-  "Type is not a struct or union",                  /* ECTF_NOTSOU */
-  "Type is not an enum",                            /* ECTF_NOTENUM */
-  "Type is not a struct, union, or enum",           /* ECTF_NOTSUE */
-  "Type is not an integer, float, or enum",         /* ECTF_NOTINTFP */
-  "Type is not an array",                           /* ECTF_NOTARRAY */
-  "Type does not reference another type",           /* ECTF_NOTREF */
-  "Input buffer is too small for type name",        /* ECTF_NAMELEN */
-  "No type information available for that name",     /* ECTF_NOTYPE */
-  "Syntax error in type name",                      /* ECTF_SYNTAX */
-  "Symbol table entry or type is not a function",    /* ECTF_NOTFUNC */
-  "No function information available for symbol",    /* ECTF_NOFUNCDAT */
-  "Symbol table entry is not a data object",        /* ECTF_NOTDATA */
-  "No type information available for symbol",       /* ECTF_NOTYPEDAT */
-  "No label information available for that name",    /* ECTF_NOLABEL */
-  "File does not contain any labels",               /* ECTF_NOLABELDATA */
-  "Feature not supported",                          /* ECTF_NOTSUP */
-  "Invalid enum element name",                      /* ECTF_NOENUMNAM */
-  "Invalid member name",                            /* ECTF_NOMEMBNAM */
-  "CTF container is read-only",                             /* ECTF_RDONLY */
-  "Limit on number of dynamic type members reached", /* ECTF_DTFULL */
-  "Limit on number of dynamic types reached",       /* ECTF_FULL */
-  "Duplicate member or variable name",              /* ECTF_DUPLICATE */
-  "Conflicting type is already defined",            /* ECTF_CONFLICT */
-  "Attempt to roll back past a ctf_update",         /* ECTF_OVERROLLBACK */
-  "Failed to compress CTF data",                    /* ECTF_COMPRESS */
-  "Failed to create CTF archive",                   /* ECTF_ARCREATE */
-  "Name not found in CTF archive",                  /* ECTF_ARNNAME */
-  "Overflow of type bitness or offset in slice",     /* ECTF_SLICEOVERFLOW */
-  "Unknown section number in dump",                 /* ECTF_DUMPSECTUNKNOWN */
-  "Section changed in middle of dump",              /* ECTF_DUMPSECTCHANGED */
-  "Feature not yet implemented",                    /* ECTF_NOTYET */
-  "Internal error in link",                         /* ECTF_INTERNAL */
-  "Type not representable in CTF"                   /* ECTF_NONREPRESENTABLE */
-};
-
-static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);
+/* This construct is due to Bruno Haible: much thanks.  */
+
+/* Give each structure member a unique name.  The name does not matter, so we
+   use the line number in ctf-error.h to uniquify them.  */
+
+#define ERRSTRFIELD(line) ERRSTRFIELD1 (line)
+#define ERRSTRFIELD1(line) ctf_errstr##line
+
+/* The error message strings, each in a unique structure member precisely big
+   enough for that error, plus a str member to access them all as a string
+   table.  */
+
+static const union _ctf_errlist_t
+{
+  __extension__ struct
+  {
+#define _CTF_STR(n, s) char ERRSTRFIELD (__LINE__) [sizeof (s)];
+#include "ctf-error.h"
+#undef _CTF_STR
+  };
+  char str[1];
+} _ctf_errlist =
+  {
+   {
+#define _CTF_STR(n, s) s,
+#include "ctf-error.h"
+#undef _CTF_STR
+   }
+  };
+
+/* Offsets to each member in the string table, computed using offsetof.  */
+
+static const unsigned int _ctf_erridx[] =
+  {
+#define _CTF_STR(n, s) [n - ECTF_BASE] = offsetof (union _ctf_errlist_t, ERRSTRFIELD (__LINE__)),
+#include "ctf-error.h"
+#undef _CTF_STR
+  };
 
 const char *
 ctf_errmsg (int error)
 {
   const char *str;
 
-  if (error >= ECTF_BASE && (error - ECTF_BASE) < _ctf_nerr)
-    str = _ctf_errlist[error - ECTF_BASE];
+  if (error >= ECTF_BASE && (error - ECTF_BASE) < ECTF_NERR)
+    str = _ctf_errlist.str + _ctf_erridx[error - ECTF_BASE];
   else
     str = ctf_strerror (error);
 
 
--- /dev/null
+#
+#   Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+# Only process lines in the error-define block
+/= ECTF_BASE/,/ECTF_NERR/ {
+    # Do not process non-errors (braces, ECTF_NERR, etc).
+    /^ *ECTF_/!n;
+    # Strip out the base initializer.
+    s, = ECTF_BASE,,;
+    # Transform errors into _STR(...).
+    s@^ *\(ECTF_[^[:blank:],]*\),\{0,1\}[[:blank:]]*/\* \(.*\).  \*/$@_CTF_STR (\1, "\2")@;
+    p;
+  }