]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - libctf/ctf-open.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / libctf / ctf-open.c
index 285e0e0ff7105216565b86d6c7c89eb05bea6f53..55f0a74164a137e05f6d30230cd60e26c78d3ea4 100644 (file)
@@ -1,5 +1,5 @@
 /* Opening CTF files.
-   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+   Copyright (C) 2019-2021 Free Software Foundation, Inc.
 
    This file is part of libctf.
 
 #include <string.h>
 #include <sys/types.h>
 #include <elf.h>
-#include <assert.h>
 #include "swap.h"
 #include <bfd.h>
 #include <zlib.h>
 
-#include "elf-bfd.h"
-
 static const ctf_dmodel_t _libctf_models[] = {
   {"ILP32", CTF_MODEL_ILP32, 4, 1, 2, 4, 4},
   {"LP64", CTF_MODEL_LP64, 8, 1, 2, 4, 8},
@@ -77,7 +74,7 @@ get_vlen_v2 (uint32_t info)
 }
 
 static inline ssize_t
-get_ctt_size_common (const ctf_file_t *fp _libctf_unused_,
+get_ctt_size_common (const ctf_dict_t *fp _libctf_unused_,
                     const ctf_type_t *tp _libctf_unused_,
                     ssize_t *sizep, ssize_t *incrementp, size_t lsize,
                     size_t csize, size_t ctf_type_size,
@@ -105,7 +102,7 @@ get_ctt_size_common (const ctf_file_t *fp _libctf_unused_,
 }
 
 static ssize_t
-get_ctt_size_v1 (const ctf_file_t *fp, const ctf_type_t *tp,
+get_ctt_size_v1 (const ctf_dict_t *fp, const ctf_type_t *tp,
                 ssize_t *sizep, ssize_t *incrementp)
 {
   ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp;
@@ -119,7 +116,7 @@ get_ctt_size_v1 (const ctf_file_t *fp, const ctf_type_t *tp,
 /* Return the size that a v1 will be once it is converted to v2.  */
 
 static ssize_t
