Home | History | Annotate | Line # | Download | only in libctf
ctf-archive.c revision 1.1.1.5
      1      1.1  christos /* CTF archive files.
      2  1.1.1.5  christos    Copyright (C) 2019-2025 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    This file is part of libctf.
      5      1.1  christos 
      6      1.1  christos    libctf is free software; you can redistribute it and/or modify it under
      7      1.1  christos    the terms of the GNU General Public License as published by the Free
      8      1.1  christos    Software Foundation; either version 3, or (at your option) any later
      9      1.1  christos    version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful, but
     12      1.1  christos    WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14      1.1  christos    See the GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program; see the file COPYING.  If not see
     18      1.1  christos    <http://www.gnu.org/licenses/>.  */
     19      1.1  christos 
     20      1.1  christos #include <ctf-impl.h>
     21      1.1  christos #include <sys/types.h>
     22      1.1  christos #include <sys/stat.h>
     23      1.1  christos #include <elf.h>
     24      1.1  christos #include "ctf-endian.h"
     25      1.1  christos #include <errno.h>
     26      1.1  christos #include <fcntl.h>
     27      1.1  christos #include <stdio.h>
     28      1.1  christos #include <string.h>
     29      1.1  christos #include <unistd.h>
     30      1.1  christos 
     31      1.1  christos #ifdef HAVE_MMAP
     32      1.1  christos #include <sys/mman.h>
     33      1.1  christos #endif
     34      1.1  christos 
     35  1.1.1.2  christos static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold);
     36  1.1.1.2  christos static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc,
     37  1.1.1.2  christos 					    const ctf_sect_t *symsect,
     38  1.1.1.2  christos 					    const ctf_sect_t *strsect,
     39  1.1.1.2  christos 					    size_t offset, int little_endian,
     40  1.1.1.2  christos 					    int *errp);
     41      1.1  christos static int sort_modent_by_name (const void *one, const void *two, void *n);
     42      1.1  christos static void *arc_mmap_header (int fd, size_t headersz);
     43      1.1  christos static void *arc_mmap_file (int fd, size_t size);
     44      1.1  christos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
     45      1.1  christos 			      const char **errmsg);
     46      1.1  christos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
     47  1.1.1.3  christos static int ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp,
     48  1.1.1.3  christos 				  int *errp);
     49  1.1.1.2  christos 
     50  1.1.1.2  christos /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts
     51  1.1.1.2  christos    and ctfi_symnamedicts.  Never initialized.  */
     52  1.1.1.2  christos static ctf_dict_t enosym;
     53      1.1  christos 
     54      1.1  christos /* Write out a CTF archive to the start of the file referenced by the passed-in
     55  1.1.1.2  christos    fd.  The entries in CTF_DICTS are referenced by name: the names are passed in
     56  1.1.1.2  christos    the names array, which must have CTF_DICTS entries.
     57      1.1  christos 
     58      1.1  christos    Returns 0 on success, or an errno, or an ECTF_* value.  */
     59      1.1  christos int
     60  1.1.1.2  christos ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
     61      1.1  christos 		  const char **names, size_t threshold)
     62      1.1  christos {
     63      1.1  christos   const char *errmsg;
     64      1.1  christos   struct ctf_archive *archdr;
     65      1.1  christos   size_t i;
     66      1.1  christos   char dummy = 0;
     67      1.1  christos   size_t headersz;
     68      1.1  christos   ssize_t namesz;
     69      1.1  christos   size_t ctf_startoffs;		/* Start of the section we are working over.  */
     70      1.1  christos   char *nametbl = NULL;		/* The name table.  */
     71      1.1  christos   char *np;
     72      1.1  christos   off_t nameoffs;
     73      1.1  christos   struct ctf_archive_modent *modent;
     74      1.1  christos 
     75      1.1  christos   ctf_dprintf ("Writing CTF archive with %lu files\n",
     76  1.1.1.2  christos 	       (unsigned long) ctf_dict_cnt);
     77      1.1  christos 
     78      1.1  christos   /* Figure out the size of the mmap()ed header, including the
     79      1.1  christos      ctf_archive_modent array.  We assume that all of this needs no
     80      1.1  christos      padding: a likely assumption, given that it's all made up of
     81      1.1  christos      uint64_t's.  */
     82      1.1  christos   headersz = sizeof (struct ctf_archive)
     83  1.1.1.2  christos     + (ctf_dict_cnt * sizeof (uint64_t) * 2);
     84      1.1  christos   ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
     85      1.1  christos 
     86      1.1  christos   /* From now on we work in two pieces: an mmap()ed region from zero up to the
     87      1.1  christos      headersz, and a region updated via write() starting after that, containing
     88      1.1  christos      all the tables.  Platforms that do not support mmap() just use write().  */
     89      1.1  christos   ctf_startoffs = headersz;
     90      1.1  christos   if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
     91      1.1  christos     {
     92      1.1  christos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
     93      1.1  christos       goto err;
     94      1.1  christos     }
     95      1.1  christos 
     96      1.1  christos   if (write (fd, &dummy, 1) < 0)
     97      1.1  christos     {
     98      1.1  christos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
     99      1.1  christos       goto err;
    100      1.1  christos     }
    101      1.1  christos 
    102      1.1  christos   if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
    103      1.1  christos     {
    104      1.1  christos       errmsg = N_("ctf_arc_write(): cannot mmap");
    105      1.1  christos       goto err;
    106      1.1  christos     }
    107      1.1  christos 
    108      1.1  christos   /* Fill in everything we can, which is everything other than the name
    109      1.1  christos      table offset.  */
    110      1.1  christos   archdr->ctfa_magic = htole64 (CTFA_MAGIC);
    111  1.1.1.2  christos   archdr->ctfa_ndicts = htole64 (ctf_dict_cnt);
    112      1.1  christos   archdr->ctfa_ctfs = htole64 (ctf_startoffs);
    113      1.1  christos 
    114      1.1  christos   /* We could validate that all CTF files have the same data model, but
    115      1.1  christos      since any reasonable construction process will be building things of
    116      1.1  christos      only one bitness anyway, this is pretty pointless, so just use the
    117      1.1  christos      model of the first CTF file for all of them.  (It *is* valid to
    118      1.1  christos      create an empty archive: the value of ctfa_model is irrelevant in
    119      1.1  christos      this case, but we must be sure not to dereference uninitialized
    120      1.1  christos      memory.)  */
    121      1.1  christos 
    122  1.1.1.2  christos   if (ctf_dict_cnt > 0)
    123  1.1.1.2  christos     archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0]));
    124      1.1  christos 
    125      1.1  christos   /* Now write out the CTFs: ctf_archive_modent array via the mapping,
    126      1.1  christos      ctfs via write().  The names themselves have not been written yet: we
    127      1.1  christos      track them in a local strtab until the time is right, and sort the
    128      1.1  christos      modents array after construction.
    129      1.1  christos 
    130      1.1  christos     The name table is not sorted.  */
    131      1.1  christos 
    132  1.1.1.2  christos   for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++)
    133      1.1  christos     namesz += strlen (names[i]) + 1;
    134      1.1  christos 
    135      1.1  christos   nametbl = malloc (namesz);
    136      1.1  christos   if (nametbl == NULL)
    137      1.1  christos     {
    138      1.1  christos       errmsg = N_("ctf_arc_write(): error writing named CTF to archive");
    139      1.1  christos       goto err_unmap;
    140      1.1  christos     }
    141      1.1  christos 
    142      1.1  christos   for (i = 0, namesz = 0,
    143      1.1  christos        modent = (ctf_archive_modent_t *) ((char *) archdr
    144      1.1  christos 					  + sizeof (struct ctf_archive));
    145  1.1.1.2  christos        i < le64toh (archdr->ctfa_ndicts); i++)
    146      1.1  christos     {
    147      1.1  christos       off_t off;
    148      1.1  christos 
    149      1.1  christos       strcpy (&nametbl[namesz], names[i]);
    150      1.1  christos 
    151  1.1.1.2  christos       off = arc_write_one_ctf (ctf_dicts[i], fd, threshold);
    152      1.1  christos       if ((off < 0) && (off > -ECTF_BASE))
    153      1.1  christos 	{
    154      1.1  christos 	  errmsg = N_("ctf_arc_write(): cannot determine file "
    155      1.1  christos 		      "position while writing to archive");
    156      1.1  christos 	  goto err_free;
    157      1.1  christos 	}
    158      1.1  christos       if (off < 0)
    159      1.1  christos 	{
    160      1.1  christos 	  errmsg = N_("ctf_arc_write(): cannot write CTF file to archive");
    161      1.1  christos 	  errno = off * -1;
    162      1.1  christos 	  goto err_free;
    163      1.1  christos 	}
    164      1.1  christos 
    165      1.1  christos       modent->name_offset = htole64 (namesz);
    166      1.1  christos       modent->ctf_offset = htole64 (off - ctf_startoffs);
    167      1.1  christos       namesz += strlen (names[i]) + 1;
    168      1.1  christos       modent++;
    169      1.1  christos     }
    170      1.1  christos 
    171      1.1  christos   ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
    172      1.1  christos 					 + sizeof (struct ctf_archive)),
    173  1.1.1.2  christos 	       le64toh (archdr->ctfa_ndicts),
    174      1.1  christos 	       sizeof (struct ctf_archive_modent), sort_modent_by_name,
    175      1.1  christos 	       nametbl);
    176      1.1  christos 
    177      1.1  christos    /* Now the name table.  */
    178      1.1  christos 
    179      1.1  christos   if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
    180      1.1  christos     {
    181      1.1  christos       errmsg = N_("ctf_arc_write(): cannot get current file position "
    182      1.1  christos 		  "in archive");
    183      1.1  christos       goto err_free;
    184      1.1  christos     }
    185      1.1  christos   archdr->ctfa_names = htole64 (nameoffs);
    186      1.1  christos   np = nametbl;
    187      1.1  christos   while (namesz > 0)
    188      1.1  christos     {
    189      1.1  christos       ssize_t len;
    190      1.1  christos       if ((len = write (fd, np, namesz)) < 0)
    191      1.1  christos 	{
    192      1.1  christos 	  errmsg = N_("ctf_arc_write(): cannot write name table to archive");
    193      1.1  christos 	  goto err_free;
    194      1.1  christos 	}
    195      1.1  christos       namesz -= len;
    196      1.1  christos       np += len;
    197      1.1  christos     }
    198      1.1  christos   free (nametbl);
    199      1.1  christos 
    200      1.1  christos   if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
    201      1.1  christos     goto err_unmap;
    202      1.1  christos   if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
    203      1.1  christos     goto err;
    204      1.1  christos   return 0;
    205      1.1  christos 
    206      1.1  christos err_free:
    207      1.1  christos   free (nametbl);
    208      1.1  christos err_unmap:
    209      1.1  christos   arc_mmap_unmap (archdr, headersz, NULL);
    210      1.1  christos err:
    211      1.1  christos   /* We report errors into the first file in the archive, if any: if this is a
    212      1.1  christos      zero-file archive, put it in the open-errors stream for lack of anywhere
    213      1.1  christos      else for it to go.  */
    214  1.1.1.2  christos   ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, "%s",
    215      1.1  christos 		gettext (errmsg));
    216      1.1  christos   return errno;
    217      1.1  christos }
    218      1.1  christos 
    219  1.1.1.2  christos /* Write out a CTF archive.  The entries in CTF_DICTS are referenced by name:
    220  1.1.1.2  christos    the names are passed in the names array, which must have CTF_DICTS entries.
    221      1.1  christos 
    222      1.1  christos    If the filename is NULL, create a temporary file and return a pointer to it.
    223      1.1  christos 
    224      1.1  christos    Returns 0 on success, or an errno, or an ECTF_* value.  */
    225      1.1  christos int
    226  1.1.1.2  christos ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
    227      1.1  christos 	       const char **names, size_t threshold)
    228      1.1  christos {
    229      1.1  christos   int err;
    230      1.1  christos   int fd;
    231      1.1  christos 
    232      1.1  christos   if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
    233      1.1  christos     {
    234  1.1.1.2  christos       ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
    235      1.1  christos 		    _("ctf_arc_write(): cannot create %s"), file);
    236      1.1  christos       return errno;
    237      1.1  christos     }
    238      1.1  christos 
    239  1.1.1.2  christos   err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, names, threshold);
    240      1.1  christos   if (err)
    241      1.1  christos     goto err_close;
    242      1.1  christos 
    243      1.1  christos   if ((err = close (fd)) < 0)
    244  1.1.1.2  christos     ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
    245      1.1  christos 		  _("ctf_arc_write(): cannot close after writing to archive"));
    246      1.1  christos   goto err;
    247      1.1  christos 
    248      1.1  christos  err_close:
    249      1.1  christos   (void) close (fd);
    250      1.1  christos  err:
    251      1.1  christos   if (err < 0)
    252      1.1  christos     unlink (file);
    253      1.1  christos 
    254      1.1  christos   return err;
    255      1.1  christos }
    256      1.1  christos 
    257  1.1.1.3  christos /* Write one CTF dict out.  Return the file position of the written file (or
    258      1.1  christos    rather, of the file-size uint64_t that precedes it): negative return is a
    259      1.1  christos    negative errno or ctf_errno value.  On error, the file position may no longer
    260      1.1  christos    be at the end of the file.  */
    261      1.1  christos static off_t
    262  1.1.1.3  christos arc_write_one_ctf (ctf_dict_t *f, int fd, size_t threshold)
    263      1.1  christos {
    264      1.1  christos   off_t off, end_off;
    265      1.1  christos   uint64_t ctfsz = 0;
    266      1.1  christos   char *ctfszp;
    267      1.1  christos   size_t ctfsz_len;
    268      1.1  christos 
    269      1.1  christos   if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
    270      1.1  christos     return errno * -1;
    271      1.1  christos 
    272      1.1  christos   /* This zero-write turns into the size in a moment. */
    273      1.1  christos   ctfsz_len = sizeof (ctfsz);
    274      1.1  christos   ctfszp = (char *) &ctfsz;
    275      1.1  christos   while (ctfsz_len > 0)
    276      1.1  christos     {
    277      1.1  christos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
    278      1.1  christos       if (writelen < 0)
    279      1.1  christos 	return errno * -1;
    280      1.1  christos       ctfsz_len -= writelen;
    281      1.1  christos       ctfszp += writelen;
    282      1.1  christos     }
    283      1.1  christos 
    284  1.1.1.4  christos   if (ctf_write_thresholded (f, fd, threshold) != 0)
    285      1.1  christos     return f->ctf_errno * -1;
    286      1.1  christos 
    287      1.1  christos   if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
    288      1.1  christos     return errno * -1;
    289      1.1  christos   ctfsz = htole64 (end_off - off);
    290      1.1  christos 
    291      1.1  christos   if ((lseek (fd, off, SEEK_SET)) < 0)
    292      1.1  christos     return errno * -1;
    293      1.1  christos 
    294      1.1  christos   /* ... here.  */
    295      1.1  christos   ctfsz_len = sizeof (ctfsz);
    296      1.1  christos   ctfszp = (char *) &ctfsz;
    297      1.1  christos   while (ctfsz_len > 0)
    298      1.1  christos     {
    299      1.1  christos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
    300      1.1  christos       if (writelen < 0)
    301      1.1  christos 	return errno * -1;
    302      1.1  christos       ctfsz_len -= writelen;
    303      1.1  christos       ctfszp += writelen;
    304      1.1  christos     }
    305      1.1  christos 
    306      1.1  christos   end_off = LCTF_ALIGN_OFFS (end_off, 8);
    307      1.1  christos   if ((lseek (fd, end_off, SEEK_SET)) < 0)
    308      1.1  christos     return errno * -1;
    309      1.1  christos 
    310      1.1  christos   return off;
    311      1.1  christos }
    312      1.1  christos 
    313      1.1  christos /* qsort() function to sort the array of struct ctf_archive_modents into
    314      1.1  christos    ascending name order.  */
    315      1.1  christos static int
    316      1.1  christos sort_modent_by_name (const void *one, const void *two, void *n)
    317      1.1  christos {
    318      1.1  christos   const struct ctf_archive_modent *a = one;
    319      1.1  christos   const struct ctf_archive_modent *b = two;
    320      1.1  christos   char *nametbl = n;
    321      1.1  christos 
    322      1.1  christos   return strcmp (&nametbl[le64toh (a->name_offset)],
    323      1.1  christos 		 &nametbl[le64toh (b->name_offset)]);
    324      1.1  christos }
    325      1.1  christos 
    326      1.1  christos /* bsearch_r() function to search for a given name in the sorted array of struct
    327      1.1  christos    ctf_archive_modents.  */
    328      1.1  christos static int
    329      1.1  christos search_modent_by_name (const void *key, const void *ent, void *arg)
    330      1.1  christos {
    331      1.1  christos   const char *k = key;
    332      1.1  christos   const struct ctf_archive_modent *v = ent;
    333      1.1  christos   const char *search_nametbl = arg;
    334      1.1  christos 
    335      1.1  christos   return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
    336      1.1  christos }
    337      1.1  christos 
    338      1.1  christos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
    339  1.1.1.2  christos    ctf_dict.  Closes ARC and/or FP on error.  Arrange to free the SYMSECT or
    340      1.1  christos    STRSECT, as needed, on close.  Possibly do not unmap on close.  */
    341      1.1  christos 
    342      1.1  christos struct ctf_archive_internal *
    343      1.1  christos ctf_new_archive_internal (int is_archive, int unmap_on_close,
    344      1.1  christos 			  struct ctf_archive *arc,
    345  1.1.1.2  christos 			  ctf_dict_t *fp, const ctf_sect_t *symsect,
    346      1.1  christos 			  const ctf_sect_t *strsect,
    347      1.1  christos 			  int *errp)
    348      1.1  christos {
    349      1.1  christos   struct ctf_archive_internal *arci;
    350      1.1  christos 
    351      1.1  christos   if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
    352      1.1  christos     {
    353      1.1  christos       if (is_archive)
    354      1.1  christos 	{
    355      1.1  christos 	  if (unmap_on_close)
    356      1.1  christos 	    ctf_arc_close_internal (arc);
    357      1.1  christos 	}
    358      1.1  christos       else
    359  1.1.1.2  christos 	ctf_dict_close (fp);
    360      1.1  christos       return (ctf_set_open_errno (errp, errno));
    361      1.1  christos     }
    362      1.1  christos   arci->ctfi_is_archive = is_archive;
    363      1.1  christos   if (is_archive)
    364      1.1  christos     arci->ctfi_archive = arc;
    365      1.1  christos   else
    366  1.1.1.2  christos     arci->ctfi_dict = fp;
    367      1.1  christos   if (symsect)
    368      1.1  christos      memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect));
    369      1.1  christos   if (strsect)
    370      1.1  christos      memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
    371      1.1  christos   arci->ctfi_free_symsect = 0;
    372      1.1  christos   arci->ctfi_free_strsect = 0;
    373      1.1  christos   arci->ctfi_unmap_on_close = unmap_on_close;
    374  1.1.1.2  christos   arci->ctfi_symsect_little_endian = -1;
    375      1.1  christos 
    376      1.1  christos   return arci;
    377      1.1  christos }
    378      1.1  christos 
    379  1.1.1.2  christos /* Set the symbol-table endianness of an archive (defaulting the symtab
    380  1.1.1.2  christos    endianness of all ctf_file_t's opened from that archive).  */
    381  1.1.1.2  christos void
    382  1.1.1.2  christos ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian)
    383  1.1.1.2  christos {
    384  1.1.1.2  christos   arc->ctfi_symsect_little_endian = !!little_endian;
    385  1.1.1.2  christos   if (!arc->ctfi_is_archive)
    386  1.1.1.2  christos     ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian);
    387  1.1.1.2  christos }
    388  1.1.1.2  christos 
    389  1.1.1.2  christos /* Get the CTF preamble from data in a buffer, which may be either an archive or
    390  1.1.1.2  christos    a CTF dict.  If multiple dicts are present in an archive, the preamble comes
    391  1.1.1.2  christos    from an arbitrary dict.  The preamble is a pointer into the ctfsect passed
    392  1.1.1.2  christos    in.  */
    393  1.1.1.2  christos 
    394  1.1.1.2  christos const ctf_preamble_t *
    395  1.1.1.2  christos ctf_arc_bufpreamble (const ctf_sect_t *ctfsect)
    396  1.1.1.2  christos {
    397  1.1.1.3  christos   if (ctfsect->cts_data != NULL
    398  1.1.1.3  christos       && ctfsect->cts_size > sizeof (uint64_t)
    399  1.1.1.3  christos       && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
    400  1.1.1.2  christos     {
    401  1.1.1.2  christos       struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
    402  1.1.1.2  christos       return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
    403  1.1.1.2  christos 				       + sizeof (uint64_t));
    404  1.1.1.2  christos     }
    405  1.1.1.2  christos   else
    406  1.1.1.2  christos     return (const ctf_preamble_t *) ctfsect->cts_data;
    407  1.1.1.2  christos }
    408  1.1.1.2  christos 
    409      1.1  christos /* Open a CTF archive or dictionary from data in a buffer (which the caller must
    410      1.1  christos    preserve until ctf_arc_close() time).  Returns the archive, or NULL and an
    411      1.1  christos    error in *err (if not NULL).  */
    412      1.1  christos ctf_archive_t *
    413      1.1  christos ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
    414      1.1  christos 		 const ctf_sect_t *strsect, int *errp)
    415      1.1  christos {
    416      1.1  christos   struct ctf_archive *arc = NULL;
    417      1.1  christos   int is_archive;
    418  1.1.1.2  christos   ctf_dict_t *fp = NULL;
    419      1.1  christos 
    420  1.1.1.3  christos   if (ctfsect->cts_data != NULL
    421  1.1.1.3  christos       && ctfsect->cts_size > sizeof (uint64_t)
    422  1.1.1.3  christos       && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
    423      1.1  christos     {
    424      1.1  christos       /* The archive is mmappable, so this operation is trivial.
    425      1.1  christos 
    426      1.1  christos 	 This buffer is nonmodifiable, so the trick involving mmapping only part
    427      1.1  christos 	 of it and storing the length in the magic number is not applicable: so
    428      1.1  christos 	 record this fact in the archive-wrapper header.  (We cannot record it
    429      1.1  christos 	 in the archive, because the archive may very well be a read-only
    430      1.1  christos 	 mapping.)  */
    431      1.1  christos 
    432      1.1  christos       is_archive = 1;
    433      1.1  christos       arc = (struct ctf_archive *) ctfsect->cts_data;
    434      1.1  christos     }
    435      1.1  christos   else
    436      1.1  christos     {
    437      1.1  christos       is_archive = 0;
    438      1.1  christos       if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL)
    439      1.1  christos 	{
    440      1.1  christos 	  ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF"));
    441      1.1  christos 	  return NULL;
    442      1.1  christos 	}
    443      1.1  christos     }
    444      1.1  christos   return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect,
    445      1.1  christos 				   errp);
    446      1.1  christos }
    447      1.1  christos 
    448      1.1  christos /* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
    449      1.1  christos    not NULL).  */
    450      1.1  christos struct ctf_archive *
    451      1.1  christos ctf_arc_open_internal (const char *filename, int *errp)
    452      1.1  christos {
    453      1.1  christos   const char *errmsg;
    454      1.1  christos   int fd;
    455      1.1  christos   struct stat s;
    456      1.1  christos   struct ctf_archive *arc;		/* (Actually the whole file.)  */
    457      1.1  christos 
    458      1.1  christos   libctf_init_debug();
    459      1.1  christos   if ((fd = open (filename, O_RDONLY)) < 0)
    460      1.1  christos     {
    461      1.1  christos       errmsg = N_("ctf_arc_open(): cannot open %s");
    462      1.1  christos       goto err;
    463      1.1  christos     }
    464      1.1  christos   if (fstat (fd, &s) < 0)
    465      1.1  christos     {
    466      1.1  christos       errmsg = N_("ctf_arc_open(): cannot stat %s");
    467      1.1  christos       goto err_close;
    468      1.1  christos     }
    469      1.1  christos 
    470      1.1  christos   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
    471      1.1  christos     {
    472      1.1  christos       errmsg = N_("ctf_arc_open(): cannot read in %s");
    473      1.1  christos       goto err_close;
    474      1.1  christos     }
    475      1.1  christos 
    476      1.1  christos   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
    477      1.1  christos     {
    478      1.1  christos       errmsg = N_("ctf_arc_open(): %s: invalid magic number");
    479      1.1  christos       errno = ECTF_FMT;
    480      1.1  christos       goto err_unmap;
    481      1.1  christos     }
    482      1.1  christos 
    483      1.1  christos   /* This horrible hack lets us know how much to unmap when the file is
    484      1.1  christos      closed.  (We no longer need the magic number, and the mapping
    485      1.1  christos      is private.)  */
    486      1.1  christos   arc->ctfa_magic = s.st_size;
    487      1.1  christos   close (fd);
    488  1.1.1.5  christos 
    489  1.1.1.5  christos   if (errp)
    490  1.1.1.5  christos     *errp = 0;
    491  1.1.1.5  christos 
    492      1.1  christos   return arc;
    493      1.1  christos 
    494      1.1  christos err_unmap:
    495      1.1  christos   arc_mmap_unmap (arc, s.st_size, NULL);
    496      1.1  christos err_close:
    497      1.1  christos   close (fd);
    498      1.1  christos err:
    499      1.1  christos   if (errp)
    500      1.1  christos     *errp = errno;
    501      1.1  christos   ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename);
    502      1.1  christos   return NULL;
    503      1.1  christos }
    504      1.1  christos 
    505      1.1  christos /* Close an archive.  */
    506      1.1  christos void
    507      1.1  christos ctf_arc_close_internal (struct ctf_archive *arc)
    508      1.1  christos {
    509      1.1  christos   if (arc == NULL)
    510      1.1  christos     return;
    511      1.1  christos 
    512      1.1  christos   /* See the comment in ctf_arc_open().  */
    513      1.1  christos   arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
    514      1.1  christos }
    515      1.1  christos 
    516      1.1  christos /* Public entry point: close an archive, or CTF file.  */
    517      1.1  christos void
    518      1.1  christos ctf_arc_close (ctf_archive_t *arc)
    519      1.1  christos {
    520      1.1  christos   if (arc == NULL)
    521      1.1  christos     return;
    522      1.1  christos 
    523      1.1  christos   if (arc->ctfi_is_archive)
    524      1.1  christos     {
    525      1.1  christos       if (arc->ctfi_unmap_on_close)
    526      1.1  christos 	ctf_arc_close_internal (arc->ctfi_archive);
    527      1.1  christos     }
    528      1.1  christos   else
    529  1.1.1.2  christos     ctf_dict_close (arc->ctfi_dict);
    530  1.1.1.2  christos   free (arc->ctfi_symdicts);
    531  1.1.1.2  christos   free (arc->ctfi_symnamedicts);
    532  1.1.1.2  christos   ctf_dynhash_destroy (arc->ctfi_dicts);
    533      1.1  christos   if (arc->ctfi_free_symsect)
    534      1.1  christos     free ((void *) arc->ctfi_symsect.cts_data);
    535      1.1  christos   if (arc->ctfi_free_strsect)
    536      1.1  christos     free ((void *) arc->ctfi_strsect.cts_data);
    537      1.1  christos   free (arc->ctfi_data);
    538      1.1  christos   if (arc->ctfi_bfd_close)
    539      1.1  christos     arc->ctfi_bfd_close (arc);
    540      1.1  christos   free (arc);
    541      1.1  christos }
    542      1.1  christos 
    543  1.1.1.2  christos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
    544      1.1  christos    non-NULL.  A name of NULL means to open the default file.  */
    545  1.1.1.2  christos static ctf_dict_t *
    546  1.1.1.2  christos ctf_dict_open_internal (const struct ctf_archive *arc,
    547  1.1.1.2  christos 			const ctf_sect_t *symsect,
    548  1.1.1.2  christos 			const ctf_sect_t *strsect,
    549  1.1.1.2  christos 			const char *name, int little_endian,
    550  1.1.1.2  christos 			int *errp)
    551      1.1  christos {
    552      1.1  christos   struct ctf_archive_modent *modent;
    553      1.1  christos   const char *search_nametbl;
    554      1.1  christos 
    555      1.1  christos   if (name == NULL)
    556      1.1  christos     name = _CTF_SECTION;		 /* The default name.  */
    557      1.1  christos 
    558  1.1.1.2  christos   ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name);
    559      1.1  christos 
    560      1.1  christos   modent = (ctf_archive_modent_t *) ((char *) arc
    561      1.1  christos 				     + sizeof (struct ctf_archive));
    562      1.1  christos 
    563      1.1  christos   search_nametbl = (const char *) arc + le64toh (arc->ctfa_names);
    564  1.1.1.2  christos   modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts),
    565      1.1  christos 		      sizeof (struct ctf_archive_modent),
    566      1.1  christos 		      search_modent_by_name, (void *) search_nametbl);
    567      1.1  christos 
    568      1.1  christos   /* This is actually a common case and normal operation: no error
    569      1.1  christos      debug output.  */
    570      1.1  christos   if (modent == NULL)
    571      1.1  christos     {
    572      1.1  christos       if (errp)
    573      1.1  christos 	*errp = ECTF_ARNNAME;
    574      1.1  christos       return NULL;
    575      1.1  christos     }
    576      1.1  christos 
    577  1.1.1.2  christos   return ctf_dict_open_by_offset (arc, symsect, strsect,
    578  1.1.1.2  christos 				  le64toh (modent->ctf_offset),
    579  1.1.1.2  christos 				  little_endian, errp);
    580      1.1  christos }
    581      1.1  christos 
    582  1.1.1.2  christos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
    583      1.1  christos    non-NULL.  A name of NULL means to open the default file.
    584      1.1  christos 
    585      1.1  christos    Use the specified string and symbol table sections.
    586      1.1  christos 
    587      1.1  christos    Public entry point.  */
    588  1.1.1.2  christos ctf_dict_t *
    589  1.1.1.2  christos ctf_dict_open_sections (const ctf_archive_t *arc,
    590  1.1.1.2  christos 			const ctf_sect_t *symsect,
    591  1.1.1.2  christos 			const ctf_sect_t *strsect,
    592  1.1.1.2  christos 			const char *name,
    593  1.1.1.2  christos 			int *errp)
    594      1.1  christos {
    595  1.1.1.5  christos   if (errp)
    596  1.1.1.5  christos     *errp = 0;
    597  1.1.1.5  christos 
    598      1.1  christos   if (arc->ctfi_is_archive)
    599      1.1  christos     {
    600  1.1.1.2  christos       ctf_dict_t *ret;
    601  1.1.1.2  christos       ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect,
    602  1.1.1.2  christos 				    name, arc->ctfi_symsect_little_endian,
    603  1.1.1.2  christos 				    errp);
    604      1.1  christos       if (ret)
    605  1.1.1.2  christos 	{
    606  1.1.1.2  christos 	  ret->ctf_archive = (ctf_archive_t *) arc;
    607  1.1.1.3  christos 	  if (ctf_arc_import_parent (arc, ret, errp) < 0)
    608  1.1.1.3  christos 	    {
    609  1.1.1.3  christos 	      ctf_dict_close (ret);
    610  1.1.1.3  christos 	      return NULL;
    611  1.1.1.3  christos 	    }
    612  1.1.1.2  christos 	}
    613      1.1  christos       return ret;
    614      1.1  christos     }
    615      1.1  christos 
    616      1.1  christos   if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
    617      1.1  christos     {
    618      1.1  christos       if (errp)
    619      1.1  christos 	*errp = ECTF_ARNNAME;
    620      1.1  christos       return NULL;
    621      1.1  christos     }
    622  1.1.1.2  christos   arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc;
    623      1.1  christos 
    624  1.1.1.2  christos   /* Bump the refcount so that the user can ctf_dict_close() it.  */
    625  1.1.1.2  christos   arc->ctfi_dict->ctf_refcnt++;
    626  1.1.1.2  christos   return arc->ctfi_dict;
    627      1.1  christos }
    628      1.1  christos 
    629  1.1.1.2  christos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
    630      1.1  christos    non-NULL.  A name of NULL means to open the default file.
    631      1.1  christos 
    632      1.1  christos    Public entry point.  */
    633  1.1.1.2  christos ctf_dict_t *
    634  1.1.1.2  christos ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp)
    635      1.1  christos {
    636      1.1  christos   const ctf_sect_t *symsect = &arc->ctfi_symsect;
    637      1.1  christos   const ctf_sect_t *strsect = &arc->ctfi_strsect;
    638      1.1  christos 
    639      1.1  christos   if (symsect->cts_name == NULL)
    640      1.1  christos     symsect = NULL;
    641      1.1  christos   if (strsect->cts_name == NULL)
    642      1.1  christos     strsect = NULL;
    643      1.1  christos 
    644  1.1.1.2  christos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
    645  1.1.1.2  christos }
    646  1.1.1.2  christos 
    647  1.1.1.2  christos static void
    648  1.1.1.2  christos ctf_cached_dict_close (void *fp)
    649  1.1.1.2  christos {
    650  1.1.1.2  christos   ctf_dict_close ((ctf_dict_t *) fp);
    651      1.1  christos }
    652      1.1  christos 
    653  1.1.1.2  christos /* Return the ctf_dict_t with the given name and cache it in the archive's
    654  1.1.1.2  christos    ctfi_dicts.  If this is the first cached dict, designate it the
    655  1.1.1.2  christos    crossdict_cache.  */
    656  1.1.1.2  christos static ctf_dict_t *
    657  1.1.1.2  christos ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
    658  1.1.1.2  christos {
    659  1.1.1.2  christos   ctf_dict_t *fp;
    660  1.1.1.2  christos   char *dupname;
    661  1.1.1.2  christos 
    662  1.1.1.2  christos   /* Just return from the cache if possible.  */
    663  1.1.1.2  christos   if (arc->ctfi_dicts
    664  1.1.1.2  christos       && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL))
    665  1.1.1.2  christos     {
    666  1.1.1.2  christos       fp->ctf_refcnt++;
    667  1.1.1.2  christos       return fp;
    668  1.1.1.2  christos     }
    669  1.1.1.2  christos 
    670  1.1.1.2  christos   /* Not yet cached: open it.  */
    671  1.1.1.2  christos   fp = ctf_dict_open (arc, name, errp);
    672  1.1.1.2  christos   dupname = strdup (name);
    673  1.1.1.2  christos 
    674  1.1.1.2  christos   if (!fp || !dupname)
    675  1.1.1.2  christos     goto oom;
    676  1.1.1.2  christos 
    677  1.1.1.2  christos   if (arc->ctfi_dicts == NULL)
    678  1.1.1.2  christos     if ((arc->ctfi_dicts
    679  1.1.1.2  christos 	 = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
    680  1.1.1.2  christos 			       free, ctf_cached_dict_close)) == NULL)
    681  1.1.1.2  christos       goto oom;
    682  1.1.1.2  christos 
    683  1.1.1.2  christos   if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0)
    684  1.1.1.2  christos     goto oom;
    685  1.1.1.2  christos   fp->ctf_refcnt++;
    686  1.1.1.2  christos 
    687  1.1.1.2  christos   if (arc->ctfi_crossdict_cache == NULL)
    688  1.1.1.2  christos     arc->ctfi_crossdict_cache = fp;
    689  1.1.1.2  christos 
    690  1.1.1.2  christos   return fp;
    691  1.1.1.2  christos 
    692  1.1.1.2  christos  oom:
    693  1.1.1.2  christos   ctf_dict_close (fp);
    694  1.1.1.2  christos   free (dupname);
    695  1.1.1.2  christos   if (errp)
    696  1.1.1.2  christos     *errp = ENOMEM;
    697  1.1.1.2  christos   return NULL;
    698  1.1.1.2  christos }
    699  1.1.1.2  christos 
    700  1.1.1.2  christos /* Flush any caches the CTF archive may have open.  */
    701  1.1.1.2  christos void
    702  1.1.1.2  christos ctf_arc_flush_caches (ctf_archive_t *wrapper)
    703  1.1.1.2  christos {
    704  1.1.1.2  christos   free (wrapper->ctfi_symdicts);
    705  1.1.1.3  christos   ctf_dynhash_destroy (wrapper->ctfi_symnamedicts);
    706  1.1.1.2  christos   ctf_dynhash_destroy (wrapper->ctfi_dicts);
    707  1.1.1.2  christos   wrapper->ctfi_symdicts = NULL;
    708  1.1.1.2  christos   wrapper->ctfi_symnamedicts = NULL;
    709  1.1.1.2  christos   wrapper->ctfi_dicts = NULL;
    710  1.1.1.2  christos   wrapper->ctfi_crossdict_cache = NULL;
    711  1.1.1.2  christos }
    712  1.1.1.2  christos 
    713  1.1.1.2  christos /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if
    714      1.1  christos    none, setting 'err' if non-NULL.  */
    715  1.1.1.2  christos static ctf_dict_t *
    716  1.1.1.2  christos ctf_dict_open_by_offset (const struct ctf_archive *arc,
    717  1.1.1.2  christos 			 const ctf_sect_t *symsect,
    718  1.1.1.2  christos 			 const ctf_sect_t *strsect, size_t offset,
    719  1.1.1.2  christos 			 int little_endian, int *errp)
    720      1.1  christos {
    721      1.1  christos   ctf_sect_t ctfsect;
    722  1.1.1.2  christos   ctf_dict_t *fp;
    723      1.1  christos 
    724  1.1.1.2  christos   ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset);
    725      1.1  christos 
    726      1.1  christos   memset (&ctfsect, 0, sizeof (ctf_sect_t));
    727      1.1  christos 
    728      1.1  christos   offset += le64toh (arc->ctfa_ctfs);
    729      1.1  christos 
    730      1.1  christos   ctfsect.cts_name = _CTF_SECTION;
    731      1.1  christos   ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
    732      1.1  christos   ctfsect.cts_entsize = 1;
    733      1.1  christos   ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
    734      1.1  christos   fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
    735      1.1  christos   if (fp)
    736  1.1.1.2  christos     {
    737  1.1.1.2  christos       ctf_setmodel (fp, le64toh (arc->ctfa_model));
    738  1.1.1.2  christos       if (little_endian >= 0)
    739  1.1.1.2  christos 	ctf_symsect_endianness (fp, little_endian);
    740  1.1.1.2  christos     }
    741      1.1  christos   return fp;
    742      1.1  christos }
    743      1.1  christos 
    744  1.1.1.2  christos /* Backward compatibility.  */
    745  1.1.1.2  christos ctf_dict_t *
    746  1.1.1.2  christos ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name,
    747  1.1.1.2  christos 		      int *errp)
    748  1.1.1.2  christos {
    749  1.1.1.2  christos   return ctf_dict_open (arc, name, errp);
    750  1.1.1.2  christos }
    751  1.1.1.2  christos 
    752  1.1.1.2  christos ctf_dict_t *
    753  1.1.1.2  christos ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
    754  1.1.1.2  christos 			       const ctf_sect_t *symsect,
    755  1.1.1.2  christos 			       const ctf_sect_t *strsect,
    756  1.1.1.2  christos 			       const char *name,
    757  1.1.1.2  christos 			       int *errp)
    758  1.1.1.2  christos {
    759  1.1.1.2  christos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
    760  1.1.1.2  christos }
    761  1.1.1.2  christos 
    762  1.1.1.2  christos /* Import the parent into a ctf archive, if this is a child, the parent is not
    763  1.1.1.2  christos    already set, and a suitable archive member exists.  No error is raised if
    764  1.1.1.2  christos    this is not possible: this is just a best-effort helper operation to give
    765  1.1.1.2  christos    people useful dicts to start with.  */
    766  1.1.1.3  christos static int
    767  1.1.1.3  christos ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp)
    768  1.1.1.2  christos {
    769  1.1.1.2  christos   if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent)
    770  1.1.1.2  christos     {
    771  1.1.1.5  christos       int err = 0;
    772  1.1.1.2  christos       ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc,
    773  1.1.1.3  christos 						 fp->ctf_parname, &err);
    774  1.1.1.3  christos       if (errp)
    775  1.1.1.3  christos 	*errp = err;
    776  1.1.1.3  christos 
    777  1.1.1.2  christos       if (parent)
    778  1.1.1.2  christos 	{
    779  1.1.1.2  christos 	  ctf_import (fp, parent);
    780  1.1.1.2  christos 	  ctf_dict_close (parent);
    781  1.1.1.2  christos 	}
    782  1.1.1.3  christos       else if (err != ECTF_ARNNAME)
    783  1.1.1.3  christos 	return -1;				/* errno is set for us.  */
    784  1.1.1.2  christos     }
    785  1.1.1.3  christos   return 0;
    786  1.1.1.2  christos }
    787  1.1.1.2  christos 
    788      1.1  christos /* Return the number of members in an archive.  */
    789      1.1  christos size_t
    790      1.1  christos ctf_archive_count (const ctf_archive_t *wrapper)
    791      1.1  christos {
    792      1.1  christos   if (!wrapper->ctfi_is_archive)
    793      1.1  christos     return 1;
    794      1.1  christos 
    795  1.1.1.4  christos   return le64toh (wrapper->ctfi_archive->ctfa_ndicts);
    796  1.1.1.2  christos }
    797  1.1.1.2  christos 
    798  1.1.1.2  christos /* Look up a symbol in an archive by name or index (if the name is set, a lookup
    799  1.1.1.2  christos    by name is done).  Return the dict in the archive that the symbol is found
    800  1.1.1.2  christos    in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't
    801  1.1.1.2  christos    have to look it up yourself).  The dict is cached, so repeated lookups are
    802  1.1.1.2  christos    nearly free.
    803  1.1.1.2  christos 
    804  1.1.1.2  christos    As usual, you should ctf_dict_close() the returned dict once you are done
    805  1.1.1.2  christos    with it.
    806  1.1.1.2  christos 
    807  1.1.1.2  christos    Returns NULL on error, and an error in errp (if set).  */
    808  1.1.1.2  christos 
    809  1.1.1.2  christos static ctf_dict_t *
    810  1.1.1.2  christos ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
    811  1.1.1.2  christos 			    const char *symname, ctf_id_t *typep, int *errp)
    812  1.1.1.2  christos {
    813  1.1.1.2  christos   ctf_dict_t *fp;
    814  1.1.1.2  christos   void *fpkey;
    815  1.1.1.2  christos   ctf_id_t type;
    816  1.1.1.2  christos 
    817  1.1.1.2  christos   /* The usual non-archive-transparent-wrapper special case.  */
    818  1.1.1.2  christos   if (!wrapper->ctfi_is_archive)
    819  1.1.1.2  christos     {
    820  1.1.1.2  christos       if (!symname)
    821  1.1.1.2  christos 	{
    822  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
    823  1.1.1.2  christos 	    {
    824  1.1.1.2  christos 	      if (errp)
    825  1.1.1.2  christos 		*errp = ctf_errno (wrapper->ctfi_dict);
    826  1.1.1.2  christos 	      return NULL;
    827  1.1.1.2  christos 	    }
    828  1.1.1.2  christos 	}
    829  1.1.1.2  christos       else
    830  1.1.1.2  christos 	{
    831  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict,
    832  1.1.1.2  christos 						 symname)) == CTF_ERR)
    833  1.1.1.2  christos 	    {
    834  1.1.1.2  christos 	      if (errp)
    835  1.1.1.2  christos 		*errp = ctf_errno (wrapper->ctfi_dict);
    836  1.1.1.2  christos 	      return NULL;
    837  1.1.1.2  christos 	    }
    838  1.1.1.2  christos 	}
    839  1.1.1.2  christos       if (typep)
    840  1.1.1.2  christos 	*typep = type;
    841  1.1.1.2  christos       wrapper->ctfi_dict->ctf_refcnt++;
    842  1.1.1.2  christos       return wrapper->ctfi_dict;
    843  1.1.1.2  christos     }
    844  1.1.1.2  christos 
    845  1.1.1.2  christos   if (wrapper->ctfi_symsect.cts_name == NULL
    846  1.1.1.2  christos       || wrapper->ctfi_symsect.cts_data == NULL
    847  1.1.1.2  christos       || wrapper->ctfi_symsect.cts_size == 0
    848  1.1.1.2  christos       || wrapper->ctfi_symsect.cts_entsize == 0)
    849  1.1.1.2  christos     {
    850  1.1.1.2  christos       if (errp)
    851  1.1.1.2  christos 	*errp = ECTF_NOSYMTAB;
    852  1.1.1.2  christos       return NULL;
    853  1.1.1.2  christos     }
    854  1.1.1.2  christos 
    855  1.1.1.2  christos   /* Make enough space for all possible symbol indexes, if not already done.  We
    856  1.1.1.2  christos      cache the originating dictionary of all symbols.  The dict links are weak,
    857  1.1.1.2  christos      to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped.
    858  1.1.1.2  christos      We also cache similar mappings for symbol names: these are ordinary
    859  1.1.1.2  christos      dynhashes, with weak links to dicts.  */
    860  1.1.1.2  christos 
    861  1.1.1.2  christos   if (!wrapper->ctfi_symdicts)
    862  1.1.1.2  christos     {
    863  1.1.1.2  christos       if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
    864  1.1.1.2  christos 					    / wrapper->ctfi_symsect.cts_entsize,
    865  1.1.1.2  christos 					    sizeof (ctf_dict_t *))) == NULL)
    866  1.1.1.2  christos 	{
    867  1.1.1.2  christos 	  if (errp)
    868  1.1.1.2  christos 	    *errp = ENOMEM;
    869  1.1.1.2  christos 	  return NULL;
    870  1.1.1.2  christos 	}
    871  1.1.1.2  christos     }
    872  1.1.1.2  christos   if (!wrapper->ctfi_symnamedicts)
    873  1.1.1.2  christos     {
    874  1.1.1.2  christos       if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
    875  1.1.1.2  christos 							    ctf_hash_eq_string,
    876  1.1.1.2  christos 							    free, NULL)) == NULL)
    877  1.1.1.2  christos 	{
    878  1.1.1.2  christos 	  if (errp)
    879  1.1.1.2  christos 	    *errp = ENOMEM;
    880  1.1.1.2  christos 	  return NULL;
    881  1.1.1.2  christos 	}
    882  1.1.1.2  christos     }
    883  1.1.1.2  christos 
    884  1.1.1.2  christos   /* Perhaps the dict in which we found a previous lookup is cached.  If it's
    885  1.1.1.2  christos      supposed to be cached but we don't find it, pretend it was always not
    886  1.1.1.2  christos      found: this should never happen, but shouldn't be allowed to cause trouble
    887  1.1.1.2  christos      if it does.  */
    888  1.1.1.2  christos 
    889  1.1.1.2  christos   if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts,
    890  1.1.1.2  christos 					 symname, NULL, &fpkey))
    891  1.1.1.2  christos       || (!symname && wrapper->ctfi_symdicts[symidx] != NULL))
    892  1.1.1.2  christos     {
    893  1.1.1.2  christos       if (symname)
    894  1.1.1.2  christos 	fp = (ctf_dict_t *) fpkey;
    895  1.1.1.2  christos       else
    896  1.1.1.2  christos 	fp = wrapper->ctfi_symdicts[symidx];
    897  1.1.1.2  christos 
    898  1.1.1.2  christos       if (fp == &enosym)
    899  1.1.1.2  christos 	goto no_sym;
    900  1.1.1.2  christos 
    901  1.1.1.2  christos       if (symname)
    902  1.1.1.2  christos 	{
    903  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR)
    904  1.1.1.2  christos 	    goto cache_no_sym;
    905  1.1.1.2  christos 	}
    906  1.1.1.2  christos       else
    907  1.1.1.2  christos 	{
    908  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
    909  1.1.1.2  christos 	    goto cache_no_sym;
    910  1.1.1.2  christos 	}
    911  1.1.1.2  christos 
    912  1.1.1.2  christos       if (typep)
    913  1.1.1.2  christos 	*typep = type;
    914  1.1.1.2  christos       fp->ctf_refcnt++;
    915  1.1.1.2  christos       return fp;
    916  1.1.1.2  christos     }
    917  1.1.1.2  christos 
    918  1.1.1.2  christos   /* Not cached: find it and cache it.  We must track open errors ourselves even
    919  1.1.1.2  christos      if our caller doesn't, to be able to distinguish no-error end-of-iteration
    920  1.1.1.2  christos      from open errors.  */
    921  1.1.1.2  christos 
    922  1.1.1.2  christos   int local_err;
    923  1.1.1.2  christos   int *local_errp;
    924  1.1.1.2  christos   ctf_next_t *i = NULL;
    925  1.1.1.2  christos   const char *name;
    926  1.1.1.2  christos 
    927  1.1.1.2  christos   if (errp)
    928  1.1.1.2  christos     local_errp = errp;
    929  1.1.1.2  christos   else
    930  1.1.1.2  christos     local_errp = &local_err;
    931  1.1.1.2  christos 
    932  1.1.1.2  christos   while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL)
    933  1.1.1.2  christos     {
    934  1.1.1.2  christos       if (!symname)
    935  1.1.1.2  christos 	{
    936  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
    937  1.1.1.2  christos 	    wrapper->ctfi_symdicts[symidx] = fp;
    938  1.1.1.2  christos 	}
    939  1.1.1.2  christos       else
    940  1.1.1.2  christos 	{
    941  1.1.1.2  christos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR)
    942  1.1.1.2  christos 	    {
    943  1.1.1.2  christos 	      char *tmp;
    944  1.1.1.2  christos 	      /* No error checking, as above.  */
    945  1.1.1.2  christos 	      if ((tmp = strdup (symname)) != NULL)
    946  1.1.1.2  christos 		ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp);
    947  1.1.1.2  christos 	    }
    948  1.1.1.2  christos 	}
    949  1.1.1.2  christos 
    950  1.1.1.2  christos       if (type != CTF_ERR)
    951  1.1.1.2  christos 	{
    952  1.1.1.2  christos 	  if (typep)
    953  1.1.1.2  christos 	    *typep = type;
    954  1.1.1.2  christos 	  ctf_next_destroy (i);
    955  1.1.1.2  christos 	  return fp;
    956  1.1.1.2  christos 	}
    957  1.1.1.2  christos       if (ctf_errno (fp) != ECTF_NOTYPEDAT)
    958  1.1.1.2  christos 	{
    959  1.1.1.2  christos 	  if (errp)
    960  1.1.1.2  christos 	    *errp = ctf_errno (fp);
    961  1.1.1.4  christos 	  ctf_dict_close (fp);
    962  1.1.1.2  christos 	  ctf_next_destroy (i);
    963  1.1.1.2  christos 	  return NULL;				/* errno is set for us.  */
    964  1.1.1.2  christos 	}
    965  1.1.1.2  christos       ctf_dict_close (fp);
    966  1.1.1.2  christos     }
    967  1.1.1.2  christos   if (*local_errp != ECTF_NEXT_END)
    968  1.1.1.2  christos     {
    969  1.1.1.2  christos       ctf_next_destroy (i);
    970  1.1.1.2  christos       return NULL;
    971  1.1.1.2  christos     }
    972  1.1.1.2  christos 
    973  1.1.1.2  christos   /* Don't leak end-of-iteration to the caller.  */
    974  1.1.1.2  christos   *local_errp = 0;
    975  1.1.1.2  christos 
    976  1.1.1.2  christos  cache_no_sym:
    977  1.1.1.2  christos   if (!symname)
    978  1.1.1.2  christos     wrapper->ctfi_symdicts[symidx] = &enosym;
    979  1.1.1.2  christos   else
    980  1.1.1.2  christos     {
    981  1.1.1.2  christos       char *tmp;
    982  1.1.1.2  christos 
    983  1.1.1.2  christos       /* No error checking: if caching fails, there is only a slight performance
    984  1.1.1.2  christos 	 impact.  */
    985  1.1.1.2  christos       if ((tmp = strdup (symname)) != NULL)
    986  1.1.1.2  christos 	if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0)
    987  1.1.1.2  christos 	  free (tmp);
    988  1.1.1.2  christos     }
    989  1.1.1.2  christos 
    990  1.1.1.2  christos  no_sym:
    991  1.1.1.2  christos   if (errp)
    992  1.1.1.2  christos     *errp = ECTF_NOTYPEDAT;
    993  1.1.1.2  christos   if (typep)
    994  1.1.1.2  christos     *typep = CTF_ERR;
    995  1.1.1.2  christos   return NULL;
    996  1.1.1.2  christos }
    997  1.1.1.2  christos 
    998  1.1.1.2  christos /* The public API for looking up a symbol by index.  */
    999  1.1.1.2  christos ctf_dict_t *
   1000  1.1.1.2  christos ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
   1001  1.1.1.2  christos 		       ctf_id_t *typep, int *errp)
   1002  1.1.1.2  christos {
   1003  1.1.1.2  christos   return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp);
   1004  1.1.1.2  christos }
   1005  1.1.1.2  christos 
   1006  1.1.1.2  christos /* The public API for looking up a symbol by name. */
   1007  1.1.1.2  christos 
   1008  1.1.1.2  christos ctf_dict_t *
   1009  1.1.1.2  christos ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
   1010  1.1.1.2  christos 			    ctf_id_t *typep, int *errp)
   1011  1.1.1.2  christos {
   1012  1.1.1.2  christos   return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
   1013      1.1  christos }
   1014      1.1  christos 
   1015  1.1.1.4  christos /* Return all enumeration constants with a given NAME across all dicts in an
   1016  1.1.1.4  christos    archive, similar to ctf_lookup_enumerator_next.  The DICT is cached, so
   1017  1.1.1.4  christos    opening costs are paid only once, but (unlike ctf_arc_lookup_symbol*
   1018  1.1.1.4  christos    above) the results of the iterations are not cached.  dict and errp are
   1019  1.1.1.4  christos    not optional.  */
   1020  1.1.1.4  christos 
   1021  1.1.1.4  christos ctf_id_t
   1022  1.1.1.4  christos ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
   1023  1.1.1.4  christos 				ctf_next_t **it, int64_t *enum_value,
   1024  1.1.1.4  christos 				ctf_dict_t **dict, int *errp)
   1025  1.1.1.4  christos {
   1026  1.1.1.4  christos   ctf_next_t *i = *it;
   1027  1.1.1.4  christos   ctf_id_t type;
   1028  1.1.1.4  christos   int opened_this_time = 0;
   1029  1.1.1.4  christos   int err;
   1030  1.1.1.4  christos 
   1031  1.1.1.4  christos   /* We have two nested iterators in here: ctn_next tracks archives, while
   1032  1.1.1.4  christos      within it ctn_next_inner tracks enumerators within an archive.  We
   1033  1.1.1.4  christos      keep track of the dict by simply reusing the passed-in arg: if it's
   1034  1.1.1.4  christos      changed by the caller, the caller will get an ECTF_WRONGFP error,
   1035  1.1.1.4  christos      so this is quite safe and means we don't have to track the arc and fp
   1036  1.1.1.4  christos      simultaneously in the ctf_next_t.  */
   1037  1.1.1.4  christos 
   1038  1.1.1.4  christos   if (!i)
   1039  1.1.1.4  christos     {
   1040  1.1.1.4  christos       if ((i = ctf_next_create ()) == NULL)
   1041  1.1.1.4  christos 	{
   1042  1.1.1.4  christos 	  err = ENOMEM;
   1043  1.1.1.4  christos 	  goto err;
   1044  1.1.1.4  christos 	}
   1045  1.1.1.4  christos       i->ctn_iter_fun = (void (*) (void)) ctf_arc_lookup_enumerator_next;
   1046  1.1.1.4  christos       i->cu.ctn_arc = arc;
   1047  1.1.1.4  christos       *it = i;
   1048  1.1.1.4  christos     }
   1049  1.1.1.4  christos 
   1050  1.1.1.4  christos   if ((void (*) (void)) ctf_arc_lookup_enumerator_next != i->ctn_iter_fun)
   1051  1.1.1.4  christos     {
   1052  1.1.1.4  christos       err = ECTF_NEXT_WRONGFUN;
   1053  1.1.1.4  christos       goto err;
   1054  1.1.1.4  christos     }
   1055  1.1.1.4  christos 
   1056  1.1.1.4  christos   if (arc != i->cu.ctn_arc)
   1057  1.1.1.4  christos     {
   1058  1.1.1.4  christos       err = ECTF_NEXT_WRONGFP;
   1059  1.1.1.4  christos       goto err;
   1060  1.1.1.4  christos     }
   1061  1.1.1.4  christos 
   1062  1.1.1.4  christos   /* Prevent any earlier end-of-iteration on this dict from confusing the
   1063  1.1.1.4  christos      test below.  */
   1064  1.1.1.4  christos   if (i->ctn_next != NULL)
   1065  1.1.1.4  christos     ctf_set_errno (*dict, 0);
   1066  1.1.1.4  christos 
   1067  1.1.1.4  christos   do
   1068  1.1.1.4  christos     {
   1069  1.1.1.4  christos       /* At end of one dict, or not started any iterations yet?
   1070  1.1.1.4  christos 	 Traverse to next dict.  If we never returned this dict to the
   1071  1.1.1.4  christos 	 caller, close it ourselves: the caller will never see it and cannot
   1072  1.1.1.4  christos 	 do so.  */
   1073  1.1.1.4  christos 
   1074  1.1.1.4  christos       if (i->ctn_next == NULL || ctf_errno (*dict) == ECTF_NEXT_END)
   1075  1.1.1.4  christos 	{
   1076  1.1.1.4  christos 	  if (opened_this_time)
   1077  1.1.1.4  christos 	    {
   1078  1.1.1.4  christos 	      ctf_dict_close (*dict);
   1079  1.1.1.4  christos 	      *dict = NULL;
   1080  1.1.1.4  christos 	      opened_this_time = 0;
   1081  1.1.1.4  christos 	    }
   1082  1.1.1.4  christos 
   1083  1.1.1.4  christos 	  *dict = ctf_archive_next (arc, &i->ctn_next, NULL, 0, &err);
   1084  1.1.1.4  christos 	  if (!*dict)
   1085  1.1.1.4  christos 	    goto err;
   1086  1.1.1.4  christos 	  opened_this_time = 1;
   1087  1.1.1.4  christos 	}
   1088  1.1.1.4  christos 
   1089  1.1.1.4  christos       type = ctf_lookup_enumerator_next (*dict, name, &i->ctn_next_inner,
   1090  1.1.1.4  christos 					 enum_value);
   1091  1.1.1.4  christos     }
   1092  1.1.1.4  christos   while (type == CTF_ERR && ctf_errno (*dict) == ECTF_NEXT_END);
   1093  1.1.1.4  christos 
   1094  1.1.1.4  christos   if (type == CTF_ERR)
   1095  1.1.1.4  christos     {
   1096  1.1.1.4  christos       err = ctf_errno (*dict);
   1097  1.1.1.4  christos       goto err;
   1098  1.1.1.4  christos     }
   1099  1.1.1.4  christos 
   1100  1.1.1.4  christos   /* If this dict is being reused from the previous iteration, bump its
   1101  1.1.1.4  christos      refcnt: the caller is going to close it and has no idea that we didn't
   1102  1.1.1.4  christos      open it this time round.  */
   1103  1.1.1.4  christos   if (!opened_this_time)
   1104  1.1.1.4  christos     ctf_ref (*dict);
   1105  1.1.1.4  christos 
   1106  1.1.1.4  christos   return type;
   1107  1.1.1.4  christos 
   1108  1.1.1.4  christos  err:						/* Also ECTF_NEXT_END. */
   1109  1.1.1.4  christos   if (opened_this_time)
   1110  1.1.1.4  christos     {
   1111  1.1.1.4  christos       ctf_dict_close (*dict);
   1112  1.1.1.4  christos       *dict = NULL;
   1113  1.1.1.4  christos     }
   1114  1.1.1.4  christos 
   1115  1.1.1.4  christos   ctf_next_destroy (i);
   1116  1.1.1.4  christos   *it = NULL;
   1117  1.1.1.4  christos   if (errp)
   1118  1.1.1.4  christos     *errp = err;
   1119  1.1.1.4  christos   return CTF_ERR;
   1120  1.1.1.4  christos }
   1121  1.1.1.4  christos 
   1122      1.1  christos /* Raw iteration over all CTF files in an archive.  We pass the raw data for all
   1123      1.1  christos    CTF files in turn to the specified callback function.  */
   1124      1.1  christos static int
   1125      1.1  christos ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
   1126      1.1  christos 			       ctf_archive_raw_member_f *func, void *data)
   1127      1.1  christos {
   1128      1.1  christos   int rc;
   1129      1.1  christos   size_t i;
   1130      1.1  christos   struct ctf_archive_modent *modent;
   1131      1.1  christos   const char *nametbl;
   1132      1.1  christos 
   1133      1.1  christos   modent = (ctf_archive_modent_t *) ((char *) arc
   1134      1.1  christos 				     + sizeof (struct ctf_archive));
   1135      1.1  christos   nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
   1136      1.1  christos 
   1137  1.1.1.2  christos   for (i = 0; i < le64toh (arc->ctfa_ndicts); i++)
   1138      1.1  christos     {
   1139      1.1  christos       const char *name;
   1140      1.1  christos       char *fp;
   1141      1.1  christos 
   1142      1.1  christos       name = &nametbl[le64toh (modent[i].name_offset)];
   1143      1.1  christos       fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
   1144      1.1  christos 	    + le64toh (modent[i].ctf_offset));
   1145      1.1  christos 
   1146      1.1  christos       if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
   1147      1.1  christos 		      le64toh (*((uint64_t *) fp)), data)) != 0)
   1148      1.1  christos 	return rc;
   1149      1.1  christos     }
   1150      1.1  christos   return 0;
   1151      1.1  christos }
   1152      1.1  christos 
   1153      1.1  christos /* Raw iteration over all CTF files in an archive: public entry point.
   1154      1.1  christos 
   1155      1.1  christos    Returns -EINVAL if not supported for this sort of archive.  */
   1156      1.1  christos int
   1157      1.1  christos ctf_archive_raw_iter (const ctf_archive_t *arc,
   1158      1.1  christos 		      ctf_archive_raw_member_f * func, void *data)
   1159      1.1  christos {
   1160      1.1  christos   if (arc->ctfi_is_archive)
   1161      1.1  christos     return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
   1162      1.1  christos 
   1163      1.1  christos   return -EINVAL;			 /* Not supported. */
   1164      1.1  christos }
   1165      1.1  christos 
   1166  1.1.1.2  christos /* Iterate over all CTF files in an archive: public entry point.  We pass all
   1167  1.1.1.2  christos    CTF files in turn to the specified callback function.  */
   1168  1.1.1.2  christos int
   1169  1.1.1.2  christos ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
   1170  1.1.1.2  christos 		  void *data)
   1171      1.1  christos {
   1172  1.1.1.2  christos   ctf_next_t *i = NULL;
   1173  1.1.1.2  christos   ctf_dict_t *fp;
   1174  1.1.1.2  christos   const char *name;
   1175  1.1.1.3  christos   int err = 0;
   1176      1.1  christos 
   1177  1.1.1.2  christos   while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL)
   1178      1.1  christos     {
   1179  1.1.1.2  christos       int rc;
   1180      1.1  christos 
   1181  1.1.1.2  christos       if ((rc = func (fp, name, data)) != 0)
   1182      1.1  christos 	{
   1183  1.1.1.2  christos 	  ctf_dict_close (fp);
   1184  1.1.1.2  christos 	  ctf_next_destroy (i);
   1185      1.1  christos 	  return rc;
   1186      1.1  christos 	}
   1187  1.1.1.2  christos       ctf_dict_close (fp);
   1188      1.1  christos     }
   1189  1.1.1.3  christos   if (err != ECTF_NEXT_END && err != 0)
   1190  1.1.1.3  christos     {
   1191  1.1.1.3  christos       ctf_next_destroy (i);
   1192  1.1.1.3  christos       return -1;
   1193  1.1.1.3  christos     }
   1194      1.1  christos   return 0;
   1195      1.1  christos }
   1196      1.1  christos 
   1197      1.1  christos /* Iterate over all CTF files in an archive, returning each dict in turn as a
   1198  1.1.1.2  christos    ctf_dict_t, and NULL on error or end of iteration.  It is the caller's
   1199  1.1.1.2  christos    responsibility to close it.  Parent dicts may be skipped.
   1200  1.1.1.2  christos 
   1201  1.1.1.2  christos    The archive member is cached for rapid return on future calls.
   1202      1.1  christos 
   1203      1.1  christos    We identify parents by name rather than by flag value: for now, with the
   1204      1.1  christos    linker only emitting parents named _CTF_SECTION, this works well enough.  */
   1205      1.1  christos 
   1206  1.1.1.2  christos ctf_dict_t *
   1207      1.1  christos ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name,
   1208      1.1  christos 		  int skip_parent, int *errp)
   1209      1.1  christos {
   1210  1.1.1.2  christos   ctf_dict_t *f;
   1211      1.1  christos   ctf_next_t *i = *it;
   1212      1.1  christos   struct ctf_archive *arc;
   1213      1.1  christos   struct ctf_archive_modent *modent;
   1214      1.1  christos   const char *nametbl;
   1215      1.1  christos   const char *name_;
   1216      1.1  christos 
   1217      1.1  christos   if (!i)
   1218      1.1  christos     {
   1219      1.1  christos       if ((i = ctf_next_create()) == NULL)
   1220      1.1  christos 	{
   1221      1.1  christos 	  if (errp)
   1222      1.1  christos 	    *errp = ENOMEM;
   1223      1.1  christos 	  return NULL;
   1224      1.1  christos 	}
   1225      1.1  christos       i->cu.ctn_arc = wrapper;
   1226      1.1  christos       i->ctn_iter_fun = (void (*) (void)) ctf_archive_next;
   1227      1.1  christos       *it = i;
   1228      1.1  christos     }
   1229      1.1  christos 
   1230      1.1  christos   if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun)
   1231      1.1  christos     {
   1232      1.1  christos       if (errp)
   1233      1.1  christos 	*errp = ECTF_NEXT_WRONGFUN;
   1234      1.1  christos       return NULL;
   1235      1.1  christos     }
   1236      1.1  christos 
   1237      1.1  christos   if (wrapper != i->cu.ctn_arc)
   1238      1.1  christos     {
   1239      1.1  christos       if (errp)
   1240      1.1  christos 	*errp = ECTF_NEXT_WRONGFP;
   1241      1.1  christos       return NULL;
   1242      1.1  christos     }
   1243      1.1  christos 
   1244  1.1.1.2  christos   /* Iteration is made a bit more complex by the need to handle ctf_dict_t's
   1245      1.1  christos      transparently wrapped in a single-member archive.  These are parents: if
   1246      1.1  christos      skip_parent is on, they are skipped and the iterator terminates
   1247      1.1  christos      immediately.  */
   1248      1.1  christos 
   1249      1.1  christos   if (!wrapper->ctfi_is_archive && i->ctn_n == 0)
   1250      1.1  christos     {
   1251      1.1  christos       i->ctn_n++;
   1252      1.1  christos       if (!skip_parent)
   1253      1.1  christos 	{
   1254  1.1.1.2  christos 	  wrapper->ctfi_dict->ctf_refcnt++;
   1255  1.1.1.2  christos 	  if (name)
   1256  1.1.1.2  christos 	    *name = _CTF_SECTION;
   1257  1.1.1.2  christos 	  return wrapper->ctfi_dict;
   1258      1.1  christos 	}
   1259      1.1  christos     }
   1260      1.1  christos 
   1261      1.1  christos   arc = wrapper->ctfi_archive;
   1262      1.1  christos 
   1263      1.1  christos   /* The loop keeps going when skip_parent is on as long as the member we find
   1264      1.1  christos      is the parent (i.e. at most two iterations, but possibly an early return if
   1265      1.1  christos      *all* we have is a parent).  */
   1266      1.1  christos 
   1267      1.1  christos   do
   1268      1.1  christos     {
   1269  1.1.1.2  christos       if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts)))
   1270      1.1  christos 	{
   1271      1.1  christos 	  ctf_next_destroy (i);
   1272      1.1  christos 	  *it = NULL;
   1273      1.1  christos 	  if (errp)
   1274      1.1  christos 	    *errp = ECTF_NEXT_END;
   1275      1.1  christos 	  return NULL;
   1276      1.1  christos 	}
   1277      1.1  christos 
   1278      1.1  christos       modent = (ctf_archive_modent_t *) ((char *) arc
   1279      1.1  christos 					 + sizeof (struct ctf_archive));
   1280      1.1  christos       nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
   1281      1.1  christos 
   1282      1.1  christos       name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
   1283      1.1  christos       i->ctn_n++;
   1284  1.1.1.2  christos     }
   1285  1.1.1.2  christos   while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
   1286      1.1  christos 
   1287      1.1  christos   if (name)
   1288      1.1  christos     *name = name_;
   1289      1.1  christos 
   1290  1.1.1.2  christos   f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp);
   1291      1.1  christos   return f;
   1292      1.1  christos }
   1293      1.1  christos 
   1294      1.1  christos #ifdef HAVE_MMAP
   1295      1.1  christos /* Map the header in.  Only used on new, empty files.  */
   1296      1.1  christos static void *arc_mmap_header (int fd, size_t headersz)
   1297      1.1  christos {
   1298      1.1  christos   void *hdr;
   1299      1.1  christos   if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
   1300      1.1  christos 		   0)) == MAP_FAILED)
   1301      1.1  christos     return NULL;
   1302      1.1  christos   return hdr;
   1303      1.1  christos }
   1304      1.1  christos 
   1305      1.1  christos /* mmap() the whole file, for reading only.  (Map it writably, but privately: we
   1306      1.1  christos    need to modify the region, but don't need anyone else to see the
   1307      1.1  christos    modifications.)  */
   1308      1.1  christos static void *arc_mmap_file (int fd, size_t size)
   1309      1.1  christos {
   1310      1.1  christos   void *arc;
   1311      1.1  christos   if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
   1312      1.1  christos 		   fd, 0)) == MAP_FAILED)
   1313      1.1  christos     return NULL;
   1314      1.1  christos   return arc;
   1315      1.1  christos }
   1316      1.1  christos 
   1317      1.1  christos /* Persist the header to disk.  */
   1318      1.1  christos static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
   1319      1.1  christos 			      size_t headersz, const char **errmsg)
   1320      1.1  christos {
   1321      1.1  christos     if (msync (header, headersz, MS_ASYNC) < 0)
   1322      1.1  christos     {
   1323      1.1  christos       if (errmsg)
   1324      1.1  christos 	*errmsg = N_("arc_mmap_writeout(): cannot sync after writing "
   1325      1.1  christos 		     "to %s: %s");
   1326      1.1  christos       return -1;
   1327      1.1  christos     }
   1328      1.1  christos     return 0;
   1329      1.1  christos }
   1330      1.1  christos 
   1331      1.1  christos /* Unmap the region.  */
   1332      1.1  christos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
   1333      1.1  christos {
   1334      1.1  christos   if (munmap (header, headersz) < 0)
   1335      1.1  christos     {
   1336      1.1  christos       if (errmsg)
   1337      1.1  christos 	*errmsg = N_("arc_mmap_munmap(): cannot unmap after writing "
   1338      1.1  christos 		     "to %s: %s");
   1339      1.1  christos       return -1;
   1340      1.1  christos     }
   1341      1.1  christos     return 0;
   1342      1.1  christos }
   1343      1.1  christos #else
   1344      1.1  christos /* Map the header in.  Only used on new, empty files.  */
   1345      1.1  christos static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz)
   1346      1.1  christos {
   1347      1.1  christos   void *hdr;
   1348      1.1  christos   if ((hdr = malloc (headersz)) == NULL)
   1349      1.1  christos     return NULL;
   1350      1.1  christos   return hdr;
   1351      1.1  christos }
   1352      1.1  christos 
   1353      1.1  christos /* Pull in the whole file, for reading only.  We assume the current file
   1354      1.1  christos    position is at the start of the file.  */
   1355      1.1  christos static void *arc_mmap_file (int fd, size_t size)
   1356      1.1  christos {
   1357      1.1  christos   char *data;
   1358      1.1  christos 
   1359      1.1  christos   if ((data = malloc (size)) == NULL)
   1360      1.1  christos     return NULL;
   1361      1.1  christos 
   1362      1.1  christos   if (ctf_pread (fd, data, size, 0) < 0)
   1363      1.1  christos     {
   1364      1.1  christos       free (data);
   1365      1.1  christos       return NULL;
   1366      1.1  christos     }
   1367      1.1  christos   return data;
   1368      1.1  christos }
   1369      1.1  christos 
   1370      1.1  christos /* Persist the header to disk.  */
   1371      1.1  christos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
   1372      1.1  christos 			      const char **errmsg)
   1373      1.1  christos {
   1374      1.1  christos   ssize_t len;
   1375      1.1  christos   char *data = (char *) header;
   1376      1.1  christos   ssize_t count = headersz;
   1377      1.1  christos 
   1378      1.1  christos   if ((lseek (fd, 0, SEEK_SET)) < 0)
   1379      1.1  christos     {
   1380      1.1  christos       if (errmsg)
   1381      1.1  christos 	*errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to "
   1382      1.1  christos 		     "%s: %s");
   1383      1.1  christos       return -1;
   1384      1.1  christos     }
   1385      1.1  christos 
   1386      1.1  christos   while (headersz > 0)
   1387      1.1  christos     {
   1388      1.1  christos       if ((len = write (fd, data, count)) < 0)
   1389      1.1  christos 	{
   1390      1.1  christos 	  if (errmsg)
   1391      1.1  christos 	    *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s");
   1392      1.1  christos 	  return len;
   1393      1.1  christos 	}
   1394      1.1  christos       if (len == EINTR)
   1395      1.1  christos 	continue;
   1396      1.1  christos 
   1397      1.1  christos       if (len == 0)				/* EOF.  */
   1398      1.1  christos 	break;
   1399      1.1  christos 
   1400      1.1  christos       count -= len;
   1401      1.1  christos       data += len;
   1402      1.1  christos     }
   1403      1.1  christos   return 0;
   1404      1.1  christos }
   1405      1.1  christos 
   1406      1.1  christos /* Unmap the region.  */
   1407      1.1  christos static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_,
   1408      1.1  christos 			   const char **errmsg _libctf_unused_)
   1409      1.1  christos {
   1410      1.1  christos   free (header);
   1411      1.1  christos   return 0;
   1412      1.1  christos }
   1413      1.1  christos #endif
   1414