]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: archive: format v2
authorNick Alcock <nick.alcock@oracle.com>
Wed, 28 May 2025 12:42:11 +0000 (13:42 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Wed, 28 May 2025 14:11:37 +0000 (15:11 +0100)
This commit does a bunch of things, all tangled together tightly enough that
disentangling them seemed no to be worth doing.

The biggest is a new archive format, v2, identified by a magic number which
is one higher than the v1 format's magic number.  As usual with libctf we
can only write out the new format, but can still read the old one.

The new format has multiple improvements over the old:

 - It is written native-endian and aggressively endian-swapped at open time,
   just like CTF and BTF dicts; format v1 was little-endian, necessitating
   byteswapping all over the place at read and write time rather than
   localized in one pair of functions at read time.

 - The modent array of name-offset -> archive-offset mappings for the CTF
   archives is explicitly pointed at via a new ctfa_modents header member
   rather than just starting after the end of the header.

 - The length that prepends each archive member actually indicates its
   length rather than always being sizeof (uint64_t) bytes too high (this
   was an outright bug)

 - There is a new shared properties table which in future we may be able to
   use to unify common values from the constituent CTF headers, reducing the
   size overhead of these (repeated, uncompressed) entities.  Right now it
   only contains one value, parent_name, which is the parent dict name if
   one is common across all dicts in the archive (always true for any
   archives derived from ctf_link()).  This is used to let
   ctf_archive_next() et al reliably open dicts in the archive even if they
   are child BTF dicts (which do not contain a header name).

   The properties table shares its property names with the CTF members,
   and uses the same format (and shared code) for the property values as for
   CTF archive members: length-prepended.  The archive members and
   name->value table ("modents") use distinct tables for properties and CTF
   dicts, to ensure they are spatially separated in the file, to maximize
   compressibility if we end up with a lot of properties and people compress
   the whole thing.

We can also restrict various old bug-workaround kludges that only apply to
dicts found in v1 archives: in particular, we needed to dig out the preamble
of some CTF dicts without opening them to figure out whether they used the
.dynstr or .strtab sections: this whole bug workaround is now unnecessary
for v2 and above.

There are other changes for readability and consistency:

 - The archive wrapper data structure, known outside ctf-archive.c as
   ctf_archive_t, is now consistently referred to inside ctf-archive.c as
   'struct ctf_archive_internal' and given the parameter name 'arci' rather
   than sometimes using ctf_archive_t and sometimes using 'wrapper' or 'arc'
   as parameter names.  The archive itself is always called 'struct
   ctf_archive' to emphasise that it is *not* a ctf_archive_t.
   ctf_archive_t remains the public typedef: the fact that it's not actually
   the same thing as the archive file format is an internal implementation
   detail.

 - We keep the archive header around in a new ctfi_hdr member, distinct
   from the actual archive itself, to make upgrading from v1 and cross-
   endianness support easier.  The archive itself is now kept as a char *
   and used only to root pointer arithmetic.

include/ctf.h
libctf/ctf-archive.c
libctf/ctf-impl.h
libctf/ctf-link.c
libctf/ctf-open-bfd.c

index cbbd0ea71af222706e56fbf15eeda6a9c9569e44..a6ab2006fa0106b3fdd54929a731187876f98276 100644 (file)
@@ -829,17 +829,36 @@ typedef struct ctf_enum64
    greater care taken with integral types.  All CTF files in an archive
    must have the same data model.  (This is not validated.)
 
-   All integers in this structure are stored in little-endian byte order.
-
-   The code relies on the fact that everything in this header is a uint64_t
-   and thus the header needs no padding (in particular, that no padding is
-   needed between ctfa_ctfs and the unnamed ctfa_archive_modent array
-   that follows it).
+   All integers in the ctfa_archive_v1 structure are stored in little-endian byte
+   order.
+
+   The generation code relies on the fact that everything in this header is a
+   uint64_t and thus the header needs no padding (in particular, that no padding
+   is needed between ctfa_ctfs and the unnamed ctfa_modent array that follows
+   it.  However, this is only an assumption of the generation code: the
+   read-side code in libctf and the file format do not have any such
+   requirements).
+
+   The shared properties and CTF dict storage have the same (length-prepended)
+   format and identical string/value mapping via struct ctf_archive_modent, but
+   are pointed to by different header fields: ctfa_modents for CTFs,
+   ctfa_propents for properties: their names are intermingled in ctfa_names but
+   the CTF dicts and property values are stashed in distinct tables, ctfa_ctfs
+   and ctfa_prop_values.  Implementations may interpret properties however they
+   wish, and their presence must not be mandatory (though dictionaries may be
+   modified given the presence of a particular property, making use of that
+   property mandatory for reading those dicts: the intent here is to allow
+   optional movement of shared header fields into the shared properties table in
+   the future.  For now, only parent_name=... is present.)
+
+   In format v1, the dict size uint64_t prepended to dictionaries is one
+   uint64_t too long: it contains the length of the size byte too.  In dict v2,
+   this is corrected (at open time, libctf fixes up v1 dicts too).
 
    This is *not* the same as the data structure returned by the ctf_arc_*()
    functions:  this is the low-level on-disk representation.  */
 
-#define CTFA_MAGIC 0x8b47f2a4d7623eeb  /* Random.  */
+#define CTFA_MAGIC 0x8b47f2a4d7623eec  /* V1, below, incremented.  */
 struct ctf_archive
 {
   /* Magic number.  (In loaded files, overwritten with the file size
@@ -852,6 +871,43 @@ struct ctf_archive
   /* Number of CTF dicts in the archive.  */
   uint64_t ctfa_ndicts;
 
+  /* Number of shared properties.  */
+  uint64_t ctfa_nprops;
+
+  /* Offset of the name table, used for both CTF member names and property
+     names.  */
+  uint64_t ctfa_names;
+
+  /* Offset of the CTF table.  Each element starts with a size (a little-
+     endian uint64_t) then a ctf_dict_t of that size.  */
+  uint64_t ctfa_ctfs;
+
+  /* Offset of the shared properties value table: identical format, except the
+     size is followed by an arbitrary (property-dependent) binary blob.  */
+  uint64_t ctfa_prop_values;
+
+  /* Offset of the modent table mapping names to CTFs.  */
+  uint64_t ctfa_modents;
+
+  /* Offset of the modent table mapping names to properties.  Ignored if
+     nprops is 0.  */
+  uint64_t ctfa_propents;
+};
+
+#define CTFA_V1_MAGIC 0x8b47f2a4d7623eeb /* Random.  */
+
+struct ctf_archive_v1
+{
+  /* Magic number.  (In loaded files, overwritten with the file size
+     so ctf_arc_close() knows how much to munmap()).  */
+  uint64_t ctfa_magic;
+
+  /* CTF data model.  */
+  uint64_t ctfa_model;
+
+  /* Number of CTF dicts in the archive.  */
+  uint64_t ctfa_ndicts;
+
   /* Offset of the name table.  */
   uint64_t ctfa_names;
 
@@ -860,9 +916,16 @@ struct ctf_archive
   uint64_t ctfa_ctfs;
 };
 
-/* An array of ctfa_ndicts of this structure lies at
-   ctf_archive[sizeof(struct ctf_archive)] and gives the ctfa_ctfs or
-   ctfa_names-relative offsets of each name or ctf_dict_t.  */
+/* An array of ctfa_ndicts of this structure lies at the offset given by
+   ctfa_modents (or, in v1, at ctf_archive[sizeof(struct ctf_archive)]) and gives
+   the ctfa_ctfs or ctfa_names-relative offsets of each name or ctf_dict_t.
+
+   Another array of ctfa_nprops of this structure lies at the ctfa_propents
+   offset: for this, the ctf_offset is the ctfa_propents-relative offset of
+   proprty values.
+
+   Both property values and CTFs are prepended by a uint64 giving their length.
+   The names are just a strtab (\0-separated).  */
 
 typedef struct ctf_archive_modent
 {
index 31ef4966334c68edb97b24bfc1ed78d0dec228da..ee63419f1e240470818c9a08a7d3555aff53c770 100644 (file)
 #include <sys/mman.h>
 #endif
 
+/* Note on datatypes: the datatype known outside this file as ctf_archive_t
+   is here known as struct ctf_archive_internal, to emphasise its role as a
+   wrapper with no on-disk representation.
+
+   The on-disk structure is struct ctf_archive.  */
+
 static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold);
-static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc,
+static off_t arc_write_one (int fd, const void *item, size_t size, int align);
+static int ctf_arc_value_write (int fd, const void *, size_t, uint64_t *start_off);
+static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive_internal *,
                                            const ctf_sect_t *symsect,
                                            const ctf_sect_t *strsect,
-                                           size_t offset, int little_endian,
-                                           int *errp);
+                                           size_t offset,
+                                           int little_endian_symtab, int *errp);
 static int sort_modent_by_name (const void *one, const void *two, void *n);