-get_ctt_size_v2_unconverted (const ctf_file_t *fp, const ctf_type_t *tp,
+get_ctt_size_v2_unconverted (const ctf_dict_t *fp, const ctf_type_t *tp,
                             ssize_t *sizep, ssize_t *incrementp)
 {
   ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp;
@@ -131,7 +128,7 @@ get_ctt_size_v2_unconverted (const ctf_file_t *fp, const ctf_type_t *tp,
 }
 
 static ssize_t
-get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp,
+get_ctt_size_v2 (const ctf_dict_t *fp, const ctf_type_t *tp,
                 ssize_t *sizep, ssize_t *incrementp)
 {
   return (get_ctt_size_common (fp, tp, sizep, incrementp,
@@ -141,8 +138,8 @@ get_ctt_size_v2 (const ctf_file_t *fp, const ctf_type_t *tp,
 }
 
 static ssize_t
-get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_,
-                  size_t vlen)
+get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
+                  ssize_t size _libctf_unused_, size_t vlen)
 {
   switch (kind)
     {
@@ -162,13 +159,14 @@ get_vbytes_common (unsigned short kind, ssize_t size _libctf_unused_,
     case CTF_K_RESTRICT:
       return 0;
     default:
-      ctf_dprintf ("detected invalid CTF kind -- %x\n", kind);
-      return ECTF_CORRUPT;
+      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
+      return -1;
     }
 }
 
 static ssize_t
-get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v1 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen)
 {
   switch (kind)
     {
@@ -184,11 +182,11 @@ get_vbytes_v1 (unsigned short kind, ssize_t size, size_t vlen)
        return (sizeof (ctf_lmember_v1_t) * vlen);
     }
 
-  return (get_vbytes_common (kind, size, vlen));
+  return (get_vbytes_common (fp, kind, size, vlen));
 }
 
 static ssize_t
-get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v2 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen)
 {
   switch (kind)
     {
@@ -204,10 +202,10 @@ get_vbytes_v2 (unsigned short kind, ssize_t size, size_t vlen)
        return (sizeof (ctf_lmember_t) * vlen);
     }
 
-  return (get_vbytes_common (kind, size, vlen));
+  return (get_vbytes_common (fp, kind, size, vlen));
 }
 
-static const ctf_fileops_t ctf_fileops[] = {
+static const ctf_dictops_t ctf_dictops[] = {
   {NULL, NULL, NULL, NULL, NULL},
   /* CTF_VERSION_1 */
   {get_kind_v1, get_root_v1, get_vlen_v1, get_ctt_size_v1, get_vbytes_v1},
@@ -219,55 +217,95 @@ static const ctf_fileops_t ctf_fileops[] = {
   {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
 };
 
-/* Initialize the symtab translation table by filling each entry with the
-  offset of the CTF type or function data corresponding to each STT_FUNC or
-  STT_OBJECT entry in the symbol table.  */
+/* Initialize the symtab translation table as appropriate for its indexing
+   state.  For unindexed symtypetabs, fill each entry with the offset of the CTF
+   type or function data corresponding to each STT_FUNC or STT_OBJECT entry in
+   the symbol table.  For indexed symtypetabs, do nothing: the needed
+   initialization for indexed lookups may be quite expensive, so it is done only
+   as needed, when lookups happen.  (In particular, the majority of indexed
+   symtypetabs come from the compiler, and all the linker does is iteration over
+   all entries, which doesn't need this initialization.)
+
+   The SP symbol table section may be NULL if there is no symtab.
+
+   If init_symtab works on one call, it cannot fail on future calls to the same
+   fp: ctf_symsect_endianness relies on this.  */
 
 static int
-init_symtab (ctf_file_t *fp, const ctf_header_t *hp,
-            const ctf_sect_t *sp, const ctf_sect_t *strp)
+init_symtab (ctf_dict_t *fp, const ctf_header_t *hp, const ctf_sect_t *sp)
 {
-  const unsigned char *symp = sp->cts_data;
+  const unsigned char *symp;
+  int skip_func_info = 0;
+  int i;
   uint32_t *xp = fp->ctf_sxlate;
   uint32_t *xend = xp + fp->ctf_nsyms;
 
   uint32_t objtoff = hp->cth_objtoff;
   uint32_t funcoff = hp->cth_funcoff;
 
-  uint32_t info, vlen;
-  Elf64_Sym sym, *gsp;
-  const char *name;
-
-  /* The CTF data object and function type sections are ordered to match
-     the relative order of the respective symbol types in the symtab.
-     If no type information is available for a symbol table entry, a
-     pad is inserted in the CTF section.  As a further optimization,
-     anonymous or undefined symbols are omitted from the CTF data.  */
-
-  for (; xp < xend; xp++, symp += sp->cts_entsize)
+  /* If the CTF_F_NEWFUNCINFO flag is not set, pretend the func info section
+     is empty: this compiler is too old to emit a function info section we
+     understand.  */
+
+  if (!(hp->cth_flags & CTF_F_NEWFUNCINFO))
+    skip_func_info = 1;
+
+  if (hp->cth_objtidxoff < hp->cth_funcidxoff)
+    fp->ctf_objtidx_names = (uint32_t *) (fp->ctf_buf + hp->cth_objtidxoff);
+  if (hp->cth_funcidxoff < hp->cth_varoff && !skip_func_info)
+    fp->ctf_funcidx_names = (uint32_t *) (fp->ctf_buf + hp->cth_funcidxoff);
+
+  /* Don't bother doing the rest if everything is indexed, or if we don't have a
+     symbol table: we will never use it.  */
+  if ((fp->ctf_objtidx_names && fp->ctf_funcidx_names) || !sp || !sp->cts_data)
+    return 0;
+
+  /* The CTF data object and function type sections are ordered to match the
+     relative order of the respective symbol types in the symtab, unless there
+     is an index section, in which case the order is arbitrary and the index
+     gives the mapping.  If no type information is available for a symbol table
+     entry, a pad is inserted in the CTF section.  As a further optimization,
+     anonymous or undefined symbols are omitted from the CTF data.  If an
+     index is available for function symbols but not object symbols, or vice
+     versa, we populate the xslate table for the unindexed symbols only.  */
+
+  for (i = 0, symp = sp->cts_data; xp < xend; xp++, symp += sp->cts_entsize,
+        i++)
     {
-      if (sp->cts_entsize == sizeof (Elf32_Sym))
-       gsp = ctf_sym_to_elf64 ((Elf32_Sym *) (uintptr_t) symp, &sym);
-      else
-       gsp = (Elf64_Sym *) (uintptr_t) symp;
+      ctf_link_sym_t sym;
 
-      if (gsp->st_name < strp->cts_size)
-       name = (const char *) strp->cts_data + gsp->st_name;
-      else
-       name = _CTF_NULLSTR;
+      switch (sp->cts_entsize)
+       {
+       case sizeof (Elf64_Sym):
+         {
+           const Elf64_Sym *symp64 = (Elf64_Sym *) (uintptr_t) symp;
+           ctf_elf64_to_link_sym (fp, &sym, symp64, i);
+         }
+         break;
+       case sizeof (Elf32_Sym):
+         {
+           const Elf32_Sym *symp32 = (Elf32_Sym *) (uintptr_t) symp;
+           ctf_elf32_to_link_sym (fp, &sym, symp32, i);
+         }
+         break;
+       default:
+         return ECTF_SYMTAB;
+       }
 
-      if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF
-         || strcmp (name, "_START_") == 0 || strcmp (name, "_END_") == 0)
+      /* This call may be led astray if our idea of the symtab's endianness is
+        wrong, but when this is fixed by a call to ctf_symsect_endianness,
+        init_symtab will be called again with the right endianness in
+        force.  */
+      if (ctf_symtab_skippable (&sym))
        {
          *xp = -1u;
          continue;
        }
 
-      switch (ELF64_ST_TYPE (gsp->st_info))
+      switch (sym.st_type)
        {
        case STT_OBJECT:
-         if (objtoff >= hp->cth_funcoff
-             || (gsp->st_shndx == SHN_EXTABS && gsp->st_value == 0))
+         if (fp->ctf_objtidx_names || objtoff >= hp->cth_funcoff)
            {
              *xp = -1u;
              break;
@@ -278,25 +316,15 @@ init_symtab (ctf_file_t *fp, const ctf_header_t *hp,
          break;
 
        case STT_FUNC:
-         if (funcoff >= hp->cth_objtidxoff)
+         if (fp->ctf_funcidx_names || funcoff >= hp->cth_objtidxoff
+             || skip_func_info)
            {
              *xp = -1u;
              break;
            }
 
          *xp = funcoff;
-
-         info = *(uint32_t *) ((uintptr_t) fp->ctf_buf + funcoff);
-         vlen = LCTF_INFO_VLEN (fp, info);
-
-         /* If we encounter a zero pad at the end, just skip it.  Otherwise
-            skip over the function and its return type (+2) and the argument
-            list (vlen).
-          */
-         if (LCTF_INFO_KIND (fp, info) == CTF_K_UNKNOWN && vlen == 0)
-           funcoff += sizeof (uint32_t);       /* Skip pad.  */
-         else
-           funcoff += sizeof (uint32_t) * (vlen + 2);
+         funcoff += sizeof (uint32_t);
          break;
 
        default:
@@ -310,14 +338,14 @@ init_symtab (ctf_file_t *fp, const ctf_header_t *hp,
 }
 
 /* Reset the CTF base pointer and derive the buf pointer from it, initializing
-   everything in the ctf_file that depends on the base or buf pointers.
+   everything in the ctf_dict that depends on the base or buf pointers.
 
    The original gap between the buf and base pointers, if any -- the original,
    unconverted CTF header -- is kept, but its contents are not specified and are
    never used.  */
 
 static void
-ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base)
+ctf_set_base (ctf_dict_t *fp, const ctf_header_t *hp, unsigned char *base)
 {
   fp->ctf_buf = base + (fp->ctf_buf - fp->ctf_base);
   fp->ctf_base = base;
@@ -329,8 +357,8 @@ ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base)
     + hp->cth_stroff;
   fp->ctf_str[CTF_STRTAB_0].cts_len = hp->cth_strlen;
 
-  /* If we have a parent container name and label, store the relocated
-     string pointers in the CTF container for easy access later. */
+  /* If we have a parent dict name and label, store the relocated string
+     pointers in the CTF dict for easy access later. */
 
   /* Note: before conversion, these will be set to values that will be
      immediately invalidated by the conversion process, but the conversion
@@ -358,11 +386,11 @@ ctf_set_base (ctf_file_t *fp, const ctf_header_t *hp, unsigned char *base)
    caller must ensure this has been done in advance.  */
 
 static void
-ctf_set_version (ctf_file_t *fp, ctf_header_t *cth, int ctf_version)
+ctf_set_version (ctf_dict_t *fp, ctf_header_t *cth, int ctf_version)
 {
   fp->ctf_version = ctf_version;
   cth->cth_version = ctf_version;
-  fp->ctf_fileops = &ctf_fileops[ctf_version];
+  fp->ctf_dictops = &ctf_dictops[ctf_version];
 }
 
 
@@ -396,7 +424,7 @@ upgrade_header (ctf_header_t *hp)
    Type kinds not checked here due to nonexistence in older formats:
       CTF_K_SLICE.  */
 static int
-upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
+upgrade_types_v1 (ctf_dict_t *fp, ctf_header_t *cth)
 {
   const ctf_type_v1_t *tbuf;
   const ctf_type_v1_t *tend;
@@ -428,11 +456,11 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
       unsigned long vlen = CTF_V1_INFO_VLEN (tp->ctt_info);
 
       size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
-      vbytes = get_vbytes_v1 (kind, size, vlen);
+      vbytes = get_vbytes_v1 (fp, kind, size, vlen);
 
       get_ctt_size_v2_unconverted (fp, (const ctf_type_t *) tp, NULL,
                                   &v2increment);
-      v2bytes = get_vbytes_v2 (kind, size, vlen);
+      v2bytes = get_vbytes_v2 (fp, kind, size, vlen);
 
       if ((vbytes < 0) || (size < 0))
        return ECTF_CORRUPT;
@@ -485,7 +513,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
       void *vdata, *v2data;
 
       size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
-      vbytes = get_vbytes_v1 (kind, size, vlen);
+      vbytes = get_vbytes_v1 (fp, kind, size, vlen);
 
       t2p->ctt_name = tp->ctt_name;
       t2p->ctt_info = CTF_TYPE_INFO (kind, isroot, vlen);
@@ -519,7 +547,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
        }
 
       v2size = get_ctt_size_v2 (fp, t2p, NULL, &v2increment);
-      v2bytes = get_vbytes_v2 (kind, v2size, vlen);
+      v2bytes = get_vbytes_v2 (fp, kind, v2size, vlen);
 
       /* Catch out-of-sync get_ctt_size_*().  The count goes wrong if
         these are not identical (and having them different makes no
@@ -620,7 +648,7 @@ upgrade_types_v1 (ctf_file_t *fp, ctf_header_t *cth)
 
 /* Upgrade from any earlier version.  */
 static int
-upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
+upgrade_types (ctf_dict_t *fp, ctf_header_t *cth)
 {
   switch (cth->cth_version)
     {
@@ -648,7 +676,7 @@ upgrade_types (ctf_file_t *fp, ctf_header_t *cth)
    recension of libctf supports upgrading.  */
 
 static int
-init_types (ctf_file_t *fp, ctf_header_t *cth)
+init_types (ctf_dict_t *fp, ctf_header_t *cth)
 {
   const ctf_type_t *tbuf;
   const ctf_type_t *tend;
@@ -658,8 +686,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
   uint32_t id, dst;
   uint32_t *xp;
 
-  /* We determine whether the container is a child or a parent based on
-     the value of cth_parname.  */
+  /* We determine whether the dict is a child or a parent based on the value of
+     cth_parname.  */
 
   int child = cth->cth_parname != 0;
   int nlstructs = 0, nlunions = 0;
@@ -703,11 +731,11 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
 
   if (child)
     {
-      ctf_dprintf ("CTF container %p is a child\n", (void *) fp);
+      ctf_dprintf ("CTF dict %p is a child\n", (void *) fp);
       fp->ctf_flags |= LCTF_CHILD;
     }
   else
-    ctf_dprintf ("CTF container %p is a parent\n", (void *) fp);
+    ctf_dprintf ("CTF dict %p is a parent\n", (void *) fp);
 
   /* Now that we've counted up the number of each type, we can allocate
      the hash tables, type translation table, and pointer table.  */
@@ -767,6 +795,7 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
 
       (void) ctf_get_ctt_size (fp, tp, &size, &increment);
       name = ctf_strptr (fp, tp->ctt_name);
+      /* Cannot fail: shielded by call in loop above.  */
       vbytes = LCTF_VBYTES (fp, kind, size, vlen);
 
       switch (kind)
@@ -883,9 +912,9 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
          }
 
        case CTF_K_POINTER:
-         /* If the type referenced by the pointer is in this CTF container,
-            then store the index of the pointer type in
-            fp->ctf_ptrtab[ index of referenced type ].  */
+         /* If the type referenced by the pointer is in this CTF dict, then
+            store the index of the pointer type in fp->ctf_ptrtab[ index of
+            referenced type ].  */
 
          if (LCTF_TYPE_ISCHILD (fp, tp->ctt_type) == child
              && LCTF_TYPE_TO_INDEX (fp, tp->ctt_type) <= fp->ctf_typemax)
@@ -905,8 +934,8 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
            return err;
          break;
        default:
-         ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n",
-                      kind);
+         ctf_err_warn (fp, 0, ECTF_CORRUPT,
+                       _("init_types(): unhandled CTF kind: %x"), kind);
          return ECTF_CORRUPT;
        }
 
@@ -951,28 +980,6 @@ init_types (ctf_file_t *fp, ctf_header_t *cth)
    We flip everything, mindlessly, even 1-byte entities, so that future
    expansions do not require changes to this code.  */
 
-/* < C11? define away static assertions.  */
-
-#if !defined (__STDC_VERSION__) || __STDC_VERSION__ < 201112L
-#define _Static_assert(cond, err)
-#endif
-
-/* Swap the endianness of something.  */
-
-#define swap_thing(x)                                                  \
-  do {                                                                 \
-    _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0            \
-                                       && sizeof (x) <= 8),            \
-                   "Invalid size, update endianness code");            \
-    switch (sizeof (x)) {                                              \
-    case 2: x = bswap_16 (x); break;                                   \
-    case 4: x = bswap_32 (x); break;                                   \
-    case 8: x = bswap_64 (x); break;                                   \
-    case 1: /* Nothing needs doing */                                  \
-      break;                                                           \
-    }                                                                  \
-  } while (0);
-
 /* Flip the endianness of the CTF header.  */
 
 static void
@@ -1010,9 +1017,7 @@ flip_lbls (void *start, size_t len)
 }
 
 /* Flip the endianness of the data-object or function sections or their indexes,
-   all arrays of uint32_t.  (The function section has more internal structure,
-   but that structure is an array of uint32_t, so can be treated as one big
-   array for byte-swapping.)  */
+   all arrays of uint32_t.  */
 
 static void
 flip_objts (void *start, size_t len)
@@ -1043,7 +1048,7 @@ flip_vars (void *start, size_t len)
    ctf_stype followed by variable data.  */
 
 static int
-flip_types (void *start, size_t len)
+flip_types (ctf_dict_t *fp, void *start, size_t len)
 {
   ctf_type_t *t = start;
 
@@ -1056,7 +1061,7 @@ flip_types (void *start, size_t len)
       uint32_t kind = CTF_V2_INFO_KIND (t->ctt_info);
       size_t size = t->ctt_size;
       uint32_t vlen = CTF_V2_INFO_VLEN (t->ctt_info);
-      size_t vbytes = get_vbytes_v2 (kind, size, vlen);
+      size_t vbytes = get_vbytes_v2 (fp, kind, size, vlen);
 
       if (_libctf_unlikely_ (size == CTF_LSIZE_SENT))
        {
@@ -1181,8 +1186,9 @@ flip_types (void *start, size_t len)
            break;
          }
        default:
-         ctf_dprintf ("unhandled CTF kind in endianness conversion -- %x\n",
-                      kind);
+         ctf_err_warn (fp, 0, ECTF_CORRUPT,
+                       _("unhandled CTF kind in endianness conversion: %x"),
+                       kind);
          return ECTF_CORRUPT;
        }
 
@@ -1200,7 +1206,7 @@ flip_types (void *start, size_t len)
    data, this is no real loss.  */
 
 static int
-flip_ctf (ctf_header_t *cth, unsigned char *buf)
+flip_ctf (ctf_dict_t *fp, ctf_header_t *cth, unsigned char *buf)
 {
   flip_lbls (buf + cth->cth_lbloff, cth->cth_objtoff - cth->cth_lbloff);
   flip_objts (buf + cth->cth_objtoff, cth->cth_funcoff - cth->cth_objtoff);
@@ -1208,12 +1214,12 @@ flip_ctf (ctf_header_t *cth, unsigned char *buf)
   flip_objts (buf + cth->cth_objtidxoff, cth->cth_funcidxoff - cth->cth_objtidxoff);
   flip_objts (buf + cth->cth_funcidxoff, cth->cth_varoff - cth->cth_funcidxoff);
   flip_vars (buf + cth->cth_varoff, cth->cth_typeoff - cth->cth_varoff);
-  return flip_types (buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff);
+  return flip_types (fp, buf + cth->cth_typeoff, cth->cth_stroff - cth->cth_typeoff);
 }
 
-/* Set up the ctl hashes in a ctf_file_t.  Called by both writable and
+/* Set up the ctl hashes in a ctf_dict_t.  Called by both writable and
    non-writable dictionary initialization.  */
-void ctf_set_ctl_hashes (ctf_file_t *fp)
+void ctf_set_ctl_hashes (ctf_dict_t *fp)
 {
   /* Initialize the ctf_lookup_by_name top-level dictionary.  We keep an
      array of type name prefixes and the corresponding ctf_hash to use.  */
@@ -1236,7 +1242,7 @@ void ctf_set_ctl_hashes (ctf_file_t *fp)
 
 /* Open a CTF file, mocking up a suitable ctf_sect.  */
 
-ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
+ctf_dict_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
                             const char *symsect, size_t symsect_size,
                             size_t symsect_entsize,
                             const char *strsect, size_t strsect_size,
@@ -1250,7 +1256,7 @@ ctf_file_t *ctf_simple_open (const char *ctfsect, size_t ctfsect_size,
 /* Open a CTF file, mocking up a suitable ctf_sect and overriding the external
    strtab with a synthetic one.  */
 
-ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
+ctf_dict_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
                                      const char *symsect, size_t symsect_size,
                                      size_t symsect_entsize,
                                      const char *strsect, size_t strsect_size,
@@ -1297,11 +1303,11 @@ ctf_file_t *ctf_simple_open_internal (const char *ctfsect, size_t ctfsect_size,
 }
 
 /* Decode the specified CTF buffer and optional symbol table, and create a new
-   CTF container representing the symbolic debugging information.  This code can
+   CTF dict representing the symbolic debugging information.  This code can
    be used directly by the debugger, or it can be used as the engine for
    ctf_fdopen() or ctf_open(), below.  */
 
-ctf_file_t *
+ctf_dict_t *
 ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
             const ctf_sect_t *strsect, int *errp)
 {
@@ -1310,7 +1316,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
 /* Like ctf_bufopen, but overriding the external strtab with a synthetic one.  */
 
-ctf_file_t *
+ctf_dict_t *
 ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
                      const ctf_sect_t *strsect, ctf_dynhash_t *syn_strtab,
                      int writable, int *errp)
@@ -1318,7 +1324,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
   const ctf_preamble_t *pp;
   size_t hdrsz = sizeof (ctf_header_t);
   ctf_header_t *hp;
-  ctf_file_t *fp;
+  ctf_dict_t *fp;
   int foreign_endian = 0;
   int err;
 
@@ -1376,8 +1382,9 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
         info.  We do not support dynamically upgrading such entries (none
         should exist in any case, since dwarf2ctf does not create them).  */
 
-      ctf_dprintf ("ctf_bufopen: CTF version %d symsect not "
-                  "supported\n", pp->ctp_version);
+      ctf_err_warn (NULL, 0, ECTF_NOTSUP, _("ctf_bufopen: CTF version %d "
+                                           "symsect not supported"),
+                   pp->ctp_version);
       return (ctf_set_open_errno (errp, ECTF_NOTSUP));
     }
 
@@ -1385,15 +1392,20 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
     hdrsz = sizeof (ctf_header_v2_t);
 
   if (_libctf_unlikely_ (pp->ctp_flags > CTF_F_MAX))
-    return (ctf_set_open_errno (errp, ECTF_FLAGS));
+    {
+      ctf_err_warn (NULL, 0, ECTF_FLAGS, _("ctf_bufopen: invalid header "
+                                          "flags: %x"),
+                   (unsigned int) pp->ctp_flags);
+      return (ctf_set_open_errno (errp, ECTF_FLAGS));
+    }
 
   if (ctfsect->cts_size < hdrsz)
     return (ctf_set_open_errno (errp, ECTF_NOCTFBUF));
 
-  if ((fp = malloc (sizeof (ctf_file_t))) == NULL)
+  if ((fp = malloc (sizeof (ctf_dict_t))) == NULL)
     return (ctf_set_open_errno (errp, ENOMEM));
 
-  memset (fp, 0, sizeof (ctf_file_t));
+  memset (fp, 0, sizeof (ctf_dict_t));
 
   if (writable)
     fp->ctf_flags |= LCTF_RDWR;
@@ -1420,7 +1432,10 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
       || hp->cth_funcoff > fp->ctf_size || hp->cth_objtidxoff > fp->ctf_size
       || hp->cth_funcidxoff > fp->ctf_size || hp->cth_typeoff > fp->ctf_size
       || hp->cth_stroff > fp->ctf_size)
-    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    {
+      ctf_err_warn (NULL, 0, ECTF_CORRUPT, _("header offset exceeds CTF size"));
+      return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    }
 
   if (hp->cth_lbloff > hp->cth_objtoff
       || hp->cth_objtoff > hp->cth_funcoff
@@ -1429,13 +1444,46 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
       || hp->cth_objtidxoff > hp->cth_funcidxoff
       || hp->cth_funcidxoff > hp->cth_varoff
       || hp->cth_varoff > hp->cth_typeoff || hp->cth_typeoff > hp->cth_stroff)
-    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    {
+      ctf_err_warn (NULL, 0, ECTF_CORRUPT, _("overlapping CTF sections"));
+      return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    }
 
   if ((hp->cth_lbloff & 3) || (hp->cth_objtoff & 2)
       || (hp->cth_funcoff & 2) || (hp->cth_objtidxoff & 2)
       || (hp->cth_funcidxoff & 2) || (hp->cth_varoff & 3)
       || (hp->cth_typeoff & 3))
-    return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    {
+      ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+                   _("CTF sections not properly aligned"));
+      return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    }
+
+  /* This invariant will be lifted in v4, but for now it is true.  */
+
+  if ((hp->cth_funcidxoff - hp->cth_objtidxoff != 0) &&
+      (hp->cth_funcidxoff - hp->cth_objtidxoff
+       != hp->cth_funcoff - hp->cth_objtoff))
+    {
+      ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+                   _("Object index section exists is neither empty nor the "
+                     "same length as the object section: %u versus %u "
+                     "bytes"), hp->cth_funcoff - hp->cth_objtoff,
+                   hp->cth_funcidxoff - hp->cth_objtidxoff);
+      return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    }
+
+  if ((hp->cth_varoff - hp->cth_funcidxoff != 0) &&
+      (hp->cth_varoff - hp->cth_funcidxoff
+       != hp->cth_objtidxoff - hp->cth_funcoff))
+    {
+      ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+                   _("Function index section exists is neither empty nor the "
+                     "same length as the function section: %u versus %u "
+                     "bytes"), hp->cth_objtidxoff - hp->cth_funcoff,
+                   hp->cth_varoff - hp->cth_funcidxoff);
+      return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+    }
 
   /* Once everything is determined to be valid, attempt to decompress the CTF
      data buffer if it is compressed, or copy it into new storage if it is not
@@ -1470,16 +1518,17 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
       if ((rc = uncompress (fp->ctf_base, &dstlen, src, srclen)) != Z_OK)
        {
-         ctf_dprintf ("zlib inflate err: %s\n", zError (rc));
+         ctf_err_warn (NULL, 0, ECTF_DECOMPRESS, _("zlib inflate err: %s"),
+                       zError (rc));
          err = ECTF_DECOMPRESS;
          goto bad;
        }
 
       if ((size_t) dstlen != fp->ctf_size)
        {
-         ctf_dprintf ("zlib inflate short -- got %lu of %lu "
-                      "bytes\n", (unsigned long) dstlen,
-                      (unsigned long) fp->ctf_size);
+         ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+                       _("zlib inflate short: got %lu of %lu bytes"),
+                       (unsigned long) dstlen, (unsigned long) fp->ctf_size);
          err = ECTF_CORRUPT;
          goto bad;
        }
@@ -1507,7 +1556,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
     }
 
   /* Once we have uncompressed and validated the CTF data buffer, we can
-     proceed with initializing the ctf_file_t we allocated above.
+     proceed with initializing the ctf_dict_t we allocated above.
 
      Nothing that depends on buf or base should be set directly in this function
      before the init_types() call, because it may be reallocated during
@@ -1559,7 +1608,7 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
   fp->ctf_syn_ext_strtab = syn_strtab;
 
   if (foreign_endian &&
-      (err = flip_ctf (hp, fp->ctf_buf)) != 0)
+      (err = flip_ctf (fp, hp, fp->ctf_buf)) != 0)
     {
       /* We can be certain that flip_ctf() will have endian-flipped everything
         other than the types table when we return.  In particular the header
@@ -1571,8 +1620,8 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
   ctf_set_base (fp, hp, fp->ctf_base);
 
-  /* No need to do anything else for dynamic containers: they do not support
-     symbol lookups, and the type table is maintained in the dthashes.  */
+  /* No need to do anything else for dynamic dicts: they do not support symbol
+     lookups, and the type table is maintained in the dthashes.  */
   if (fp->ctf_flags & LCTF_RDWR)
     {
       fp->ctf_refcnt = 1;
@@ -1582,10 +1631,18 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
   if ((err = init_types (fp, hp)) != 0)
     goto bad;
 
-  /* If we have a symbol table section, allocate and initialize
-     the symtab translation table, pointed to by ctf_sxlate.  This table may be
-     too large for the actual size of the object and function info sections: if
-     so, ctf_nsyms will be adjusted and the excess will never be used.  */
+  /* Allocate and initialize the symtab translation table, pointed to by
+     ctf_sxlate, and the corresponding index sections.  This table may be too
+     large for the actual size of the object and function info sections: if so,
+     ctf_nsyms will be adjusted and the excess will never be used.  It's
+     possible to do indexed symbol lookups even without a symbol table, so check
+     even in that case.  Initially, we assume the symtab is native-endian: if it
+     isn't, the caller will inform us later by calling ctf_symsect_endianness.  */
+#ifdef WORDS_BIGENDIAN
+  fp->ctf_symsect_little_endian = 0;
+#else
+  fp->ctf_symsect_little_endian = 1;
+#endif
 
   if (symsect != NULL)
     {
@@ -1597,11 +1654,11 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
          err = ENOMEM;
          goto bad;
        }
-
-      if ((err = init_symtab (fp, hp, symsect, strsect)) != 0)
-       goto bad;
     }
 
+  if ((err = init_symtab (fp, hp, symsect)) != 0)
+    goto bad;
+
   ctf_set_ctl_hashes (fp);
 
   if (symsect != NULL)
@@ -1619,37 +1676,39 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
 
 bad:
   ctf_set_open_errno (errp, err);
-  ctf_file_close (fp);
+  ctf_err_warn_to_open (fp);
+  ctf_dict_close (fp);
   return NULL;
 }
 
-/* Bump the refcount on the specified CTF container, to allow export of
-   ctf_file_t's from iterators that open and close the ctf_file_t around the
-   loop.  (This does not extend their lifetime beyond that of the ctf_archive_t
-   in which they are contained.)  */
+/* Bump the refcount on the specified CTF dict, to allow export of ctf_dict_t's
+   from iterators that open and close the ctf_dict_t around the loop.  (This
+   does not extend their lifetime beyond that of the ctf_archive_t in which they
+   are contained.)  */
 
 void
-ctf_ref (ctf_file_t *fp)
+ctf_ref (ctf_dict_t *fp)
 {
   fp->ctf_refcnt++;
 }
 
-/* Close the specified CTF container and free associated data structures.  Note
-   that ctf_file_close() is a reference counted operation: if the specified file
-   is the parent of other active containers, its reference count will be greater
-   than one and it will be freed later when no active children exist.  */
+/* Close the specified CTF dict and free associated data structures.  Note that
+   ctf_dict_close() is a reference counted operation: if the specified file is
+   the parent of other active dict, its reference count will be greater than one
+   and it will be freed later when no active children exist.  */
 
 void
-ctf_file_close (ctf_file_t *fp)
+ctf_dict_close (ctf_dict_t *fp)
 {
   ctf_dtdef_t *dtd, *ntd;
   ctf_dvdef_t *dvd, *nvd;
+  ctf_in_flight_dynsym_t *did, *nid;
   ctf_err_warning_t *err, *nerr;
 
   if (fp == NULL)
-    return;               /* Allow ctf_file_close(NULL) to simplify caller code.  */
+    return;               /* Allow ctf_dict_close(NULL) to simplify caller code.  */
 
-  ctf_dprintf ("ctf_file_close(%p) refcnt=%u\n", (void *) fp, fp->ctf_refcnt);
+  ctf_dprintf ("ctf_dict_close(%p) refcnt=%u\n", (void *) fp, fp->ctf_refcnt);
 
   if (fp->ctf_refcnt > 1)
     {
@@ -1667,7 +1726,7 @@ ctf_file_close (ctf_file_t *fp)
   free (fp->ctf_dyncuname);
   free (fp->ctf_dynparname);
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
-    ctf_file_close (fp->ctf_parent);
+    ctf_dict_close (fp->ctf_parent);
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
     {
@@ -1696,6 +1755,20 @@ ctf_file_close (ctf_file_t *fp)
       ctf_dvd_delete (fp, dvd);
     }
   ctf_dynhash_destroy (fp->ctf_dvhash);
+
+  free (fp->ctf_funcidx_sxlate);
+  free (fp->ctf_objtidx_sxlate);
+  ctf_dynhash_destroy (fp->ctf_objthash);
+  ctf_dynhash_destroy (fp->ctf_funchash);
+  free (fp->ctf_dynsymidx);
+  ctf_dynhash_destroy (fp->ctf_dynsyms);
+  for (did = ctf_list_next (&fp->ctf_in_flight_dynsyms); did != NULL; did = nid)
+    {
+      nid = ctf_list_next (did);
+      ctf_list_delete (&fp->ctf_in_flight_dynsyms, did);
+      free (did);
+    }
+
   ctf_str_free_atoms (fp);
   free (fp->ctf_tmp_typeslice);
 
@@ -1719,6 +1792,8 @@ ctf_file_close (ctf_file_t *fp)
   ctf_dynhash_destroy (fp->ctf_link_in_cu_mapping);
   ctf_dynhash_destroy (fp->ctf_link_out_cu_mapping);
   ctf_dynhash_destroy (fp->ctf_add_processing);
+  ctf_dedup_fini (fp, NULL, 0);
+  ctf_dynset_destroy (fp->ctf_dedup_atoms_alloc);
 
   for (err = ctf_list_next (&fp->ctf_errs_warnings); err != NULL; err = nerr)
     {
@@ -1736,6 +1811,13 @@ ctf_file_close (ctf_file_t *fp)
   free (fp);
 }
 
+/* Backward compatibility.  */
+void
+ctf_file_close (ctf_file_t *fp)
+{
+  ctf_dict_close (fp);
+}
+
 /* The converse of ctf_open().  ctf_open() disguises whatever it opens as an
    archive, so closing one is just like closing an archive.  */
 void
@@ -1744,36 +1826,70 @@ ctf_close (ctf_archive_t *arc)
   ctf_arc_close (arc);
 }
 
-/* Get the CTF archive from which this ctf_file_t is derived.  */
+/* Get the CTF archive from which this ctf_dict_t is derived.  */
 ctf_archive_t *
-ctf_get_arc (const ctf_file_t *fp)
+ctf_get_arc (const ctf_dict_t *fp)
 {
   return fp->ctf_archive;
 }
 
 /* Return the ctfsect out of the core ctf_impl.  Useful for freeing the
-   ctfsect's data * after ctf_file_close(), which is why we return the actual
+   ctfsect's data * after ctf_dict_close(), which is why we return the actual
    structure, not a pointer to it, since that is likely to become a pointer to
    freed data before the return value is used under the expected use case of
-   ctf_getsect()/ ctf_file_close()/free().  */
+   ctf_getsect()/ ctf_dict_close()/free().  */
 ctf_sect_t
-ctf_getdatasect (const ctf_file_t *fp)
+ctf_getdatasect (const ctf_dict_t *fp)
 {
   return fp->ctf_data;
 }
 
-/* Return the CTF handle for the parent CTF container, if one exists.
-   Otherwise return NULL to indicate this container has no imported parent.  */
-ctf_file_t *
-ctf_parent_file (ctf_file_t *fp)
+ctf_sect_t
+ctf_getsymsect (const ctf_dict_t *fp)
+{
+  return fp->ctf_symtab;
+}
+
+ctf_sect_t
+ctf_getstrsect (const ctf_dict_t *fp)
+{
+  return fp->ctf_strtab;
+}
+
+/* Set the endianness of the symbol table attached to FP.  */
+void
+ctf_symsect_endianness (ctf_dict_t *fp, int little_endian)
+{
+  int old_endianness = fp->ctf_symsect_little_endian;
+
+  fp->ctf_symsect_little_endian = !!little_endian;
+
+  /* If we already have a symtab translation table, we need to repopulate it if
+     our idea of the endianness has changed.  */
+
+  if (old_endianness != fp->ctf_symsect_little_endian
+      && fp->ctf_sxlate != NULL && fp->ctf_symtab.cts_data != NULL)
+    assert (init_symtab (fp, fp->ctf_header, &fp->ctf_symtab) == 0);
+}
+
+/* Return the CTF handle for the parent CTF dict, if one exists.  Otherwise
+   return NULL to indicate this dict has no imported parent.  */
+ctf_dict_t *
+ctf_parent_dict (ctf_dict_t *fp)
 {
   return fp->ctf_parent;
 }
 
-/* Return the name of the parent CTF container, if one exists.  Otherwise
-   return NULL to indicate this container is a root container.  */
+/* Backward compatibility.  */
+ctf_dict_t *
+ctf_parent_file (ctf_dict_t *fp)
+{
+  return ctf_parent_dict (fp);
+}
+
+/* Return the name of the parent CTF dict, if one exists, or NULL otherwise.  */
 const char *
-ctf_parent_name (ctf_file_t *fp)
+ctf_parent_name (ctf_dict_t *fp)
 {
   return fp->ctf_parname;
 }
@@ -1781,7 +1897,7 @@ ctf_parent_name (ctf_file_t *fp)
 /* Set the parent name.  It is an error to call this routine without calling
    ctf_import() at some point.  */
 int
-ctf_parent_name_set (ctf_file_t *fp, const char *name)
+ctf_parent_name_set (ctf_dict_t *fp, const char *name)
 {
   if (fp->ctf_dynparname != NULL)
     free (fp->ctf_dynparname);
@@ -1793,16 +1909,16 @@ ctf_parent_name_set (ctf_file_t *fp, const char *name)
 }
 
 /* Return the name of the compilation unit this CTF file applies to.  Usually
-   non-NULL only for non-parent containers.  */
+   non-NULL only for non-parent dicts.  */
 const char *
-ctf_cuname (ctf_file_t *fp)
+ctf_cuname (ctf_dict_t *fp)
 {
   return fp->ctf_cuname;
 }
 
 /* Set the compilation unit name.  */
 int
-ctf_cuname_set (ctf_file_t *fp, const char *name)
+ctf_cuname_set (ctf_dict_t *fp, const char *name)
 {
   if (fp->ctf_dyncuname != NULL)
     free (fp->ctf_dyncuname);
@@ -1813,11 +1929,11 @@ ctf_cuname_set (ctf_file_t *fp, const char *name)
   return 0;
 }
 
-/* Import the types from the specified parent container by storing a pointer
-   to it in ctf_parent and incrementing its reference count.  Only one parent
-   is allowed: if a parent already exists, it is replaced by the new parent.  */
+/* Import the types from the specified parent dict by storing a pointer to it in
+   ctf_parent and incrementing its reference count.  Only one parent is allowed:
+   if a parent already exists, it is replaced by the new parent.  */
 int
-ctf_import (ctf_file_t *fp, ctf_file_t *pfp)
+ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
     return (ctf_set_errno (fp, EINVAL));
@@ -1826,7 +1942,7 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp)
     return (ctf_set_errno (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
-    ctf_file_close (fp->ctf_parent);
+    ctf_dict_close (fp->ctf_parent);
   fp->ctf_parent = NULL;
 
   if (pfp != NULL)
@@ -1851,7 +1967,7 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp)
    caller must do all freeing itself.  Used internally to avoid refcount
    loops.  */
 int
-ctf_import_unref (ctf_file_t *fp, ctf_file_t *pfp)
+ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
   if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
     return (ctf_set_errno (fp, EINVAL));
@@ -1860,7 +1976,7 @@ ctf_import_unref (ctf_file_t *fp, ctf_file_t *pfp)
     return (ctf_set_errno (fp, ECTF_DMODEL));
 
   if (fp->ctf_parent && !fp->ctf_parent_unreffed)
-    ctf_file_close (fp->ctf_parent);
+    ctf_dict_close (fp->ctf_parent);
   fp->ctf_parent = NULL;
 
   if (pfp != NULL)
@@ -1879,9 +1995,9 @@ ctf_import_unref (ctf_file_t *fp, ctf_file_t *pfp)
   return 0;
 }
 