+static void ctf_arc_close_internal (struct ctf_archive *arc);
 static void *arc_mmap_header (int fd, size_t headersz);
 static void *arc_mmap_file (int fd, size_t size);
 static int arc_mmap_writeout (int fd, void *header, size_t headersz,
                              const char **errmsg);
 static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
-static int ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp,
-                                 int *errp);
+static int ctf_arc_import_parent (const struct ctf_archive_internal *arci,
+                                 ctf_dict_t *fp, int *errp);
 
 /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts
    and ctfi_symnamedicts.  Never initialized.  */
@@ -128,10 +137,11 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
   ssize_t namesz;
   size_t ctf_startoffs;                /* Start of the section we are working over.  */
   char *nametbl = NULL;                /* The name table.  */
-  char *np;
-  off_t nameoffs;
+  int multiple_parents = 0;
+  const char *known_parent = NULL;
   int err;
-  struct ctf_archive_modent *modent;
+  size_t prop_off = 0;
+  ctf_archive_modent_t *modent;
 
   /* Prepare by serializing everything.  Done first because it allocates a lot
      of space and thus is more likely to fail.  */
@@ -143,9 +153,9 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
               (unsigned long) ctf_dict_cnt);
 
   /* Figure out the size of the mmap()ed header, including the
-     ctf_archive_modent array.  We assume that all of this needs no
-     padding: a likely assumption, given that it's all made up of
-     uint64_t's.  */
+     ctf_archive_modent array immediately following the header itself.  We
+     assume that all of this needs no padding: a likely assumption, given
+     that it's all made up of uint64_t's.  */
   headersz = sizeof (struct ctf_archive)
     + (ctf_dict_cnt * sizeof (uint64_t) * 2);
   ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
@@ -173,10 +183,13 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
     }
 
   /* Fill in everything we can, which is everything other than the name
-     table offset.  */
-  archdr->ctfa_magic = htole64 (CTFA_MAGIC);
-  archdr->ctfa_ndicts = htole64 (ctf_dict_cnt);
-  archdr->ctfa_ctfs = htole64 (ctf_startoffs);
+     table and shared properties table offsets.  */
+  archdr->ctfa_magic = CTFA_MAGIC;
+  archdr->ctfa_ndicts = ctf_dict_cnt;
+  archdr->ctfa_ctfs = ctf_startoffs;
+  archdr->ctfa_nprops = 0;                     /* Updated later.  */
+  archdr->ctfa_propents = 0;                   /* Updated later.  */
+  archdr->ctfa_modents = sizeof (struct ctf_archive);
 
   /* We could validate that all CTF files have the same data model, but
      since any reasonable construction process will be building things of
@@ -187,16 +200,20 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
      memory.)  */
 
   if (ctf_dict_cnt > 0)
-    archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0]));
+    archdr->ctfa_model = ctf_getmodel (ctf_dicts[0]);
 
   /* Now write out the CTFs: ctf_archive_modent array via the mapping,
      ctfs via write().  The names themselves have not been written yet: we
      track them in a local strtab until the time is right, and sort the
      modents array after construction.
 
-    The name table is not sorted.  */
+     We also keep track of the parent of each dict, so we can easily tell if
+     all dicts have a consistent parent (or none).  (This is usually the
+     case, e.g. for all archives resulting from a ctf_link() operation.)
+
+     The name table is not sorted.  */
 
-  for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++)
+  for (i = 0, namesz = 0; i < archdr->ctfa_ndicts; i++)
     namesz += strlen (names[i]) + 1;
 
   nametbl = malloc (namesz);
@@ -209,60 +226,100 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
   for (i = 0, namesz = 0,
        modent = (ctf_archive_modent_t *) ((char *) archdr
                                          + sizeof (struct ctf_archive));
-       i < le64toh (archdr->ctfa_ndicts); i++)
+       i < archdr->ctfa_ndicts; i++)
     {
       off_t off;
 
       strcpy (&nametbl[namesz], names[i]);
 
       off = arc_write_one_ctf (ctf_dicts[i], fd, threshold);
-      if ((off < 0) && (off > -ECTF_BASE))
-       {
-         errmsg = N_("ctf_arc_write(): cannot determine file "
-                     "position while writing to archive");
-         goto err_free;
-       }
-      if (off < 0)
+      if (off == -1)
        {
          errmsg = N_("ctf_arc_write(): cannot write CTF file to archive");
-         errno = off * -1;
          goto err_free;
        }
 
-      modent->name_offset = htole64 (namesz);
-      modent->ctf_offset = htole64 (off - ctf_startoffs);
+      modent->name_offset = namesz;
+      modent->ctf_offset = off - ctf_startoffs;
       namesz += strlen (names[i]) + 1;
       modent++;
+
+      if (!multiple_parents)
+       {
+         if (!known_parent)
+           known_parent = ctf_dicts[i]->ctf_parent_name;
+         else
+           if (ctf_dicts[i]->ctf_parent_name
+               && strcmp (known_parent, ctf_dicts[i]->ctf_parent_name) != 0)
+             multiple_parents = 1;
+       }
     }
 
   ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
                                         + sizeof (struct ctf_archive)),
-              le64toh (archdr->ctfa_ndicts),
-              sizeof (struct ctf_archive_modent), sort_modent_by_name,
+              archdr->ctfa_ndicts,
+              sizeof (ctf_archive_modent_t), sort_modent_by_name,
               nametbl);
 
+  /* Properties.  We have only one property so far, defined only if we have
+     exactly one parent in common across all dicts.  */
+  if (!multiple_parents && known_parent)
+    {
+      char *new_nametbl;
+
+      archdr->ctfa_nprops++;
+      if ((new_nametbl = realloc (nametbl, namesz
+                                 + strlen ("parent_name") + 1)) == NULL)
+       {
+         errmsg = N_("ctf_arc_write(): error allocating properties");
+         goto err_free;
+       }
+      nametbl = new_nametbl;
+      strcpy (&nametbl[namesz], "parent_name");
+      prop_off = namesz;
+      namesz += strlen ("parent_name") + 1;
+    }
+
    /* Now the name table.  */
 
-  if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
+  if (ctf_arc_value_write (fd, nametbl, namesz, &archdr->ctfa_names) < 0)
     {
-      errmsg = N_("ctf_arc_write(): cannot get current file position "
-                 "in archive");
+      errmsg = N_("ctf_arc_write(): cannot write name table to archive");
       goto err_free;
     }
-  archdr->ctfa_names = htole64 (nameoffs);
-  np = nametbl;
-  while (namesz > 0)
+  free (nametbl);
+
+  /* Now the properties.  There is only one currently: the parent name,
+     which means the sorted nature of the name table is trivial.  (When
+     multiple properties are written out, only the last will be
+     aligned.)  */
+
+  if (!multiple_parents && known_parent)
     {
-      ssize_t len;
-      if ((len = write (fd, np, namesz)) < 0)
+      ctf_archive_modent_t props;
+      off_t prop_values;
+      uint64_t propents;
+
+      memset (&props, 0, sizeof (ctf_archive_modent_t));
+
+      props.name_offset = prop_off;
+      props.ctf_offset = 0;
+
+      if ((prop_values = arc_write_one (fd, known_parent,
+                                       strlen (known_parent) + 1, 1)) < 0
+         || (ctf_arc_value_write (fd, &props, sizeof (ctf_archive_modent_t),
+                                  &propents) < 0))
        {
-         errmsg = N_("ctf_arc_write(): cannot write name table to archive");
-         goto err_free;
+         /* Something went wrong: just blank out the props and keep going.  */
+         archdr->ctfa_prop_values = 0;
+         archdr->ctfa_propents = 0;
+       }
+      else
+       {
+         archdr->ctfa_prop_values = prop_values;
+         archdr->ctfa_propents = propents;
        }
-      namesz -= len;
-      np += len;
     }
-  free (nametbl);
 
   if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
     goto err_unmap;
@@ -323,71 +380,116 @@ ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
 
 /* Write one CTF dict out.  Return the file position of the written file (or
    rather, of the file-size uint64_t that precedes it): negative return is a
-   negative errno or ctf_errno value.  On error, the file position may no longer
-   be at the end of the file.  */
+   negative errno or ctf_errno value.  On error, the file position may no
+   longer be at the end of the file, but if it is, it will be at an 8-byte
+   aligned offset.  Sets errno on error.  */
 static off_t