-/* Set the data model constant for the CTF container.  */
+/* Set the data model constant for the CTF dict.  */
 int
-ctf_setmodel (ctf_file_t *fp, int model)
+ctf_setmodel (ctf_dict_t *fp, int model)
 {
   const ctf_dmodel_t *dp;
 
@@ -1897,24 +2013,24 @@ ctf_setmodel (ctf_file_t *fp, int model)
   return (ctf_set_errno (fp, EINVAL));
 }
 
-/* Return the data model constant for the CTF container.  */
+/* Return the data model constant for the CTF dict.  */
 int
-ctf_getmodel (ctf_file_t *fp)
+ctf_getmodel (ctf_dict_t *fp)
 {
   return fp->ctf_dmodel->ctd_code;
 }
 
-/* The caller can hang an arbitrary pointer off each ctf_file_t using this
+/* The caller can hang an arbitrary pointer off each ctf_dict_t using this
    function.  */
 void
-ctf_setspecific (ctf_file_t *fp, void *data)
+ctf_setspecific (ctf_dict_t *fp, void *data)
 {
   fp->ctf_specific = data;
 }
 
 /* Retrieve the arbitrary pointer again.  */
 void *
-ctf_getspecific (ctf_file_t *fp)
+ctf_getspecific (ctf_dict_t *fp)
 {
   return fp->ctf_specific;
 }