-arc_write_one_ctf (ctf_dict_t *f, int fd, size_t threshold)
+arc_write_one_ctf (ctf_dict_t *fp, int fd, size_t threshold)
 {
-  off_t off, end_off;
-  uint64_t ctfsz = 0;
-  char *ctfszp;
-  size_t ctfsz_len;
+  uint64_t off, ctfsz = 0;
+  off_t end_off;
 
-  if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
-    return errno * -1;
+  /* This zero write turns into the size in a moment...  */
+  if (ctf_arc_value_write (fd, &ctfsz, sizeof (ctfsz), &off) < 0)
+    return -1;
 
-  /* This zero-write turns into the size in a moment. */
-  ctfsz_len = sizeof (ctfsz);
-  ctfszp = (char *) &ctfsz;
-  while (ctfsz_len > 0)
+  if (ctf_write_thresholded (fp, fd, threshold) != 0)
     {
-      ssize_t writelen = write (fd, ctfszp, ctfsz_len);
-      if (writelen < 0)
-       return errno * -1;
-      ctfsz_len -= writelen;
-      ctfszp += writelen;
+      errno = fp->ctf_errno;
+      return -1;
     }
 
-  if (ctf_write_thresholded (f, fd, threshold) != 0)
-    return f->ctf_errno * -1;
-
   if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
-    return errno * -1;
-  ctfsz = htole64 (end_off - off);
+    return -1;
+  ctfsz = end_off - (off + sizeof (ctfsz));
 
   if ((lseek (fd, off, SEEK_SET)) < 0)
-    return errno * -1;
+    return -1;
 
   /* ... here.  */
-  ctfsz_len = sizeof (ctfsz);
-  ctfszp = (char *) &ctfsz;
-  while (ctfsz_len > 0)
-    {
-      ssize_t writelen = write (fd, ctfszp, ctfsz_len);
-      if (writelen < 0)
-       return errno * -1;
-      ctfsz_len -= writelen;
-      ctfszp += writelen;
-    }
+  if (ctf_arc_value_write (fd, &ctfsz, sizeof (ctfsz), &off) < 0)
+    return -1;
+
+  /* Align the end byte and move there.  */
 
   end_off = LCTF_ALIGN_OFFS (end_off, 8);
   if ((lseek (fd, end_off, SEEK_SET)) < 0)
-    return errno * -1;
+    return -1;
 
-  return off;
+  return (off_t) off;
 }
 
-/* qsort() function to sort the array of struct ctf_archive_modents into
+/* Write one size-prepended thing out.  On error, the file position may no
+   longer be at the end of the file.  Sets errno on error.  */
+
+static off_t
+arc_write_one (int fd, const void *item, size_t size, int align)
+{
+  uint64_t sz64 = (uint64_t) size;
+  uint64_t off;
+
+  if (ctf_arc_value_write (fd, &sz64, sizeof (sz64), &off) < 0)
+    return -1;
+
+  if (ctf_arc_value_write (fd, item, size, NULL) < 0)
+    return -1;
+
+  if (align)
+    {
+      off_t end_off;
+
+      if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
+       return -1;
+
+      end_off = LCTF_ALIGN_OFFS (end_off, 8);
+      if ((lseek (fd, end_off, SEEK_SET)) < 0)
+       return -1;
+    }
+
+  return (off_t) off;
+}
+
+/* Write out one value in the archive.  Sets errno and returns -1 on
+   error.  */
+
+static int
+ctf_arc_value_write (int fd, const void *tbl_, size_t tblsz,
+                    uint64_t *start_off)
+{
+  off_t off;
+  const unsigned char *tbl = (const unsigned char *) tbl_;
+
+  if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
+    return -1;
+
+  if (start_off)
+    *start_off = off;
+
+  while (tblsz > 0)
+    {
+      ssize_t len;
+
+      if ((len = write (fd, tbl, tblsz)) < 0)
+       {
+         *start_off = 0;
+         return -1;
+       }
+      tblsz -= len;
+      tbl += len;
+    }
+  return 0;
+}
+
+/* qsort() function to sort the array of ctf_archive_modents_t into
    ascending name order.  */
 static int
 sort_modent_by_name (const void *one, const void *two, void *n)
 {
-  const struct ctf_archive_modent *a = one;
-  const struct ctf_archive_modent *b = two;
+  const ctf_archive_modent_t *a = one;
+  const ctf_archive_modent_t *b = two;
   char *nametbl = n;
 
-  return strcmp (&nametbl[le64toh (a->name_offset)],
-                &nametbl[le64toh (b->name_offset)]);
+  return strcmp (&nametbl[a->name_offset], &nametbl[b->name_offset]);
 }
 
 /* bsearch_r() function to search for a given name in the sorted array of struct
@@ -396,39 +498,72 @@ static int
 search_modent_by_name (const void *key, const void *ent, void *arg)
 {
   const char *k = key;
-  const struct ctf_archive_modent *v = ent;
-  const char *search_nametbl = arg;
+  const ctf_archive_modent_t *v = ent;
+  const struct ctf_archive_internal *arci;
+  const char *search_nametbl;
+
+  arci = (const struct ctf_archive_internal *) arg;
 
-  return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
+  search_nametbl = (char *) arci->ctfi_archive + arci->ctfi_hdr->ctfa_names;
+  return strcmp (k, &search_nametbl[v->name_offset]);
 }
 
 /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
-   ctf_dict.  Closes ARC and/or FP on error.  Arrange to free the SYMSECT or
-   STRSECT, as needed, on close.  Possibly do not unmap on close.  */
+   ctf_dict: endian-swap the archive header as necessary, and check all its
+   offsets for validity.  Close ARC and/or FP on error.  Arrange to free or
+   unmap the SYMSECT or STRSECT, as needed, on close.  */
 
 struct ctf_archive_internal *
-ctf_new_archive_internal (int is_archive, int unmap_on_close,
-                         struct ctf_archive *arc,
+ctf_new_archive_internal (int is_archive, int is_v1, int unmap_on_close,
+                         struct ctf_archive *arc, size_t arc_len,
                          ctf_dict_t *fp, const ctf_sect_t *symsect,
                          const ctf_sect_t *strsect,
                          int *errp)
 {
-  struct ctf_archive_internal *arci;
+  struct ctf_archive_internal *arci = NULL;
 
   if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
+    goto err;
+
+  ctf_set_open_errno (errp, 0);
+
+  arci->ctfi_is_archive = is_archive;
+  arci->ctfi_archive_v1 = is_v1;
+
+  if (is_archive)
     {
-      if (is_archive)
+      arci->ctfi_archive = (unsigned char *) arc;
+      if (is_v1)
+       arci->ctfi_hdr_len = sizeof (struct ctf_archive_v1);
+      else
+       arci->ctfi_hdr_len = sizeof (struct ctf_archive);
+
+      if ((arci->ctfi_hdr = malloc (sizeof (struct ctf_archive))) == NULL)
+       goto err;
+
+      /* Upgrade the v1 header if needed.  */
+
+      if (!is_v1)
+       memcpy (arci->ctfi_hdr, arc, sizeof (struct ctf_archive));
+      else
        {
-         if (unmap_on_close)
-           ctf_arc_close_internal (arc);
+         struct ctf_archive_v1 *v1hdr = (struct ctf_archive_v1 *) arc;
+
+         memset (arci->ctfi_hdr, 0, sizeof (struct ctf_archive));
+         arci->ctfi_hdr->ctfa_magic = v1hdr->ctfa_magic;
+         arci->ctfi_hdr->ctfa_model = v1hdr->ctfa_model;
+         arci->ctfi_hdr->ctfa_ndicts = v1hdr->ctfa_ndicts;
+         arci->ctfi_hdr->ctfa_names = v1hdr->ctfa_names;
+         arci->ctfi_hdr->ctfa_ctfs = v1hdr->ctfa_ctfs;
+         arci->ctfi_hdr->ctfa_modents = sizeof (struct ctf_archive_v1);
        }
-      else
-       ctf_dict_close (fp);
-      return (ctf_set_open_errno (errp, errno));
+
+      if (ctf_arc_flip_archive (arci, arc_len, errp) < 0)
+       goto err_set;
+
+      if (ctf_arc_range_check (arci, arc_len, errp) < 0)
+       goto err_set;
     }
-  arci->ctfi_is_archive = is_archive;
-  if (is_archive)
-    arci->ctfi_archive = arc;
   else
     arci->ctfi_dict = fp;
   if (symsect)
@@ -441,36 +576,59 @@ ctf_new_archive_internal (int is_archive, int unmap_on_close,
   arci->ctfi_symsect_little_endian = -1;
 
   return arci;
+
+ err:
+  ctf_set_open_errno (errp, errno);
+ err_set:
+  if (is_archive)
+    {
+      if (unmap_on_close)
+       ctf_arc_close_internal (arc);
+    }
+  else
+    ctf_dict_close (fp);
+  if (arci)
+    {
+      free (arci->ctfi_hdr);
+      free (arci);
+    }
+  return NULL;
 }
 
 /* Set the symbol-table endianness of an archive (defaulting the symtab
    endianness of all ctf_file_t's opened from that archive).  */
 void
-ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian)
+ctf_arc_symsect_endianness (struct ctf_archive_internal *arci, int little_endian)
 {
-  arc->ctfi_symsect_little_endian = !!little_endian;
-  if (!arc->ctfi_is_archive)
-    ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian);
+  arci->ctfi_symsect_little_endian = !!little_endian;
+  if (!arci->ctfi_is_archive)
+    ctf_symsect_endianness (arci->ctfi_dict, arci->ctfi_symsect_little_endian);
 }
 
 /* Get the CTF preamble from data in a buffer, which may be either an archive or
    a CTF dict.  If multiple dicts are present in an archive, the preamble comes
    from an arbitrary dict.  The preamble is a pointer into the ctfsect passed
-   in.  */
+   in.  Returns NULL if called on non-v1 archives.  (Backward-compatibility
+   only.)  */
 
 const ctf_preamble_t *
-ctf_arc_bufpreamble (const ctf_sect_t *ctfsect)
+ctf_arc_bufpreamble_v1 (const ctf_sect_t *ctfsect)
 {
-  if (ctfsect->cts_data != NULL
-      && ctfsect->cts_size > sizeof (uint64_t)
-      && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
+  if (ctfsect->cts_data == NULL
+      || ctfsect->cts_size <= sizeof (uint64_t))
+    {
+      errno = EOVERFLOW;
+      return NULL;
+    }
+
+  if (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_V1_MAGIC)
     {
-      struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
+      struct ctf_archive_v1 *arc = (struct ctf_archive_v1 *) ctfsect->cts_data;
       return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
                                       + sizeof (uint64_t));
     }
-  else
-    return (const ctf_preamble_t *) ctfsect->cts_data;
+
+  return NULL;
 }
 
 /* Open a CTF archive or dictionary from data in a buffer (which the caller must
@@ -481,23 +639,30 @@ ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
                 const ctf_sect_t *strsect, int *errp)
 {
   struct ctf_archive *arc = NULL;
-  int is_archive;
+  int is_archive, is_v1 = 0;
   ctf_dict_t *fp = NULL;
 
   if (ctfsect->cts_data != NULL
       && ctfsect->cts_size > sizeof (uint64_t)
-      && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
+      && (*(uint64_t *) ctfsect->cts_data == CTFA_MAGIC
+         || bswap_64 ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC
+         || le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_V1_MAGIC))
     {
       /* The archive is mmappable, so this operation is trivial.
 
-        This buffer is nonmodifiable, so the trick involving mmapping only part
-        of it and storing the length in the magic number is not applicable: so
-        record this fact in the archive-wrapper header.  (We cannot record it
-        in the archive, because the archive may very well be a read-only
-        mapping.)  */
+        This buffer is nonmodifiable, so the trick involving mmapping only
+        part of it and storing the length in the magic number is not
+        applicable: so record this fact in the archive-wrapper header.  (We
+        cannot record it in the archive, because the archive may very well
+        be a read-only mapping.  unmap_on_close is left unset in the
+        ctf_new_archive_internal call so that we don't try to unmap it
+        ourselves.)  */
 
       is_archive = 1;
       arc = (struct ctf_archive *) ctfsect->cts_data;
+
+      if (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_V1_MAGIC)
+       is_v1 = 1;
     }
   else
     {
@@ -508,17 +673,18 @@ ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
          return NULL;
        }
     }
-  return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect,
-                                  errp);
+  return ctf_new_archive_internal (is_archive, is_v1, 0, arc, ctfsect->cts_size,
+                                  fp, symsect, strsect, errp);
 }
 
-/* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
-   not NULL).  */
-struct ctf_archive *
+/* Open a CTF archive from a given file.  Returns the archive (wrapper), or
+   NULL and an error in *err (if not NULL).  Only archives are supported,
+   not dicts (because our only caller already handles those itself).  */
+struct ctf_archive_internal *
 ctf_arc_open_internal (const char *filename, int *errp)
 {
   const char *errmsg;
-  int fd;
+  int fd, is_v1 = 0;
   struct stat s;
   struct ctf_archive *arc;             /* (Actually the whole file.)  */
 
@@ -534,29 +700,34 @@ ctf_arc_open_internal (const char *filename, int *errp)
       goto err_close;
     }
 
+  /* This will fail if the file is too big -- e.g. > 4GiB on 32-bit
+     platforms -- and thus free us from having to do integer-overflow checks
+     elsewhere.  */
   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
     {
       errmsg = N_("ctf_arc_open(): cannot read in %s");
       goto err_close;
     }
 
-  if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
+  if (arc->ctfa_magic != CTFA_MAGIC && bswap_64 (arc->ctfa_magic) != CTFA_MAGIC
+      && le64toh (arc->ctfa_magic) != CTFA_V1_MAGIC)
     {
       errmsg = N_("ctf_arc_open(): %s: invalid magic number");
       errno = ECTF_FMT;
       goto err_unmap;
     }
 
+  if (le64toh (arc->ctfa_magic) == CTFA_V1_MAGIC)
+    is_v1 = 1;
+
   /* This horrible hack lets us know how much to unmap when the file is
      closed.  (We no longer need the magic number, and the mapping
      is private.)  */
   arc->ctfa_magic = s.st_size;
   close (fd);
 
-  if (errp)
-    *errp = 0;
-
-  return arc;
+  return ctf_new_archive_internal (1, is_v1, 1, arc, s.st_size, NULL,
+                                  NULL, NULL, errp);
 
 err_unmap:
   arc_mmap_unmap (arc, s.st_size, NULL);
@@ -570,7 +741,7 @@ err:
 }
 
 /* Close an archive.  */
-void
+static void
 ctf_arc_close_internal (struct ctf_archive *arc)
 {
   if (arc == NULL)
@@ -580,57 +751,56 @@ ctf_arc_close_internal (struct ctf_archive *arc)
   arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
 }
 
-/* Public entry point: close an archive, or CTF file.  */
+/* Public entry point: close an archive (via its wrapper), or CTF dict.  */
 void
-ctf_arc_close (ctf_archive_t *arc)
+ctf_arc_close (struct ctf_archive_internal *arci)
 {
-  if (arc == NULL)
+  if (arci == NULL)
     return;
 
-  if (arc->ctfi_is_archive)
+  if (arci->ctfi_is_archive)
     {
-      if (arc->ctfi_unmap_on_close)
-       ctf_arc_close_internal (arc->ctfi_archive);
+      if (arci->ctfi_unmap_on_close)
+       ctf_arc_close_internal ((struct ctf_archive *) arci->ctfi_archive);
     }
   else
-    ctf_dict_close (arc->ctfi_dict);
-  free (arc->ctfi_symdicts);
-  free (arc->ctfi_symnamedicts);
-  ctf_dynhash_destroy (arc->ctfi_dicts);
-  if (arc->ctfi_free_symsect)
-    free ((void *) arc->ctfi_symsect.cts_data);
-  if (arc->ctfi_free_strsect)
-    free ((void *) arc->ctfi_strsect.cts_data);
-  free (arc->ctfi_data);
-  if (arc->ctfi_bfd_close)
-    arc->ctfi_bfd_close (arc);
-  free (arc);
+    ctf_dict_close (arci->ctfi_dict);
+  free (arci->ctfi_hdr);
+  free (arci->ctfi_symdicts);
+  free (arci->ctfi_symnamedicts);
+  ctf_dynhash_destroy (arci->ctfi_dicts);
+  if (arci->ctfi_free_symsect)
+    free ((void *) arci->ctfi_symsect.cts_data);
+  if (arci->ctfi_free_strsect)
+    free ((void *) arci->ctfi_strsect.cts_data);
+  free (arci->ctfi_data);
+  if (arci->ctfi_bfd_close)
+    arci->ctfi_bfd_close (arci);
+  free (arci);
 }
 
 /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
    non-NULL.  A name of NULL means to open the default file.  */
 static ctf_dict_t *
-ctf_dict_open_internal (const struct ctf_archive *arc,
+ctf_dict_open_internal (const struct ctf_archive_internal *arci,
                        const ctf_sect_t *symsect,
                        const ctf_sect_t *strsect,
-                       const char *name, int little_endian,
+                       const char *name, int little_endian_symtab,
                        int *errp)
 {
-  struct ctf_archive_modent *modent;
-  const char *search_nametbl;
+  ctf_archive_modent_t *modent;
 
   if (name == NULL)
     name = _CTF_SECTION;                /* The default name.  */
 
   ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name);
 
-  modent = (ctf_archive_modent_t *) ((char *) arc
-                                    + sizeof (struct ctf_archive));
+  modent = (ctf_archive_modent_t *) (arci->ctfi_archive
+                                    + arci->ctfi_hdr->ctfa_modents);
 
-  search_nametbl = (const char *) arc + le64toh (arc->ctfa_names);
-  modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts),
-                     sizeof (struct ctf_archive_modent),
-                     search_modent_by_name, (void *) search_nametbl);
+  modent = bsearch_r (name, modent, arci->ctfi_hdr->ctfa_ndicts,
+                     sizeof (ctf_archive_modent_t),
+                     search_modent_by_name, (void *) arci);
 
   /* This is actually a common case and normal operation: no error
      debug output.  */
@@ -641,9 +811,8 @@ ctf_dict_open_internal (const struct ctf_archive *arc,
       return NULL;
     }
 
-  return ctf_dict_open_by_offset (arc, symsect, strsect,
-                                 le64toh (modent->ctf_offset),
-                                 little_endian, errp);
+  return ctf_dict_open_by_offset (arci, symsect, strsect, modent->ctf_offset,
+                                 little_endian_symtab, errp);
 }
 
 /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
@@ -653,7 +822,7 @@ ctf_dict_open_internal (const struct ctf_archive *arc,
 
    Public entry point.  */
 ctf_dict_t *
-ctf_dict_open_sections (const ctf_archive_t *arc,
+ctf_dict_open_sections (const struct ctf_archive_internal *arci,
                        const ctf_sect_t *symsect,
                        const ctf_sect_t *strsect,
                        const char *name,
@@ -662,22 +831,22 @@ ctf_dict_open_sections (const ctf_archive_t *arc,
   if (errp)
     *errp = 0;
 
-  if (arc->ctfi_is_archive)
+  if (arci->ctfi_is_archive)
     {
-      ctf_dict_t *ret;
-      ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect,
-                                   name, arc->ctfi_symsect_little_endian,
-                                   errp);
-      if (ret)
+      ctf_dict_t *fp;
+      fp = ctf_dict_open_internal (arci, symsect, strsect, name,
+                                  arci->ctfi_symsect_little_endian,
+                                  errp);
+      if (fp)
        {
-         ret->ctf_archive = (ctf_archive_t *) arc;
-         if (ctf_arc_import_parent (arc, ret, errp) < 0)
+         fp->ctf_archive = (struct ctf_archive_internal *) arci;
+         if (ctf_arc_import_parent (arci, fp, errp) < 0)
            {
-             ctf_dict_close (ret);
+             ctf_dict_close (fp);
              return NULL;
            }
        }
-      return ret;
+      return fp;
     }
 
   if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
@@ -686,11 +855,11 @@ ctf_dict_open_sections (const ctf_archive_t *arc,
        *errp = ECTF_ARNNAME;
       return NULL;
     }
-  arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc;
+  arci->ctfi_dict->ctf_archive = (struct ctf_archive_internal *) arci;
 
   /* Bump the refcount so that the user can ctf_dict_close() it.  */
-  arc->ctfi_dict->ctf_refcnt++;
-  return arc->ctfi_dict;
+  arci->ctfi_dict->ctf_refcnt++;
+  return arci->ctfi_dict;
 }
 
 /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
@@ -698,17 +867,17 @@ ctf_dict_open_sections (const ctf_archive_t *arc,
 
    Public entry point.  */
 ctf_dict_t *
-ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp)
+ctf_dict_open (const struct ctf_archive_internal *arci, const char *name, int *errp)
 {
-  const ctf_sect_t *symsect = &arc->ctfi_symsect;
-  const ctf_sect_t *strsect = &arc->ctfi_strsect;
+  const ctf_sect_t *symsect = &arci->ctfi_symsect;
+  const ctf_sect_t *strsect = &arci->ctfi_strsect;
 
   if (symsect->cts_name == NULL)
     symsect = NULL;
   if (strsect->cts_name == NULL)
     strsect = NULL;
 
-  return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
+  return ctf_dict_open_sections (arci, symsect, strsect, name, errp);
 }
 
 static void
@@ -721,45 +890,45 @@ ctf_cached_dict_close (void *fp)
    ctfi_dicts.  If this is the first cached dict, designate it the
    crossdict_cache.  */
 static ctf_dict_t *
-ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
+ctf_dict_open_cached (struct ctf_archive_internal *arci, const char *name, int *errp)
 {
   ctf_dict_t *fp;
   char *dupname = NULL;
 
   /* Just return from the cache if possible.  */
-  if (arc->ctfi_dicts
-      && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL))
+  if (arci->ctfi_dicts
+      && ((fp = ctf_dynhash_lookup (arci->ctfi_dicts, name)) != NULL))
     {
       fp->ctf_refcnt++;
       return fp;
     }
 
   /* Not yet cached: open it.  */
-  if ((fp = ctf_dict_open (arc, name, errp)) == NULL)
+  if ((fp = ctf_dict_open (arci, name, errp)) == NULL)
     goto err;
 
   if ((dupname = strdup (name)) == NULL)
     goto oom;
 
-  if (arc->ctfi_dicts == NULL)
-    if ((arc->ctfi_dicts
+  if (arci->ctfi_dicts == NULL)
+    if ((arci->ctfi_dicts
         = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
                               free, ctf_cached_dict_close)) == NULL)
       goto oom;
 
-  if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0)
+  if (ctf_dynhash_insert (arci->ctfi_dicts, dupname, fp) < 0)
     goto oom;
   fp->ctf_refcnt++;
 
-  if (arc->ctfi_crossdict_cache == NULL)
-    arc->ctfi_crossdict_cache = fp;
+  if (arci->ctfi_crossdict_cache == NULL)
+    arci->ctfi_crossdict_cache = fp;
 
   /* If this archive has multiple members, and this is a parent, pretend
      that we have opened at least one child.  This forces type and string
      allocations in the parent to use provisional IDs, permitting you to
      import children into it even if you modify the parent before you import
      any.  */
-  if (arc->ctfi_is_archive && arc->ctfi_archive->ctfa_ndicts > 1
+  if (arci->ctfi_is_archive && arci->ctfi_hdr->ctfa_ndicts > 1
       && !(fp->ctf_flags & LCTF_CHILD))
     {
       ctf_dprintf ("archived parent: max children bumped.\n");
@@ -779,24 +948,25 @@ ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
 
 /* Flush any caches the CTF archive may have open.  */
 void
-ctf_arc_flush_caches (ctf_archive_t *wrapper)
+ctf_arc_flush_caches (struct ctf_archive_internal *arci)
 {
-  free (wrapper->ctfi_symdicts);
-  ctf_dynhash_destroy (wrapper->ctfi_symnamedicts);
-  ctf_dynhash_destroy (wrapper->ctfi_dicts);
-  wrapper->ctfi_symdicts = NULL;
-  wrapper->ctfi_symnamedicts = NULL;
-  wrapper->ctfi_dicts = NULL;
-  wrapper->ctfi_crossdict_cache = NULL;
+  free (arci->ctfi_symdicts);
+  ctf_dynhash_destroy (arci->ctfi_symnamedicts);
+  ctf_dynhash_destroy (arci->ctfi_dicts);
+  arci->ctfi_symdicts = NULL;
+  arci->ctfi_symnamedicts = NULL;
+  arci->ctfi_dicts = NULL;
+  arci->ctfi_crossdict_cache = NULL;
 }
 
 /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if
    none, setting 'err' if non-NULL.  */
 static ctf_dict_t *
-ctf_dict_open_by_offset (const struct ctf_archive *arc,
+ctf_dict_open_by_offset (const struct ctf_archive_internal *arci,
                         const ctf_sect_t *symsect,
                         const ctf_sect_t *strsect, size_t offset,
-                        int little_endian, int *errp)
+                        int little_endian_symtab,
+                        int *errp)
 {
   ctf_sect_t ctfsect;
   ctf_dict_t *fp;
@@ -805,38 +975,81 @@ ctf_dict_open_by_offset (const struct ctf_archive *arc,
 
   memset (&ctfsect, 0, sizeof (ctf_sect_t));
 
-  offset += le64toh (arc->ctfa_ctfs);
+  offset += arci->ctfi_hdr->ctfa_ctfs;
 
   ctfsect.cts_name = _CTF_SECTION;
-  ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
+  ctfsect.cts_size = *((uint64_t *) (arci->ctfi_archive + offset));
   ctfsect.cts_entsize = 1;
-  ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
+  ctfsect.cts_data = (void *) (arci->ctfi_archive + offset + sizeof (uint64_t));
+
   fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
   if (fp)
     {
-      ctf_setmodel (fp, le64toh (arc->ctfa_model));
-      if (little_endian >= 0)
-       ctf_symsect_endianness (fp, little_endian);
+      ctf_setmodel (fp, arci->ctfi_hdr->ctfa_model);
+      if (little_endian_symtab >= 0)
+       ctf_symsect_endianness (fp, little_endian_symtab);
     }
   return fp;
 }
 
 /* Backward compatibility.  */
 ctf_dict_t *
-ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name,
+ctf_arc_open_by_name (const ctf_archive_t *arci, const char *name,
                      int *errp)
 {
-  return ctf_dict_open (arc, name, errp);
+  return ctf_dict_open (arci, name, errp);
 }
 
 ctf_dict_t *
-ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
+ctf_arc_open_by_name_sections (const struct ctf_archive_internal *arci,
                               const ctf_sect_t *symsect,
                               const ctf_sect_t *strsect,
                               const char *name,
                               int *errp)
 {
-  return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
+  return ctf_dict_open_sections (arci, symsect, strsect, name, errp);
+}
+
+/* Get a property value from the shared properties table of an archive,
+   given a name, or NULL.  */
+
+static const char *
+ctf_arc_get_property (const struct ctf_archive_internal *arci, const char *prop)
+{
+  ctf_archive_modent_t *modent;
+  uint64_t *size;
+
+  if (!arci->ctfi_archive)
+    return NULL;
+
+  if (arci->ctfi_hdr->ctfa_propents == 0
+      || arci->ctfi_hdr->ctfa_prop_values == 0)
+    return NULL;
+
+  modent = (ctf_archive_modent_t *) (arci->ctfi_archive
+                                    + arci->ctfi_hdr->ctfa_modents);
+
+  modent = bsearch_r (prop, modent, arci->ctfi_hdr->ctfa_nprops,
+                     sizeof (ctf_archive_modent_t),
+                     search_modent_by_name, (void *) arci);
+
+  if (modent == NULL)
+    return NULL;
+
+  /* Currently, all property values we use are strings: we can exploit this
+     and skip the size, with one special case for no value at all meaning
+     the null string.  */
+
+  size = (uint64_t *) (arci->ctfi_archive
+                      + arci->ctfi_hdr->ctfa_propents
+                      + modent->ctf_offset);
+  if (*size == 0)
+    return "";
+
+  return (char *) (arci->ctfi_archive
+                  + arci->ctfi_hdr->ctfa_propents
+                  + modent->ctf_offset
+                  + sizeof (uint64_t));
 }
 
 /* Import the parent into a ctf archive, if this is a child, the parent is not
@@ -844,7 +1057,8 @@ ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
    this is not possible: this is just a best-effort helper operation to give
    people useful dicts to start with.  */
 static int
-ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp)
+ctf_arc_import_parent (const struct ctf_archive_internal *arci, ctf_dict_t *fp,
+                      int *errp)
 {
   if ((fp->ctf_flags & LCTF_CHILD) && !fp->ctf_parent)
     {
@@ -852,25 +1066,26 @@ ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp)
       ctf_dict_t *parent;
       const char *parent_name = fp->ctf_parent_name;
 
-      /* If no parent is set, and this is an archive, assume that the parent
-        is the first dict in the archive, which matches what ctf_link
-        produces.  UPTODO: add a dedicated header entry for parent
-        name.  */
-
-      if (!parent_name && arc->ctfi_archive)
-       {
-         struct ctf_archive_modent *modent;
-         const char *nametbl;
-
-         modent = (ctf_archive_modent_t *) ((char *) arc->ctfi_archive
-                                            + sizeof (struct ctf_archive));
-
-         nametbl = (((const char *) arc->ctfi_archive)
-                    + le64toh (arc->ctfi_archive->ctfa_names));
-         parent_name = &nametbl[le64toh (modent[0].name_offset)];
-       }
-
-      parent = ctf_dict_open_cached ((ctf_archive_t *) arc, parent_name, &err);
+      /* If no parent is set, and this is an archive, check the parent name
+        in the properties table.  (v1 archives will not have one, but v1
+        archives will only ever contain CTF dicts, which will always have
+        a parent name set if they need one.  This contingency is for BTF,
+        which can only appear in v2 archives.)
+
+        There may not be a parent name set even in this case: in the
+        (admittedly pathological) case of archives which contain a mix of
+        parents and some BTF children, the parent name will not be set
+        because no consistent name exists.  In this case,
+        ctf_archive_next's callers will simply have to import the parent
+        themselves.  Such archives cannot be created by ctf_link, so
+        callers are only expected to need this in conjunction with
+        special-case archive construction tools, and general-purpose
+        callers don't need to worry.  */
+
+      if (!parent_name && arci->ctfi_archive)
+       parent_name = ctf_arc_get_property (arci, "parent_name");
+
+      parent = ctf_dict_open_cached ((ctf_archive_t *) arci, parent_name, &err);
       if (errp)
        *errp = err;
 
@@ -890,12 +1105,12 @@ ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp)
 
 /* Return the number of members in an archive.  */
 size_t
-ctf_archive_count (const ctf_archive_t *wrapper)
+ctf_archive_count (const struct ctf_archive_internal *arci)
 {
-  if (!wrapper->ctfi_is_archive)
+  if (!arci->ctfi_is_archive)
     return 1;
 
-  return le64toh (wrapper->ctfi_archive->ctfa_ndicts);
+  return arci->ctfi_hdr->ctfa_ndicts;
 }
 
 /* Look up a symbol in an archive by name or index (if the name is set, a lookup
@@ -910,7 +1125,7 @@ ctf_archive_count (const ctf_archive_t *wrapper)
    Returns NULL on error, and an error in errp (if set).  */
 
 static ctf_dict_t *
-ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
+ctf_arc_lookup_sym_or_name (struct ctf_archive_internal *arci, unsigned long symidx,
                            const char *symname, ctf_id_t *typep, int *errp)
 {
   ctf_dict_t *fp;
@@ -918,37 +1133,37 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
   ctf_id_t type;
 
   /* The usual non-archive-transparent-wrapper special case.  */
-  if (!wrapper->ctfi_is_archive)
+  if (!arci->ctfi_is_archive)
     {
       if (!symname)
        {
-         if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
+         if ((type = ctf_lookup_by_symbol (arci->ctfi_dict, symidx)) == CTF_ERR)
            {
              if (errp)
-               *errp = ctf_errno (wrapper->ctfi_dict);
+               *errp = ctf_errno (arci->ctfi_dict);
              return NULL;
            }
        }
       else
        {
-         if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict,
+         if ((type = ctf_lookup_by_symbol_name (arci->ctfi_dict,
                                                 symname)) == CTF_ERR)
            {
              if (errp)
-               *errp = ctf_errno (wrapper->ctfi_dict);
+               *errp = ctf_errno (arci->ctfi_dict);
              return NULL;
            }
        }
       if (typep)
        *typep = type;
-      wrapper->ctfi_dict->ctf_refcnt++;
-      return wrapper->ctfi_dict;
+      arci->ctfi_dict->ctf_refcnt++;
+      return arci->ctfi_dict;
     }
 
-  if (wrapper->ctfi_symsect.cts_name == NULL
-      || wrapper->ctfi_symsect.cts_data == NULL
-      || wrapper->ctfi_symsect.cts_size == 0
-      || wrapper->ctfi_symsect.cts_entsize == 0)
+  if (arci->ctfi_symsect.cts_name == NULL
+      || arci->ctfi_symsect.cts_data == NULL
+      || arci->ctfi_symsect.cts_size == 0
+      || arci->ctfi_symsect.cts_entsize == 0)
     {
       if (errp)
        *errp = ECTF_NOSYMTAB;
@@ -961,22 +1176,22 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
      We also cache similar mappings for symbol names: these are ordinary
      dynhashes, with weak links to dicts.  */
 
-  if (!wrapper->ctfi_symdicts)
+  if (!arci->ctfi_symdicts)
     {
-      if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
-                                           / wrapper->ctfi_symsect.cts_entsize,
-                                           sizeof (ctf_dict_t *))) == NULL)
+      if ((arci->ctfi_symdicts = calloc (arci->ctfi_symsect.cts_size
+                                        / arci->ctfi_symsect.cts_entsize,
+                                        sizeof (ctf_dict_t *))) == NULL)
        {
          if (errp)
            *errp = ENOMEM;
          return NULL;
        }
     }
-  if (!wrapper->ctfi_symnamedicts)
+  if (!arci->ctfi_symnamedicts)
     {
-      if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
-                                                           ctf_hash_eq_string,
-                                                           free, NULL)) == NULL)
+      if ((arci->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
+                                                        ctf_hash_eq_string,
+                                                        free, NULL)) == NULL)
        {
          if (errp)
            *errp = ENOMEM;
@@ -989,14 +1204,14 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
      found: this should never happen, but shouldn't be allowed to cause trouble
      if it does.  */
 
-  if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts,
+  if ((symname && ctf_dynhash_lookup_kv (arci->ctfi_symnamedicts,
                                         symname, NULL, &fpkey))
-      || (!symname && wrapper->ctfi_symdicts[symidx] != NULL))
+      || (!symname && arci->ctfi_symdicts[symidx] != NULL))
     {
       if (symname)
        fp = (ctf_dict_t *) fpkey;
       else
-       fp = wrapper->ctfi_symdicts[symidx];
+       fp = arci->ctfi_symdicts[symidx];
 
       if (fp == &enosym)
        goto no_sym;
@@ -1032,12 +1247,12 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
   else
     local_errp = &local_err;
 
-  while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL)
+  while ((fp = ctf_archive_next (arci, &i, &name, 0, local_errp)) != NULL)
     {
       if (!symname)
        {
          if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
-           wrapper->ctfi_symdicts[symidx] = fp;
+           arci->ctfi_symdicts[symidx] = fp;
        }
       else
        {
@@ -1046,7 +1261,7 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
              char *tmp;
              /* No error checking, as above.  */
              if ((tmp = strdup (symname)) != NULL)
-               ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp);
+               ctf_dynhash_insert (arci->ctfi_symnamedicts, tmp, fp);
            }
        }
 
@@ -1078,7 +1293,7 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
 
  cache_no_sym:
   if (!symname)
-    wrapper->ctfi_symdicts[symidx] = &enosym;
+    arci->ctfi_symdicts[symidx] = &enosym;
   else
     {
       char *tmp;
@@ -1086,7 +1301,7 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
       /* No error checking: if caching fails, there is only a slight performance
         impact.  */
       if ((tmp = strdup (symname)) != NULL)
-       if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0)
+       if (ctf_dynhash_insert (arci->ctfi_symnamedicts, tmp, &enosym) < 0)
          free (tmp);
     }
 
@@ -1100,19 +1315,19 @@ ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
 
 /* The public API for looking up a symbol by index.  */
 ctf_dict_t *
-ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
+ctf_arc_lookup_symbol (struct ctf_archive_internal *arci, unsigned long symidx,
                       ctf_id_t *typep, int *errp)
 {
-  return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp);
+  return ctf_arc_lookup_sym_or_name (arci, symidx, NULL, typep, errp);
 }
 
 /* The public API for looking up a symbol by name. */
 
 ctf_dict_t *
-ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
+ctf_arc_lookup_symbol_name (struct ctf_archive_internal *arci, const char *symname,
                            ctf_id_t *typep, int *errp)
 {
-  return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
+  return ctf_arc_lookup_sym_or_name (arci, 0, symname, typep, errp);
 }
 
 /* Return all enumeration constants with a given NAME across all dicts in an
@@ -1122,9 +1337,10 @@ ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
    not optional.  */
 
 ctf_id_t
-ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
-                               ctf_next_t **it, int64_t *enum_value,
-                               ctf_dict_t **dict, int *errp)
+ctf_arc_lookup_enumerator_next (struct ctf_archive_internal *arci,
+                               const char *name, ctf_next_t **it,
+                               int64_t *enum_value, ctf_dict_t **dict,
+                               int *errp)
 {
   ctf_next_t *i = *it;
   ctf_id_t type;
@@ -1146,7 +1362,7 @@ ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
          goto err;
        }
       i->ctn_iter_fun = (void (*) (void)) ctf_arc_lookup_enumerator_next;
-      i->cu.ctn_arc = arc;
+      i->cu.ctn_arc = arci;
       *it = i;
     }
 
@@ -1156,7 +1372,7 @@ ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
       goto err;
     }
 
-  if (arc != i->cu.ctn_arc)
+  if (arci != i->cu.ctn_arc)
     {
       err = ECTF_NEXT_WRONGFP;
       goto err;
@@ -1183,7 +1399,7 @@ ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
              opened_this_time = 0;
            }
 
-         *dict = ctf_archive_next (arc, &i->ctn_next, NULL, 0, &err);
+         *dict = ctf_archive_next (arci, &i->ctn_next, NULL, 0, &err);
          if (!*dict)
            goto err;
          opened_this_time = 1;
@@ -1222,62 +1438,57 @@ ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
   return CTF_ERR;
 }
 
-/* Raw iteration over all CTF files in an archive.  We pass the raw data for all
-   CTF files in turn to the specified callback function.  */
-static int
-ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
-                              ctf_archive_raw_member_f *func, void *data)
+/* Raw iteration over all CTF files in an archive: public entry point.
+
+   Returns -EINVAL if not supported for this sort of archive.  */
+int
+ctf_archive_raw_iter (const struct ctf_archive_internal *arci,
+                     ctf_archive_raw_member_f * func, void *data)
 {
   int rc;
   size_t i;
-  struct ctf_archive_modent *modent;
+  ctf_archive_modent_t *modent;
   const char *nametbl;
 
-  modent = (ctf_archive_modent_t *) ((char *) arc
-                                    + sizeof (struct ctf_archive));
-  nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
+  if (!arci->ctfi_is_archive || !arci->ctfi_archive)
+    return -EINVAL;                            /* Not supported.  */
+
+  modent = (ctf_archive_modent_t *) (arci->ctfi_archive
+                                    + arci->ctfi_hdr->ctfa_modents);
+  nametbl = (const char *) arci->ctfi_archive + arci->ctfi_hdr->ctfa_names;
 
-  for (i = 0; i < le64toh (arc->ctfa_ndicts); i++)
+  for (i = 0; i < arci->ctfi_hdr->ctfa_ndicts; i++)
     {
       const char *name;
-      char *fp;
+      unsigned char *content;
+      size_t name_offset, ctf_offset, ctf_size;
+
+      name_offset = modent[i].name_offset;
+      ctf_offset = modent[i].ctf_offset;
 
-      name = &nametbl[le64toh (modent[i].name_offset)];
-      fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
-           + le64toh (modent[i].ctf_offset));
+      name = &nametbl[name_offset];
+      content = arci->ctfi_archive + arci->ctfi_hdr->ctfa_ctfs + ctf_offset;
+      ctf_size = *((uint64_t *) content);
 
-      if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
-                     le64toh (*((uint64_t *) fp)), data)) != 0)
+      if ((rc = func (name, (void *) (content + sizeof (uint64_t)),
+                     ctf_size, data)) != 0)
        return rc;
     }
   return 0;
 }
 
-/* Raw iteration over all CTF files in an archive: public entry point.
-
-   Returns -EINVAL if not supported for this sort of archive.  */
-int
-ctf_archive_raw_iter (const ctf_archive_t *arc,
-                     ctf_archive_raw_member_f * func, void *data)
-{
-  if (arc->ctfi_is_archive)
-    return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
-
-  return -EINVAL;                       /* Not supported. */
-}
-
 /* Iterate over all CTF files in an archive: public entry point.  We pass all
    CTF files in turn to the specified callback function.  */
 int
-ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
-                 void *data)
+ctf_archive_iter (const struct ctf_archive_internal *arci,
+                 ctf_archive_member_f *func, void *data)
 {
   ctf_next_t *i = NULL;
   ctf_dict_t *fp;
   const char *name;
   int err = 0;
 
-  while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL)
+  while ((fp = ctf_archive_next (arci, &i, &name, 0, &err)) != NULL)
     {
       int rc;
 
@@ -1307,13 +1518,12 @@ ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
    linker only emitting parents named _CTF_SECTION, this works well enough.  */
 
 ctf_dict_t *
-ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name,
-                 int skip_parent, int *errp)
+ctf_archive_next (const struct ctf_archive_internal *arci, ctf_next_t **it,
+                 const char **name, int skip_parent, int *errp)
 {
   ctf_dict_t *f;
   ctf_next_t *i = *it;
-  struct ctf_archive *arc;
-  struct ctf_archive_modent *modent;
+  ctf_archive_modent_t *modent;
   const char *nametbl;
   const char *name_;
 
@@ -1325,7 +1535,7 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
            *errp = ENOMEM;
          return NULL;
        }
-      i->cu.ctn_arc = wrapper;
+      i->cu.ctn_arc = arci;
       i->ctn_iter_fun = (void (*) (void)) ctf_archive_next;
       *it = i;
     }
@@ -1337,7 +1547,7 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
       return NULL;
     }
 
-  if (wrapper != i->cu.ctn_arc)
+  if (arci != i->cu.ctn_arc)
     {
       if (errp)
        *errp = ECTF_NEXT_WRONGFP;
@@ -1349,27 +1559,25 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
      skip_parent is on, they are skipped and the iterator terminates
      immediately.  */
 
-  if (!wrapper->ctfi_is_archive && i->ctn_n == 0)
+  if (!arci->ctfi_is_archive && i->ctn_n == 0)
     {
       i->ctn_n++;
       if (!skip_parent)
        {
-         wrapper->ctfi_dict->ctf_refcnt++;
+         arci->ctfi_dict->ctf_refcnt++;
          if (name)
            *name = _CTF_SECTION;
-         return wrapper->ctfi_dict;
+         return arci->ctfi_dict;
        }
     }
 
-  arc = wrapper->ctfi_archive;
-
   /* The loop keeps going when skip_parent is on as long as the member we find
      is the parent (i.e. at most two iterations, but possibly an early return if
      *all* we have is a parent).  */
 
   do
     {
-      if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts)))
+      if ((!arci->ctfi_is_archive) || (i->ctn_n >= arci->ctfi_hdr->ctfa_ndicts))
        {
          ctf_next_destroy (i);
          *it = NULL;
@@ -1378,11 +1586,10 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
          return NULL;
        }
 
-      modent = (ctf_archive_modent_t *) ((char *) arc
-                                        + sizeof (struct ctf_archive));
-      nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
-
-      name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
+      modent = (ctf_archive_modent_t *) ((char *) arci->ctfi_archive
+                                    + arci->ctfi_hdr->ctfa_modents);
+      nametbl = (const char *) arci->ctfi_archive + arci->ctfi_hdr->ctfa_names;
+      name_ = &nametbl[modent[i->ctn_n].name_offset];
       i->ctn_n++;
     }
   while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
@@ -1390,7 +1597,7 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
   if (name)
     *name = name_;
 
-  f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp);
+  f = ctf_dict_open_cached ((ctf_archive_t *) arci, name_, errp);
   return f;
 }
 
index 92b57b33dfa8e7683a64dde141e72f0c5660cc19..af45dfeb4450fc7c95714fe726f84c306979a4d4 100644 (file)
@@ -552,18 +552,21 @@ struct ctf_archive_internal
   int ctfi_is_archive;
   int ctfi_unmap_on_close;
   ctf_dict_t *ctfi_dict;
-  struct ctf_archive *ctfi_archive;
-  ctf_dynhash_t *ctfi_dicts;     /* Dicts we have opened and cached.  */
+  unsigned char *ctfi_archive;
+  struct ctf_archive *ctfi_hdr;            /* Always malloced.  Header only.  */
+  size_t ctfi_hdr_len;
+  int ctfi_archive_v1;             /* If set, this is a v1 archive.  */
+  ctf_dynhash_t *ctfi_dicts;       /* Dicts we have opened and cached.  */
   ctf_dict_t *ctfi_crossdict_cache; /* Cross-dict caching.  */
-  ctf_dict_t **ctfi_symdicts;    /* Array of index -> ctf_dict_t *.  */
+  ctf_dict_t **ctfi_symdicts;      /* Array of index -> ctf_dict_t *.  */
   ctf_dynhash_t *ctfi_symnamedicts; /* Hash of name -> ctf_dict_t *.  */
   ctf_sect_t ctfi_symsect;
-  int ctfi_symsect_little_endian; /* -1 for unknown / do not set.  */
+  int ctfi_symsect_little_endian;   /* -1 for unknown / do not set.  */
   ctf_sect_t ctfi_strsect;
   int ctfi_free_symsect;
   int ctfi_free_strsect;
   void *ctfi_data;
-  bfd *ctfi_abfd;                /* Optional source of section data.  */
+  bfd *ctfi_abfd;                  /* Optional source of section data.  */
   void (*ctfi_bfd_close) (struct ctf_archive_internal *);
 };
 
@@ -815,13 +818,12 @@ extern int ctf_preserialize (ctf_dict_t *fp, int force_ctf);
 extern void ctf_depreserialize (ctf_dict_t *fp);
 
 extern struct ctf_archive_internal *
-ctf_new_archive_internal (int is_archive, int unmap_on_close,
-                         struct ctf_archive *, ctf_dict_t *,
-                         const ctf_sect_t *symsect,
+ctf_new_archive_internal (int is_archive, int is_v1, int unmap_on_close,
+                         struct ctf_archive *, size_t,
+                         ctf_dict_t *, const ctf_sect_t *symsect,
                          const ctf_sect_t *strsect, int *errp);
-extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
-extern void ctf_arc_close_internal (struct ctf_archive *);
-extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
+extern struct ctf_archive_internal *ctf_arc_open_internal (const char *, int *);
+extern const ctf_preamble_t *ctf_arc_bufpreamble_v1 (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
 extern int ctf_flip_header (void *, int, int);
 extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *,
index 62a87d16111bd87163714adec83c09fec6677f7a..479d9789bd92ac6457e79e12f0969d62b245eba3 100644 (file)
@@ -1177,7 +1177,7 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
         equal to the CU name.  We have to wrap it in an archive wrapper
         first.  */
 
-      if ((in_arc = ctf_new_archive_internal (0, 0, NULL, outputs[0], NULL,
+      if ((in_arc = ctf_new_archive_internal (0, 0, 0, NULL, 0, outputs[0], NULL,
                                              NULL, &err)) == NULL)
        {
          ctf_set_errno (fp, err);
index d1210116f778a545cf01f82a4caf08ae40e49c80..59df2302b59cc7c5e95c92e3b5b737ec5e9b3854 100644 (file)
@@ -119,9 +119,20 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
       bfderrstr = N_("CTF section is NULL");
       goto err;
     }
-  preamble = ctf_arc_bufpreamble (ctfsect);
 
-  if (preamble->ctp_flags & CTF_F_DYNSTR)
+  /* v3 dicts may cite the symtab or the dynsymtab, without using sh_link to
+     indicate which: pick the right one.  v4 dicts always use the dynsymtab (for
+     now).  */
+
+  errno = 0;
+  preamble = ctf_arc_bufpreamble_v1 (ctfsect);
+  if (!preamble && errno == EOVERFLOW)
+    {
+      bfderrstr = N_("section too short to be CTF or BTF");
+      goto err;
+    }
+
+  if (!preamble || (preamble && preamble->ctp_flags & CTF_F_DYNSTR))
     {
       symhdr = &elf_tdata (abfd)->dynsymtab_hdr;
       strtab_name = ".dynstr";
@@ -301,21 +312,16 @@ ctf_fdopen (int fd, const char *filename, const char *target, int *errp)
       fp->ctf_data_mmapped = data;
       fp->ctf_data_mmapped_len = (size_t) st.st_size;
 
-      return ctf_new_archive_internal (0, 1, NULL, fp, NULL, NULL, errp);
+      return ctf_new_archive_internal (0, 0, 1, NULL, 0, fp, NULL, NULL, errp);
     }
 
   if ((nbytes = ctf_pread (fd, &arc_magic, sizeof (arc_magic), 0)) <= 0)
     return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT));
 
-  if ((size_t) nbytes >= sizeof (uint64_t) && le64toh (arc_magic) == CTFA_MAGIC)
-    {
-      struct ctf_archive *arc;
-
-      if ((arc = ctf_arc_open_internal (filename, errp)) == NULL)
-       return NULL;                    /* errno is set for us.  */
-
-      return ctf_new_archive_internal (1, 1, arc, NULL, NULL, NULL, errp);
-    }
+  if ((size_t) nbytes >= sizeof (uint64_t)
+      && (arc_magic == CTFA_MAGIC || bswap_64 (arc_magic) == CTFA_MAGIC
+         || le64toh (arc_magic) == CTFA_V1_MAGIC))
+      return ctf_arc_open_internal (filename, errp);
 
   /* Attempt to open the file with BFD.  We must dup the fd first, since bfd
      takes ownership of the passed fd.  */