xref: /netbsd-src/external/gpl3/gdb/dist/libctf/ctf-archive.c (revision 12989c96ee862c63521a9ead8c44629b7a2ba9b1)
18dffb485Schristos /* CTF archive files.
2*12989c96Schristos    Copyright (C) 2019-2024 Free Software Foundation, Inc.
38dffb485Schristos 
48dffb485Schristos    This file is part of libctf.
58dffb485Schristos 
68dffb485Schristos    libctf is free software; you can redistribute it and/or modify it under
78dffb485Schristos    the terms of the GNU General Public License as published by the Free
88dffb485Schristos    Software Foundation; either version 3, or (at your option) any later
98dffb485Schristos    version.
108dffb485Schristos 
118dffb485Schristos    This program is distributed in the hope that it will be useful, but
128dffb485Schristos    WITHOUT ANY WARRANTY; without even the implied warranty of
138dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
148dffb485Schristos    See the GNU General Public License for more details.
158dffb485Schristos 
168dffb485Schristos    You should have received a copy of the GNU General Public License
178dffb485Schristos    along with this program; see the file COPYING.  If not see
188dffb485Schristos    <http://www.gnu.org/licenses/>.  */
198dffb485Schristos 
208dffb485Schristos #include <ctf-impl.h>
218dffb485Schristos #include <sys/types.h>
228dffb485Schristos #include <sys/stat.h>
238dffb485Schristos #include <elf.h>
248dffb485Schristos #include "ctf-endian.h"
258dffb485Schristos #include <errno.h>
268dffb485Schristos #include <fcntl.h>
278dffb485Schristos #include <stdio.h>
288dffb485Schristos #include <string.h>
298dffb485Schristos #include <unistd.h>
308dffb485Schristos 
318dffb485Schristos #ifdef HAVE_MMAP
328dffb485Schristos #include <sys/mman.h>
338dffb485Schristos #endif
348dffb485Schristos 
354b169a6bSchristos static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold);
364b169a6bSchristos static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc,
378dffb485Schristos 					    const ctf_sect_t *symsect,
388dffb485Schristos 					    const ctf_sect_t *strsect,
394b169a6bSchristos 					    size_t offset, int little_endian,
404b169a6bSchristos 					    int *errp);
418dffb485Schristos static int sort_modent_by_name (const void *one, const void *two, void *n);
428dffb485Schristos static void *arc_mmap_header (int fd, size_t headersz);
438dffb485Schristos static void *arc_mmap_file (int fd, size_t size);
448dffb485Schristos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
458dffb485Schristos 			      const char **errmsg);
468dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
47*12989c96Schristos static int ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp,
48*12989c96Schristos 				  int *errp);
494b169a6bSchristos 
504b169a6bSchristos /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts
514b169a6bSchristos    and ctfi_symnamedicts.  Never initialized.  */
524b169a6bSchristos static ctf_dict_t enosym;
538dffb485Schristos 
548dffb485Schristos /* Write out a CTF archive to the start of the file referenced by the passed-in
554b169a6bSchristos    fd.  The entries in CTF_DICTS are referenced by name: the names are passed in
564b169a6bSchristos    the names array, which must have CTF_DICTS entries.
578dffb485Schristos 
588dffb485Schristos    Returns 0 on success, or an errno, or an ECTF_* value.  */
598dffb485Schristos int
604b169a6bSchristos ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
618dffb485Schristos 		  const char **names, size_t threshold)
628dffb485Schristos {
638dffb485Schristos   const char *errmsg;
648dffb485Schristos   struct ctf_archive *archdr;
658dffb485Schristos   size_t i;
668dffb485Schristos   char dummy = 0;
678dffb485Schristos   size_t headersz;
688dffb485Schristos   ssize_t namesz;
698dffb485Schristos   size_t ctf_startoffs;		/* Start of the section we are working over.  */
708dffb485Schristos   char *nametbl = NULL;		/* The name table.  */
718dffb485Schristos   char *np;
728dffb485Schristos   off_t nameoffs;
738dffb485Schristos   struct ctf_archive_modent *modent;
748dffb485Schristos 
758dffb485Schristos   ctf_dprintf ("Writing CTF archive with %lu files\n",
764b169a6bSchristos 	       (unsigned long) ctf_dict_cnt);
778dffb485Schristos 
788dffb485Schristos   /* Figure out the size of the mmap()ed header, including the
798dffb485Schristos      ctf_archive_modent array.  We assume that all of this needs no
808dffb485Schristos      padding: a likely assumption, given that it's all made up of
818dffb485Schristos      uint64_t's.  */
828dffb485Schristos   headersz = sizeof (struct ctf_archive)
834b169a6bSchristos     + (ctf_dict_cnt * sizeof (uint64_t) * 2);
848dffb485Schristos   ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
858dffb485Schristos 
868dffb485Schristos   /* From now on we work in two pieces: an mmap()ed region from zero up to the
878dffb485Schristos      headersz, and a region updated via write() starting after that, containing
888dffb485Schristos      all the tables.  Platforms that do not support mmap() just use write().  */
898dffb485Schristos   ctf_startoffs = headersz;
908dffb485Schristos   if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
918dffb485Schristos     {
928dffb485Schristos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
938dffb485Schristos       goto err;
948dffb485Schristos     }
958dffb485Schristos 
968dffb485Schristos   if (write (fd, &dummy, 1) < 0)
978dffb485Schristos     {
988dffb485Schristos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
998dffb485Schristos       goto err;
1008dffb485Schristos     }
1018dffb485Schristos 
1028dffb485Schristos   if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
1038dffb485Schristos     {
1048dffb485Schristos       errmsg = N_("ctf_arc_write(): cannot mmap");
1058dffb485Schristos       goto err;
1068dffb485Schristos     }
1078dffb485Schristos 
1088dffb485Schristos   /* Fill in everything we can, which is everything other than the name
1098dffb485Schristos      table offset.  */
1108dffb485Schristos   archdr->ctfa_magic = htole64 (CTFA_MAGIC);
1114b169a6bSchristos   archdr->ctfa_ndicts = htole64 (ctf_dict_cnt);
1128dffb485Schristos   archdr->ctfa_ctfs = htole64 (ctf_startoffs);
1138dffb485Schristos 
1148dffb485Schristos   /* We could validate that all CTF files have the same data model, but
1158dffb485Schristos      since any reasonable construction process will be building things of
1168dffb485Schristos      only one bitness anyway, this is pretty pointless, so just use the
1178dffb485Schristos      model of the first CTF file for all of them.  (It *is* valid to
1188dffb485Schristos      create an empty archive: the value of ctfa_model is irrelevant in
1198dffb485Schristos      this case, but we must be sure not to dereference uninitialized
1208dffb485Schristos      memory.)  */
1218dffb485Schristos 
1224b169a6bSchristos   if (ctf_dict_cnt > 0)
1234b169a6bSchristos     archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0]));
1248dffb485Schristos 
1258dffb485Schristos   /* Now write out the CTFs: ctf_archive_modent array via the mapping,
1268dffb485Schristos      ctfs via write().  The names themselves have not been written yet: we
1278dffb485Schristos      track them in a local strtab until the time is right, and sort the
1288dffb485Schristos      modents array after construction.
1298dffb485Schristos 
1308dffb485Schristos     The name table is not sorted.  */
1318dffb485Schristos 
1324b169a6bSchristos   for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++)
1338dffb485Schristos     namesz += strlen (names[i]) + 1;
1348dffb485Schristos 
1358dffb485Schristos   nametbl = malloc (namesz);
1368dffb485Schristos   if (nametbl == NULL)
1378dffb485Schristos     {
1388dffb485Schristos       errmsg = N_("ctf_arc_write(): error writing named CTF to archive");
1398dffb485Schristos       goto err_unmap;
1408dffb485Schristos     }
1418dffb485Schristos 
1428dffb485Schristos   for (i = 0, namesz = 0,
1438dffb485Schristos        modent = (ctf_archive_modent_t *) ((char *) archdr
1448dffb485Schristos 					  + sizeof (struct ctf_archive));
1454b169a6bSchristos        i < le64toh (archdr->ctfa_ndicts); i++)
1468dffb485Schristos     {
1478dffb485Schristos       off_t off;
1488dffb485Schristos 
1498dffb485Schristos       strcpy (&nametbl[namesz], names[i]);
1508dffb485Schristos 
1514b169a6bSchristos       off = arc_write_one_ctf (ctf_dicts[i], fd, threshold);
1528dffb485Schristos       if ((off < 0) && (off > -ECTF_BASE))
1538dffb485Schristos 	{
1548dffb485Schristos 	  errmsg = N_("ctf_arc_write(): cannot determine file "
1558dffb485Schristos 		      "position while writing to archive");
1568dffb485Schristos 	  goto err_free;
1578dffb485Schristos 	}
1588dffb485Schristos       if (off < 0)
1598dffb485Schristos 	{
1608dffb485Schristos 	  errmsg = N_("ctf_arc_write(): cannot write CTF file to archive");
1618dffb485Schristos 	  errno = off * -1;
1628dffb485Schristos 	  goto err_free;
1638dffb485Schristos 	}
1648dffb485Schristos 
1658dffb485Schristos       modent->name_offset = htole64 (namesz);
1668dffb485Schristos       modent->ctf_offset = htole64 (off - ctf_startoffs);
1678dffb485Schristos       namesz += strlen (names[i]) + 1;
1688dffb485Schristos       modent++;
1698dffb485Schristos     }
1708dffb485Schristos 
1718dffb485Schristos   ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
1728dffb485Schristos 					 + sizeof (struct ctf_archive)),
1734b169a6bSchristos 	       le64toh (archdr->ctfa_ndicts),
1748dffb485Schristos 	       sizeof (struct ctf_archive_modent), sort_modent_by_name,
1758dffb485Schristos 	       nametbl);
1768dffb485Schristos 
1778dffb485Schristos    /* Now the name table.  */
1788dffb485Schristos 
1798dffb485Schristos   if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
1808dffb485Schristos     {
1818dffb485Schristos       errmsg = N_("ctf_arc_write(): cannot get current file position "
1828dffb485Schristos 		  "in archive");
1838dffb485Schristos       goto err_free;
1848dffb485Schristos     }
1858dffb485Schristos   archdr->ctfa_names = htole64 (nameoffs);
1868dffb485Schristos   np = nametbl;
1878dffb485Schristos   while (namesz > 0)
1888dffb485Schristos     {
1898dffb485Schristos       ssize_t len;
1908dffb485Schristos       if ((len = write (fd, np, namesz)) < 0)
1918dffb485Schristos 	{
1928dffb485Schristos 	  errmsg = N_("ctf_arc_write(): cannot write name table to archive");
1938dffb485Schristos 	  goto err_free;
1948dffb485Schristos 	}
1958dffb485Schristos       namesz -= len;
1968dffb485Schristos       np += len;
1978dffb485Schristos     }
1988dffb485Schristos   free (nametbl);
1998dffb485Schristos 
2008dffb485Schristos   if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
2018dffb485Schristos     goto err_unmap;
2028dffb485Schristos   if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
2038dffb485Schristos     goto err;
2048dffb485Schristos   return 0;
2058dffb485Schristos 
2068dffb485Schristos err_free:
2078dffb485Schristos   free (nametbl);
2088dffb485Schristos err_unmap:
2098dffb485Schristos   arc_mmap_unmap (archdr, headersz, NULL);
2108dffb485Schristos err:
2118dffb485Schristos   /* We report errors into the first file in the archive, if any: if this is a
2128dffb485Schristos      zero-file archive, put it in the open-errors stream for lack of anywhere
2138dffb485Schristos      else for it to go.  */
2144b169a6bSchristos   ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, "%s",
2158dffb485Schristos 		gettext (errmsg));
2168dffb485Schristos   return errno;
2178dffb485Schristos }
2188dffb485Schristos 
2194b169a6bSchristos /* Write out a CTF archive.  The entries in CTF_DICTS are referenced by name:
2204b169a6bSchristos    the names are passed in the names array, which must have CTF_DICTS entries.
2218dffb485Schristos 
2228dffb485Schristos    If the filename is NULL, create a temporary file and return a pointer to it.
2238dffb485Schristos 
2248dffb485Schristos    Returns 0 on success, or an errno, or an ECTF_* value.  */
2258dffb485Schristos int
2264b169a6bSchristos ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
2278dffb485Schristos 	       const char **names, size_t threshold)
2288dffb485Schristos {
2298dffb485Schristos   int err;
2308dffb485Schristos   int fd;
2318dffb485Schristos 
2328dffb485Schristos   if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
2338dffb485Schristos     {
2344b169a6bSchristos       ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
2358dffb485Schristos 		    _("ctf_arc_write(): cannot create %s"), file);
2368dffb485Schristos       return errno;
2378dffb485Schristos     }
2388dffb485Schristos 
2394b169a6bSchristos   err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, names, threshold);
2408dffb485Schristos   if (err)
2418dffb485Schristos     goto err_close;
2428dffb485Schristos 
2438dffb485Schristos   if ((err = close (fd)) < 0)
2444b169a6bSchristos     ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
2458dffb485Schristos 		  _("ctf_arc_write(): cannot close after writing to archive"));
2468dffb485Schristos   goto err;
2478dffb485Schristos 
2488dffb485Schristos  err_close:
2498dffb485Schristos   (void) close (fd);
2508dffb485Schristos  err:
2518dffb485Schristos   if (err < 0)
2528dffb485Schristos     unlink (file);
2538dffb485Schristos 
2548dffb485Schristos   return err;
2558dffb485Schristos }
2568dffb485Schristos 
257*12989c96Schristos /* Write one CTF dict out.  Return the file position of the written file (or
2588dffb485Schristos    rather, of the file-size uint64_t that precedes it): negative return is a
2598dffb485Schristos    negative errno or ctf_errno value.  On error, the file position may no longer
2608dffb485Schristos    be at the end of the file.  */
2618dffb485Schristos static off_t
2624b169a6bSchristos arc_write_one_ctf (ctf_dict_t *f, int fd, size_t threshold)
2638dffb485Schristos {
2648dffb485Schristos   off_t off, end_off;
2658dffb485Schristos   uint64_t ctfsz = 0;
2668dffb485Schristos   char *ctfszp;
2678dffb485Schristos   size_t ctfsz_len;
2684b169a6bSchristos   int (*writefn) (ctf_dict_t * fp, int fd);
2698dffb485Schristos 
2708dffb485Schristos   if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
2718dffb485Schristos     return errno * -1;
2728dffb485Schristos 
2738dffb485Schristos   if (f->ctf_size > threshold)
2748dffb485Schristos     writefn = ctf_compress_write;
2758dffb485Schristos   else
2768dffb485Schristos     writefn = ctf_write;
2778dffb485Schristos 
2788dffb485Schristos   /* This zero-write turns into the size in a moment. */
2798dffb485Schristos   ctfsz_len = sizeof (ctfsz);
2808dffb485Schristos   ctfszp = (char *) &ctfsz;
2818dffb485Schristos   while (ctfsz_len > 0)
2828dffb485Schristos     {
2838dffb485Schristos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
2848dffb485Schristos       if (writelen < 0)
2858dffb485Schristos 	return errno * -1;
2868dffb485Schristos       ctfsz_len -= writelen;
2878dffb485Schristos       ctfszp += writelen;
2888dffb485Schristos     }
2898dffb485Schristos 
2908dffb485Schristos   if (writefn (f, fd) != 0)
2918dffb485Schristos     return f->ctf_errno * -1;
2928dffb485Schristos 
2938dffb485Schristos   if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
2948dffb485Schristos     return errno * -1;
2958dffb485Schristos   ctfsz = htole64 (end_off - off);
2968dffb485Schristos 
2978dffb485Schristos   if ((lseek (fd, off, SEEK_SET)) < 0)
2988dffb485Schristos     return errno * -1;
2998dffb485Schristos 
3008dffb485Schristos   /* ... here.  */
3018dffb485Schristos   ctfsz_len = sizeof (ctfsz);
3028dffb485Schristos   ctfszp = (char *) &ctfsz;
3038dffb485Schristos   while (ctfsz_len > 0)
3048dffb485Schristos     {
3058dffb485Schristos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
3068dffb485Schristos       if (writelen < 0)
3078dffb485Schristos 	return errno * -1;
3088dffb485Schristos       ctfsz_len -= writelen;
3098dffb485Schristos       ctfszp += writelen;
3108dffb485Schristos     }
3118dffb485Schristos 
3128dffb485Schristos   end_off = LCTF_ALIGN_OFFS (end_off, 8);
3138dffb485Schristos   if ((lseek (fd, end_off, SEEK_SET)) < 0)
3148dffb485Schristos     return errno * -1;
3158dffb485Schristos 
3168dffb485Schristos   return off;
3178dffb485Schristos }
3188dffb485Schristos 
3198dffb485Schristos /* qsort() function to sort the array of struct ctf_archive_modents into
3208dffb485Schristos    ascending name order.  */
3218dffb485Schristos static int
3228dffb485Schristos sort_modent_by_name (const void *one, const void *two, void *n)
3238dffb485Schristos {
3248dffb485Schristos   const struct ctf_archive_modent *a = one;
3258dffb485Schristos   const struct ctf_archive_modent *b = two;
3268dffb485Schristos   char *nametbl = n;
3278dffb485Schristos 
3288dffb485Schristos   return strcmp (&nametbl[le64toh (a->name_offset)],
3298dffb485Schristos 		 &nametbl[le64toh (b->name_offset)]);
3308dffb485Schristos }
3318dffb485Schristos 
3328dffb485Schristos /* bsearch_r() function to search for a given name in the sorted array of struct
3338dffb485Schristos    ctf_archive_modents.  */
3348dffb485Schristos static int
3358dffb485Schristos search_modent_by_name (const void *key, const void *ent, void *arg)
3368dffb485Schristos {
3378dffb485Schristos   const char *k = key;
3388dffb485Schristos   const struct ctf_archive_modent *v = ent;
3398dffb485Schristos   const char *search_nametbl = arg;
3408dffb485Schristos 
3418dffb485Schristos   return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
3428dffb485Schristos }
3438dffb485Schristos 
3448dffb485Schristos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
3454b169a6bSchristos    ctf_dict.  Closes ARC and/or FP on error.  Arrange to free the SYMSECT or
3468dffb485Schristos    STRSECT, as needed, on close.  Possibly do not unmap on close.  */
3478dffb485Schristos 
3488dffb485Schristos struct ctf_archive_internal *
3498dffb485Schristos ctf_new_archive_internal (int is_archive, int unmap_on_close,
3508dffb485Schristos 			  struct ctf_archive *arc,
3514b169a6bSchristos 			  ctf_dict_t *fp, const ctf_sect_t *symsect,
3528dffb485Schristos 			  const ctf_sect_t *strsect,
3538dffb485Schristos 			  int *errp)
3548dffb485Schristos {
3558dffb485Schristos   struct ctf_archive_internal *arci;
3568dffb485Schristos 
3578dffb485Schristos   if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
3588dffb485Schristos     {
3598dffb485Schristos       if (is_archive)
3608dffb485Schristos 	{
3618dffb485Schristos 	  if (unmap_on_close)
3628dffb485Schristos 	    ctf_arc_close_internal (arc);
3638dffb485Schristos 	}
3648dffb485Schristos       else
3654b169a6bSchristos 	ctf_dict_close (fp);
3668dffb485Schristos       return (ctf_set_open_errno (errp, errno));
3678dffb485Schristos     }
3688dffb485Schristos   arci->ctfi_is_archive = is_archive;
3698dffb485Schristos   if (is_archive)
3708dffb485Schristos     arci->ctfi_archive = arc;
3718dffb485Schristos   else
3724b169a6bSchristos     arci->ctfi_dict = fp;
3738dffb485Schristos   if (symsect)
3748dffb485Schristos      memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect));
3758dffb485Schristos   if (strsect)
3768dffb485Schristos      memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
3778dffb485Schristos   arci->ctfi_free_symsect = 0;
3788dffb485Schristos   arci->ctfi_free_strsect = 0;
3798dffb485Schristos   arci->ctfi_unmap_on_close = unmap_on_close;
3804b169a6bSchristos   arci->ctfi_symsect_little_endian = -1;
3818dffb485Schristos 
3828dffb485Schristos   return arci;
3838dffb485Schristos }
3848dffb485Schristos 
3854b169a6bSchristos /* Set the symbol-table endianness of an archive (defaulting the symtab
3864b169a6bSchristos    endianness of all ctf_file_t's opened from that archive).  */
3874b169a6bSchristos void
3884b169a6bSchristos ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian)
3894b169a6bSchristos {
3904b169a6bSchristos   arc->ctfi_symsect_little_endian = !!little_endian;
3914b169a6bSchristos   if (!arc->ctfi_is_archive)
3924b169a6bSchristos     ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian);
3934b169a6bSchristos }
3944b169a6bSchristos 
3954b169a6bSchristos /* Get the CTF preamble from data in a buffer, which may be either an archive or
3964b169a6bSchristos    a CTF dict.  If multiple dicts are present in an archive, the preamble comes
3974b169a6bSchristos    from an arbitrary dict.  The preamble is a pointer into the ctfsect passed
3984b169a6bSchristos    in.  */
3994b169a6bSchristos 
4004b169a6bSchristos const ctf_preamble_t *
4014b169a6bSchristos ctf_arc_bufpreamble (const ctf_sect_t *ctfsect)
4024b169a6bSchristos {
403*12989c96Schristos   if (ctfsect->cts_data != NULL
404*12989c96Schristos       && ctfsect->cts_size > sizeof (uint64_t)
405*12989c96Schristos       && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
4064b169a6bSchristos     {
4074b169a6bSchristos       struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
4084b169a6bSchristos       return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
4094b169a6bSchristos 				       + sizeof (uint64_t));
4104b169a6bSchristos     }
4114b169a6bSchristos   else
4124b169a6bSchristos     return (const ctf_preamble_t *) ctfsect->cts_data;
4134b169a6bSchristos }
4144b169a6bSchristos 
4158dffb485Schristos /* Open a CTF archive or dictionary from data in a buffer (which the caller must
4168dffb485Schristos    preserve until ctf_arc_close() time).  Returns the archive, or NULL and an
4178dffb485Schristos    error in *err (if not NULL).  */
4188dffb485Schristos ctf_archive_t *
4198dffb485Schristos ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
4208dffb485Schristos 		 const ctf_sect_t *strsect, int *errp)
4218dffb485Schristos {
4228dffb485Schristos   struct ctf_archive *arc = NULL;
4238dffb485Schristos   int is_archive;
4244b169a6bSchristos   ctf_dict_t *fp = NULL;
4258dffb485Schristos 
426*12989c96Schristos   if (ctfsect->cts_data != NULL
427*12989c96Schristos       && ctfsect->cts_size > sizeof (uint64_t)
428*12989c96Schristos       && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
4298dffb485Schristos     {
4308dffb485Schristos       /* The archive is mmappable, so this operation is trivial.
4318dffb485Schristos 
4328dffb485Schristos 	 This buffer is nonmodifiable, so the trick involving mmapping only part
4338dffb485Schristos 	 of it and storing the length in the magic number is not applicable: so
4348dffb485Schristos 	 record this fact in the archive-wrapper header.  (We cannot record it
4358dffb485Schristos 	 in the archive, because the archive may very well be a read-only
4368dffb485Schristos 	 mapping.)  */
4378dffb485Schristos 
4388dffb485Schristos       is_archive = 1;
4398dffb485Schristos       arc = (struct ctf_archive *) ctfsect->cts_data;
4408dffb485Schristos     }
4418dffb485Schristos   else
4428dffb485Schristos     {
4438dffb485Schristos       is_archive = 0;
4448dffb485Schristos       if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL)
4458dffb485Schristos 	{
4468dffb485Schristos 	  ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF"));
4478dffb485Schristos 	  return NULL;
4488dffb485Schristos 	}
4498dffb485Schristos     }
4508dffb485Schristos   return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect,
4518dffb485Schristos 				   errp);
4528dffb485Schristos }
4538dffb485Schristos 
4548dffb485Schristos /* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
4558dffb485Schristos    not NULL).  */
4568dffb485Schristos struct ctf_archive *
4578dffb485Schristos ctf_arc_open_internal (const char *filename, int *errp)
4588dffb485Schristos {
4598dffb485Schristos   const char *errmsg;
4608dffb485Schristos   int fd;
4618dffb485Schristos   struct stat s;
4628dffb485Schristos   struct ctf_archive *arc;		/* (Actually the whole file.)  */
4638dffb485Schristos 
4648dffb485Schristos   libctf_init_debug();
4658dffb485Schristos   if ((fd = open (filename, O_RDONLY)) < 0)
4668dffb485Schristos     {
4678dffb485Schristos       errmsg = N_("ctf_arc_open(): cannot open %s");
4688dffb485Schristos       goto err;
4698dffb485Schristos     }
4708dffb485Schristos   if (fstat (fd, &s) < 0)
4718dffb485Schristos     {
4728dffb485Schristos       errmsg = N_("ctf_arc_open(): cannot stat %s");
4738dffb485Schristos       goto err_close;
4748dffb485Schristos     }
4758dffb485Schristos 
4768dffb485Schristos   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
4778dffb485Schristos     {
4788dffb485Schristos       errmsg = N_("ctf_arc_open(): cannot read in %s");
4798dffb485Schristos       goto err_close;
4808dffb485Schristos     }
4818dffb485Schristos 
4828dffb485Schristos   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
4838dffb485Schristos     {
4848dffb485Schristos       errmsg = N_("ctf_arc_open(): %s: invalid magic number");
4858dffb485Schristos       errno = ECTF_FMT;
4868dffb485Schristos       goto err_unmap;
4878dffb485Schristos     }
4888dffb485Schristos 
4898dffb485Schristos   /* This horrible hack lets us know how much to unmap when the file is
4908dffb485Schristos      closed.  (We no longer need the magic number, and the mapping
4918dffb485Schristos      is private.)  */
4928dffb485Schristos   arc->ctfa_magic = s.st_size;
4938dffb485Schristos   close (fd);
4948dffb485Schristos   return arc;
4958dffb485Schristos 
4968dffb485Schristos err_unmap:
4978dffb485Schristos   arc_mmap_unmap (arc, s.st_size, NULL);
4988dffb485Schristos err_close:
4998dffb485Schristos   close (fd);
5008dffb485Schristos err:
5018dffb485Schristos   if (errp)
5028dffb485Schristos     *errp = errno;
5038dffb485Schristos   ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename);
5048dffb485Schristos   return NULL;
5058dffb485Schristos }
5068dffb485Schristos 
5078dffb485Schristos /* Close an archive.  */
5088dffb485Schristos void
5098dffb485Schristos ctf_arc_close_internal (struct ctf_archive *arc)
5108dffb485Schristos {
5118dffb485Schristos   if (arc == NULL)
5128dffb485Schristos     return;
5138dffb485Schristos 
5148dffb485Schristos   /* See the comment in ctf_arc_open().  */
5158dffb485Schristos   arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
5168dffb485Schristos }
5178dffb485Schristos 
5188dffb485Schristos /* Public entry point: close an archive, or CTF file.  */
5198dffb485Schristos void
5208dffb485Schristos ctf_arc_close (ctf_archive_t *arc)
5218dffb485Schristos {
5228dffb485Schristos   if (arc == NULL)
5238dffb485Schristos     return;
5248dffb485Schristos 
5258dffb485Schristos   if (arc->ctfi_is_archive)
5268dffb485Schristos     {
5278dffb485Schristos       if (arc->ctfi_unmap_on_close)
5288dffb485Schristos 	ctf_arc_close_internal (arc->ctfi_archive);
5298dffb485Schristos     }
5308dffb485Schristos   else
5314b169a6bSchristos     ctf_dict_close (arc->ctfi_dict);
5324b169a6bSchristos   free (arc->ctfi_symdicts);
5334b169a6bSchristos   free (arc->ctfi_symnamedicts);
5344b169a6bSchristos   ctf_dynhash_destroy (arc->ctfi_dicts);
5358dffb485Schristos   if (arc->ctfi_free_symsect)
5368dffb485Schristos     free ((void *) arc->ctfi_symsect.cts_data);
5378dffb485Schristos   if (arc->ctfi_free_strsect)
5388dffb485Schristos     free ((void *) arc->ctfi_strsect.cts_data);
5398dffb485Schristos   free (arc->ctfi_data);
5408dffb485Schristos   if (arc->ctfi_bfd_close)
5418dffb485Schristos     arc->ctfi_bfd_close (arc);
5428dffb485Schristos   free (arc);
5438dffb485Schristos }
5448dffb485Schristos 
5454b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
5468dffb485Schristos    non-NULL.  A name of NULL means to open the default file.  */
5474b169a6bSchristos static ctf_dict_t *
5484b169a6bSchristos ctf_dict_open_internal (const struct ctf_archive *arc,
5498dffb485Schristos 			const ctf_sect_t *symsect,
5508dffb485Schristos 			const ctf_sect_t *strsect,
5514b169a6bSchristos 			const char *name, int little_endian,
5524b169a6bSchristos 			int *errp)
5538dffb485Schristos {
5548dffb485Schristos   struct ctf_archive_modent *modent;
5558dffb485Schristos   const char *search_nametbl;
5568dffb485Schristos 
5578dffb485Schristos   if (name == NULL)
5588dffb485Schristos     name = _CTF_SECTION;		 /* The default name.  */
5598dffb485Schristos 
5604b169a6bSchristos   ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name);
5618dffb485Schristos 
5628dffb485Schristos   modent = (ctf_archive_modent_t *) ((char *) arc
5638dffb485Schristos 				     + sizeof (struct ctf_archive));
5648dffb485Schristos 
5658dffb485Schristos   search_nametbl = (const char *) arc + le64toh (arc->ctfa_names);
5664b169a6bSchristos   modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts),
5678dffb485Schristos 		      sizeof (struct ctf_archive_modent),
5688dffb485Schristos 		      search_modent_by_name, (void *) search_nametbl);
5698dffb485Schristos 
5708dffb485Schristos   /* This is actually a common case and normal operation: no error
5718dffb485Schristos      debug output.  */
5728dffb485Schristos   if (modent == NULL)
5738dffb485Schristos     {
5748dffb485Schristos       if (errp)
5758dffb485Schristos 	*errp = ECTF_ARNNAME;
5768dffb485Schristos       return NULL;
5778dffb485Schristos     }
5788dffb485Schristos 
5794b169a6bSchristos   return ctf_dict_open_by_offset (arc, symsect, strsect,
5804b169a6bSchristos 				  le64toh (modent->ctf_offset),
5814b169a6bSchristos 				  little_endian, errp);
5828dffb485Schristos }
5838dffb485Schristos 
5844b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
5858dffb485Schristos    non-NULL.  A name of NULL means to open the default file.
5868dffb485Schristos 
5878dffb485Schristos    Use the specified string and symbol table sections.
5888dffb485Schristos 
5898dffb485Schristos    Public entry point.  */
5904b169a6bSchristos ctf_dict_t *
5914b169a6bSchristos ctf_dict_open_sections (const ctf_archive_t *arc,
5928dffb485Schristos 			const ctf_sect_t *symsect,
5938dffb485Schristos 			const ctf_sect_t *strsect,
5948dffb485Schristos 			const char *name,
5958dffb485Schristos 			int *errp)
5968dffb485Schristos {
5978dffb485Schristos   if (arc->ctfi_is_archive)
5988dffb485Schristos     {
5994b169a6bSchristos       ctf_dict_t *ret;
6004b169a6bSchristos       ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect,
6014b169a6bSchristos 				    name, arc->ctfi_symsect_little_endian,
6024b169a6bSchristos 				    errp);
6038dffb485Schristos       if (ret)
6044b169a6bSchristos 	{
6058dffb485Schristos 	  ret->ctf_archive = (ctf_archive_t *) arc;
606*12989c96Schristos 	  if (ctf_arc_import_parent (arc, ret, errp) < 0)
607*12989c96Schristos 	    {
608*12989c96Schristos 	      ctf_dict_close (ret);
609*12989c96Schristos 	      return NULL;
610*12989c96Schristos 	    }
6114b169a6bSchristos 	}
6128dffb485Schristos       return ret;
6138dffb485Schristos     }
6148dffb485Schristos 
6158dffb485Schristos   if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
6168dffb485Schristos     {
6178dffb485Schristos       if (errp)
6188dffb485Schristos 	*errp = ECTF_ARNNAME;
6198dffb485Schristos       return NULL;
6208dffb485Schristos     }
6214b169a6bSchristos   arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc;
6228dffb485Schristos 
6234b169a6bSchristos   /* Bump the refcount so that the user can ctf_dict_close() it.  */
6244b169a6bSchristos   arc->ctfi_dict->ctf_refcnt++;
6254b169a6bSchristos   return arc->ctfi_dict;
6268dffb485Schristos }
6278dffb485Schristos 
6284b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
6298dffb485Schristos    non-NULL.  A name of NULL means to open the default file.
6308dffb485Schristos 
6318dffb485Schristos    Public entry point.  */
6324b169a6bSchristos ctf_dict_t *
6334b169a6bSchristos ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp)
6348dffb485Schristos {
6358dffb485Schristos   const ctf_sect_t *symsect = &arc->ctfi_symsect;
6368dffb485Schristos   const ctf_sect_t *strsect = &arc->ctfi_strsect;
6378dffb485Schristos 
6388dffb485Schristos   if (symsect->cts_name == NULL)
6398dffb485Schristos     symsect = NULL;
6408dffb485Schristos   if (strsect->cts_name == NULL)
6418dffb485Schristos     strsect = NULL;
6428dffb485Schristos 
6434b169a6bSchristos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
6448dffb485Schristos }
6458dffb485Schristos 
6464b169a6bSchristos static void
6474b169a6bSchristos ctf_cached_dict_close (void *fp)
6484b169a6bSchristos {
6494b169a6bSchristos   ctf_dict_close ((ctf_dict_t *) fp);
6504b169a6bSchristos }
6514b169a6bSchristos 
6524b169a6bSchristos /* Return the ctf_dict_t with the given name and cache it in the archive's
6534b169a6bSchristos    ctfi_dicts.  If this is the first cached dict, designate it the
6544b169a6bSchristos    crossdict_cache.  */
6554b169a6bSchristos static ctf_dict_t *
6564b169a6bSchristos ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
6574b169a6bSchristos {
6584b169a6bSchristos   ctf_dict_t *fp;
6594b169a6bSchristos   char *dupname;
6604b169a6bSchristos 
6614b169a6bSchristos   /* Just return from the cache if possible.  */
6624b169a6bSchristos   if (arc->ctfi_dicts
6634b169a6bSchristos       && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL))
6644b169a6bSchristos     {
6654b169a6bSchristos       fp->ctf_refcnt++;
6664b169a6bSchristos       return fp;
6674b169a6bSchristos     }
6684b169a6bSchristos 
6694b169a6bSchristos   /* Not yet cached: open it.  */
6704b169a6bSchristos   fp = ctf_dict_open (arc, name, errp);
6714b169a6bSchristos   dupname = strdup (name);
6724b169a6bSchristos 
6734b169a6bSchristos   if (!fp || !dupname)
6744b169a6bSchristos     goto oom;
6754b169a6bSchristos 
6764b169a6bSchristos   if (arc->ctfi_dicts == NULL)
6774b169a6bSchristos     if ((arc->ctfi_dicts
6784b169a6bSchristos 	 = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
6794b169a6bSchristos 			       free, ctf_cached_dict_close)) == NULL)
6804b169a6bSchristos       goto oom;
6814b169a6bSchristos 
6824b169a6bSchristos   if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0)
6834b169a6bSchristos     goto oom;
6844b169a6bSchristos   fp->ctf_refcnt++;
6854b169a6bSchristos 
6864b169a6bSchristos   if (arc->ctfi_crossdict_cache == NULL)
6874b169a6bSchristos     arc->ctfi_crossdict_cache = fp;
6884b169a6bSchristos 
6894b169a6bSchristos   return fp;
6904b169a6bSchristos 
6914b169a6bSchristos  oom:
6924b169a6bSchristos   ctf_dict_close (fp);
6934b169a6bSchristos   free (dupname);
6944b169a6bSchristos   if (errp)
6954b169a6bSchristos     *errp = ENOMEM;
6964b169a6bSchristos   return NULL;
6974b169a6bSchristos }
6984b169a6bSchristos 
6994b169a6bSchristos /* Flush any caches the CTF archive may have open.  */
7004b169a6bSchristos void
7014b169a6bSchristos ctf_arc_flush_caches (ctf_archive_t *wrapper)
7024b169a6bSchristos {
7034b169a6bSchristos   free (wrapper->ctfi_symdicts);
704*12989c96Schristos   ctf_dynhash_destroy (wrapper->ctfi_symnamedicts);
7054b169a6bSchristos   ctf_dynhash_destroy (wrapper->ctfi_dicts);
7064b169a6bSchristos   wrapper->ctfi_symdicts = NULL;
7074b169a6bSchristos   wrapper->ctfi_symnamedicts = NULL;
7084b169a6bSchristos   wrapper->ctfi_dicts = NULL;
7094b169a6bSchristos   wrapper->ctfi_crossdict_cache = NULL;
7104b169a6bSchristos }
7114b169a6bSchristos 
7124b169a6bSchristos /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if
7138dffb485Schristos    none, setting 'err' if non-NULL.  */
7144b169a6bSchristos static ctf_dict_t *
7154b169a6bSchristos ctf_dict_open_by_offset (const struct ctf_archive *arc,
7168dffb485Schristos 			 const ctf_sect_t *symsect,
7178dffb485Schristos 			 const ctf_sect_t *strsect, size_t offset,
7184b169a6bSchristos 			 int little_endian, int *errp)
7198dffb485Schristos {
7208dffb485Schristos   ctf_sect_t ctfsect;
7214b169a6bSchristos   ctf_dict_t *fp;
7228dffb485Schristos 
7234b169a6bSchristos   ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset);
7248dffb485Schristos 
7258dffb485Schristos   memset (&ctfsect, 0, sizeof (ctf_sect_t));
7268dffb485Schristos 
7278dffb485Schristos   offset += le64toh (arc->ctfa_ctfs);
7288dffb485Schristos 
7298dffb485Schristos   ctfsect.cts_name = _CTF_SECTION;
7308dffb485Schristos   ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
7318dffb485Schristos   ctfsect.cts_entsize = 1;
7328dffb485Schristos   ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
7338dffb485Schristos   fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
7348dffb485Schristos   if (fp)
7354b169a6bSchristos     {
7368dffb485Schristos       ctf_setmodel (fp, le64toh (arc->ctfa_model));
7374b169a6bSchristos       if (little_endian >= 0)
7384b169a6bSchristos 	ctf_symsect_endianness (fp, little_endian);
7394b169a6bSchristos     }
7408dffb485Schristos   return fp;
7418dffb485Schristos }
7428dffb485Schristos 
7434b169a6bSchristos /* Backward compatibility.  */
7444b169a6bSchristos ctf_dict_t *
7454b169a6bSchristos ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name,
7464b169a6bSchristos 		      int *errp)
7474b169a6bSchristos {
7484b169a6bSchristos   return ctf_dict_open (arc, name, errp);
7494b169a6bSchristos }
7504b169a6bSchristos 
7514b169a6bSchristos ctf_dict_t *
7524b169a6bSchristos ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
7534b169a6bSchristos 			       const ctf_sect_t *symsect,
7544b169a6bSchristos 			       const ctf_sect_t *strsect,
7554b169a6bSchristos 			       const char *name,
7564b169a6bSchristos 			       int *errp)
7574b169a6bSchristos {
7584b169a6bSchristos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
7594b169a6bSchristos }
7604b169a6bSchristos 
7614b169a6bSchristos /* Import the parent into a ctf archive, if this is a child, the parent is not
7624b169a6bSchristos    already set, and a suitable archive member exists.  No error is raised if
7634b169a6bSchristos    this is not possible: this is just a best-effort helper operation to give
7644b169a6bSchristos    people useful dicts to start with.  */
765*12989c96Schristos static int
766*12989c96Schristos ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp)
7674b169a6bSchristos {
7684b169a6bSchristos   if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent)
7694b169a6bSchristos     {
770*12989c96Schristos       int err;
7714b169a6bSchristos       ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc,
772*12989c96Schristos 						 fp->ctf_parname, &err);
773*12989c96Schristos       if (errp)
774*12989c96Schristos 	*errp = err;
775*12989c96Schristos 
7764b169a6bSchristos       if (parent)
7774b169a6bSchristos 	{
7784b169a6bSchristos 	  ctf_import (fp, parent);
7794b169a6bSchristos 	  ctf_dict_close (parent);
7804b169a6bSchristos 	}
781*12989c96Schristos       else if (err != ECTF_ARNNAME)
782*12989c96Schristos 	return -1;				/* errno is set for us.  */
7834b169a6bSchristos     }
784*12989c96Schristos   return 0;
7854b169a6bSchristos }
7864b169a6bSchristos 
7878dffb485Schristos /* Return the number of members in an archive.  */
7888dffb485Schristos size_t
7898dffb485Schristos ctf_archive_count (const ctf_archive_t *wrapper)
7908dffb485Schristos {
7918dffb485Schristos   if (!wrapper->ctfi_is_archive)
7928dffb485Schristos     return 1;
7938dffb485Schristos 
7944b169a6bSchristos   return wrapper->ctfi_archive->ctfa_ndicts;
7954b169a6bSchristos }
7964b169a6bSchristos 
7974b169a6bSchristos /* Look up a symbol in an archive by name or index (if the name is set, a lookup
7984b169a6bSchristos    by name is done).  Return the dict in the archive that the symbol is found
7994b169a6bSchristos    in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't
8004b169a6bSchristos    have to look it up yourself).  The dict is cached, so repeated lookups are
8014b169a6bSchristos    nearly free.
8024b169a6bSchristos 
8034b169a6bSchristos    As usual, you should ctf_dict_close() the returned dict once you are done
8044b169a6bSchristos    with it.
8054b169a6bSchristos 
8064b169a6bSchristos    Returns NULL on error, and an error in errp (if set).  */
8074b169a6bSchristos 
8084b169a6bSchristos static ctf_dict_t *
8094b169a6bSchristos ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
8104b169a6bSchristos 			    const char *symname, ctf_id_t *typep, int *errp)
8114b169a6bSchristos {
8124b169a6bSchristos   ctf_dict_t *fp;
8134b169a6bSchristos   void *fpkey;
8144b169a6bSchristos   ctf_id_t type;
8154b169a6bSchristos 
8164b169a6bSchristos   /* The usual non-archive-transparent-wrapper special case.  */
8174b169a6bSchristos   if (!wrapper->ctfi_is_archive)
8184b169a6bSchristos     {
8194b169a6bSchristos       if (!symname)
8204b169a6bSchristos 	{
8214b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
8224b169a6bSchristos 	    {
8234b169a6bSchristos 	      if (errp)
8244b169a6bSchristos 		*errp = ctf_errno (wrapper->ctfi_dict);
8254b169a6bSchristos 	      return NULL;
8264b169a6bSchristos 	    }
8274b169a6bSchristos 	}
8284b169a6bSchristos       else
8294b169a6bSchristos 	{
8304b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict,
8314b169a6bSchristos 						 symname)) == CTF_ERR)
8324b169a6bSchristos 	    {
8334b169a6bSchristos 	      if (errp)
8344b169a6bSchristos 		*errp = ctf_errno (wrapper->ctfi_dict);
8354b169a6bSchristos 	      return NULL;
8364b169a6bSchristos 	    }
8374b169a6bSchristos 	}
8384b169a6bSchristos       if (typep)
8394b169a6bSchristos 	*typep = type;
8404b169a6bSchristos       wrapper->ctfi_dict->ctf_refcnt++;
8414b169a6bSchristos       return wrapper->ctfi_dict;
8424b169a6bSchristos     }
8434b169a6bSchristos 
8444b169a6bSchristos   if (wrapper->ctfi_symsect.cts_name == NULL
8454b169a6bSchristos       || wrapper->ctfi_symsect.cts_data == NULL
8464b169a6bSchristos       || wrapper->ctfi_symsect.cts_size == 0
8474b169a6bSchristos       || wrapper->ctfi_symsect.cts_entsize == 0)
8484b169a6bSchristos     {
8494b169a6bSchristos       if (errp)
8504b169a6bSchristos 	*errp = ECTF_NOSYMTAB;
8514b169a6bSchristos       return NULL;
8524b169a6bSchristos     }
8534b169a6bSchristos 
8544b169a6bSchristos   /* Make enough space for all possible symbol indexes, if not already done.  We
8554b169a6bSchristos      cache the originating dictionary of all symbols.  The dict links are weak,
8564b169a6bSchristos      to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped.
8574b169a6bSchristos      We also cache similar mappings for symbol names: these are ordinary
8584b169a6bSchristos      dynhashes, with weak links to dicts.  */
8594b169a6bSchristos 
8604b169a6bSchristos   if (!wrapper->ctfi_symdicts)
8614b169a6bSchristos     {
8624b169a6bSchristos       if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
8634b169a6bSchristos 					    / wrapper->ctfi_symsect.cts_entsize,
8644b169a6bSchristos 					    sizeof (ctf_dict_t *))) == NULL)
8654b169a6bSchristos 	{
8664b169a6bSchristos 	  if (errp)
8674b169a6bSchristos 	    *errp = ENOMEM;
8684b169a6bSchristos 	  return NULL;
8694b169a6bSchristos 	}
8704b169a6bSchristos     }
8714b169a6bSchristos   if (!wrapper->ctfi_symnamedicts)
8724b169a6bSchristos     {
8734b169a6bSchristos       if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
8744b169a6bSchristos 							    ctf_hash_eq_string,
8754b169a6bSchristos 							    free, NULL)) == NULL)
8764b169a6bSchristos 	{
8774b169a6bSchristos 	  if (errp)
8784b169a6bSchristos 	    *errp = ENOMEM;
8794b169a6bSchristos 	  return NULL;
8804b169a6bSchristos 	}
8814b169a6bSchristos     }
8824b169a6bSchristos 
8834b169a6bSchristos   /* Perhaps the dict in which we found a previous lookup is cached.  If it's
8844b169a6bSchristos      supposed to be cached but we don't find it, pretend it was always not
8854b169a6bSchristos      found: this should never happen, but shouldn't be allowed to cause trouble
8864b169a6bSchristos      if it does.  */
8874b169a6bSchristos 
8884b169a6bSchristos   if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts,
8894b169a6bSchristos 					 symname, NULL, &fpkey))
8904b169a6bSchristos       || (!symname && wrapper->ctfi_symdicts[symidx] != NULL))
8914b169a6bSchristos     {
8924b169a6bSchristos       if (symname)
8934b169a6bSchristos 	fp = (ctf_dict_t *) fpkey;
8944b169a6bSchristos       else
8954b169a6bSchristos 	fp = wrapper->ctfi_symdicts[symidx];
8964b169a6bSchristos 
8974b169a6bSchristos       if (fp == &enosym)
8984b169a6bSchristos 	goto no_sym;
8994b169a6bSchristos 
9004b169a6bSchristos       if (symname)
9014b169a6bSchristos 	{
9024b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR)
9034b169a6bSchristos 	    goto cache_no_sym;
9044b169a6bSchristos 	}
9054b169a6bSchristos       else
9064b169a6bSchristos 	{
9074b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
9084b169a6bSchristos 	    goto cache_no_sym;
9094b169a6bSchristos 	}
9104b169a6bSchristos 
9114b169a6bSchristos       if (typep)
9124b169a6bSchristos 	*typep = type;
9134b169a6bSchristos       fp->ctf_refcnt++;
9144b169a6bSchristos       return fp;
9154b169a6bSchristos     }
9164b169a6bSchristos 
9174b169a6bSchristos   /* Not cached: find it and cache it.  We must track open errors ourselves even
9184b169a6bSchristos      if our caller doesn't, to be able to distinguish no-error end-of-iteration
9194b169a6bSchristos      from open errors.  */
9204b169a6bSchristos 
9214b169a6bSchristos   int local_err;
9224b169a6bSchristos   int *local_errp;
9234b169a6bSchristos   ctf_next_t *i = NULL;
9244b169a6bSchristos   const char *name;
9254b169a6bSchristos 
9264b169a6bSchristos   if (errp)
9274b169a6bSchristos     local_errp = errp;
9284b169a6bSchristos   else
9294b169a6bSchristos     local_errp = &local_err;
9304b169a6bSchristos 
9314b169a6bSchristos   while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL)
9324b169a6bSchristos     {
9334b169a6bSchristos       if (!symname)
9344b169a6bSchristos 	{
9354b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
9364b169a6bSchristos 	    wrapper->ctfi_symdicts[symidx] = fp;
9374b169a6bSchristos 	}
9384b169a6bSchristos       else
9394b169a6bSchristos 	{
9404b169a6bSchristos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR)
9414b169a6bSchristos 	    {
9424b169a6bSchristos 	      char *tmp;
9434b169a6bSchristos 	      /* No error checking, as above.  */
9444b169a6bSchristos 	      if ((tmp = strdup (symname)) != NULL)
9454b169a6bSchristos 		ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp);
9464b169a6bSchristos 	    }
9474b169a6bSchristos 	}
9484b169a6bSchristos 
9494b169a6bSchristos       if (type != CTF_ERR)
9504b169a6bSchristos 	{
9514b169a6bSchristos 	  if (typep)
9524b169a6bSchristos 	    *typep = type;
9534b169a6bSchristos 	  ctf_next_destroy (i);
9544b169a6bSchristos 	  return fp;
9554b169a6bSchristos 	}
9564b169a6bSchristos       if (ctf_errno (fp) != ECTF_NOTYPEDAT)
9574b169a6bSchristos 	{
9584b169a6bSchristos 	  if (errp)
9594b169a6bSchristos 	    *errp = ctf_errno (fp);
9604b169a6bSchristos 	  ctf_next_destroy (i);
9614b169a6bSchristos 	  return NULL;				/* errno is set for us.  */
9624b169a6bSchristos 	}
9634b169a6bSchristos       ctf_dict_close (fp);
9644b169a6bSchristos     }
9654b169a6bSchristos   if (*local_errp != ECTF_NEXT_END)
9664b169a6bSchristos     {
9674b169a6bSchristos       ctf_next_destroy (i);
9684b169a6bSchristos       return NULL;
9694b169a6bSchristos     }
9704b169a6bSchristos 
9714b169a6bSchristos   /* Don't leak end-of-iteration to the caller.  */
9724b169a6bSchristos   *local_errp = 0;
9734b169a6bSchristos 
9744b169a6bSchristos  cache_no_sym:
9754b169a6bSchristos   if (!symname)
9764b169a6bSchristos     wrapper->ctfi_symdicts[symidx] = &enosym;
9774b169a6bSchristos   else
9784b169a6bSchristos     {
9794b169a6bSchristos       char *tmp;
9804b169a6bSchristos 
9814b169a6bSchristos       /* No error checking: if caching fails, there is only a slight performance
9824b169a6bSchristos 	 impact.  */
9834b169a6bSchristos       if ((tmp = strdup (symname)) != NULL)
9844b169a6bSchristos 	if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0)
9854b169a6bSchristos 	  free (tmp);
9864b169a6bSchristos     }
9874b169a6bSchristos 
9884b169a6bSchristos  no_sym:
9894b169a6bSchristos   if (errp)
9904b169a6bSchristos     *errp = ECTF_NOTYPEDAT;
9914b169a6bSchristos   if (typep)
9924b169a6bSchristos     *typep = CTF_ERR;
9934b169a6bSchristos   return NULL;
9944b169a6bSchristos }
9954b169a6bSchristos 
9964b169a6bSchristos /* The public API for looking up a symbol by index.  */
9974b169a6bSchristos ctf_dict_t *
9984b169a6bSchristos ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
9994b169a6bSchristos 		       ctf_id_t *typep, int *errp)
10004b169a6bSchristos {
10014b169a6bSchristos   return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp);
10024b169a6bSchristos }
10034b169a6bSchristos 
10044b169a6bSchristos /* The public API for looking up a symbol by name. */
10054b169a6bSchristos 
10064b169a6bSchristos ctf_dict_t *
10074b169a6bSchristos ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
10084b169a6bSchristos 			    ctf_id_t *typep, int *errp)
10094b169a6bSchristos {
10104b169a6bSchristos   return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
10118dffb485Schristos }
10128dffb485Schristos 
10138dffb485Schristos /* Raw iteration over all CTF files in an archive.  We pass the raw data for all
10148dffb485Schristos    CTF files in turn to the specified callback function.  */
10158dffb485Schristos static int
10168dffb485Schristos ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
10178dffb485Schristos 			       ctf_archive_raw_member_f *func, void *data)
10188dffb485Schristos {
10198dffb485Schristos   int rc;
10208dffb485Schristos   size_t i;
10218dffb485Schristos   struct ctf_archive_modent *modent;
10228dffb485Schristos   const char *nametbl;
10238dffb485Schristos 
10248dffb485Schristos   modent = (ctf_archive_modent_t *) ((char *) arc
10258dffb485Schristos 				     + sizeof (struct ctf_archive));
10268dffb485Schristos   nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
10278dffb485Schristos 
10284b169a6bSchristos   for (i = 0; i < le64toh (arc->ctfa_ndicts); i++)
10298dffb485Schristos     {
10308dffb485Schristos       const char *name;
10318dffb485Schristos       char *fp;
10328dffb485Schristos 
10338dffb485Schristos       name = &nametbl[le64toh (modent[i].name_offset)];
10348dffb485Schristos       fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
10358dffb485Schristos 	    + le64toh (modent[i].ctf_offset));
10368dffb485Schristos 
10378dffb485Schristos       if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
10388dffb485Schristos 		      le64toh (*((uint64_t *) fp)), data)) != 0)
10398dffb485Schristos 	return rc;
10408dffb485Schristos     }
10418dffb485Schristos   return 0;
10428dffb485Schristos }
10438dffb485Schristos 
10448dffb485Schristos /* Raw iteration over all CTF files in an archive: public entry point.
10458dffb485Schristos 
10468dffb485Schristos    Returns -EINVAL if not supported for this sort of archive.  */
10478dffb485Schristos int
10488dffb485Schristos ctf_archive_raw_iter (const ctf_archive_t *arc,
10498dffb485Schristos 		      ctf_archive_raw_member_f * func, void *data)
10508dffb485Schristos {
10518dffb485Schristos   if (arc->ctfi_is_archive)
10528dffb485Schristos     return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
10538dffb485Schristos 
10548dffb485Schristos   return -EINVAL;			 /* Not supported. */
10558dffb485Schristos }
10568dffb485Schristos 
10578dffb485Schristos /* Iterate over all CTF files in an archive: public entry point.  We pass all
10588dffb485Schristos    CTF files in turn to the specified callback function.  */
10598dffb485Schristos int
10608dffb485Schristos ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
10618dffb485Schristos 		  void *data)
10628dffb485Schristos {
10634b169a6bSchristos   ctf_next_t *i = NULL;
10644b169a6bSchristos   ctf_dict_t *fp;
10654b169a6bSchristos   const char *name;
1066*12989c96Schristos   int err = 0;
10678dffb485Schristos 
10684b169a6bSchristos   while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL)
10694b169a6bSchristos     {
10704b169a6bSchristos       int rc;
10718dffb485Schristos 
10724b169a6bSchristos       if ((rc = func (fp, name, data)) != 0)
10734b169a6bSchristos 	{
10744b169a6bSchristos 	  ctf_dict_close (fp);
10754b169a6bSchristos 	  ctf_next_destroy (i);
10764b169a6bSchristos 	  return rc;
10774b169a6bSchristos 	}
10784b169a6bSchristos       ctf_dict_close (fp);
10794b169a6bSchristos     }
1080*12989c96Schristos   if (err != ECTF_NEXT_END && err != 0)
1081*12989c96Schristos     {
1082*12989c96Schristos       ctf_next_destroy (i);
1083*12989c96Schristos       return -1;
1084*12989c96Schristos     }
10854b169a6bSchristos   return 0;
10868dffb485Schristos }
10878dffb485Schristos 
10888dffb485Schristos /* Iterate over all CTF files in an archive, returning each dict in turn as a
10894b169a6bSchristos    ctf_dict_t, and NULL on error or end of iteration.  It is the caller's
10904b169a6bSchristos    responsibility to close it.  Parent dicts may be skipped.
10914b169a6bSchristos 
10924b169a6bSchristos    The archive member is cached for rapid return on future calls.
10938dffb485Schristos 
10948dffb485Schristos    We identify parents by name rather than by flag value: for now, with the
10958dffb485Schristos    linker only emitting parents named _CTF_SECTION, this works well enough.  */
10968dffb485Schristos 
10974b169a6bSchristos ctf_dict_t *
10988dffb485Schristos ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name,
10998dffb485Schristos 		  int skip_parent, int *errp)
11008dffb485Schristos {
11014b169a6bSchristos   ctf_dict_t *f;
11028dffb485Schristos   ctf_next_t *i = *it;
11038dffb485Schristos   struct ctf_archive *arc;
11048dffb485Schristos   struct ctf_archive_modent *modent;
11058dffb485Schristos   const char *nametbl;
11068dffb485Schristos   const char *name_;
11078dffb485Schristos 
11088dffb485Schristos   if (!i)
11098dffb485Schristos     {
11108dffb485Schristos       if ((i = ctf_next_create()) == NULL)
11118dffb485Schristos 	{
11128dffb485Schristos 	  if (errp)
11138dffb485Schristos 	    *errp = ENOMEM;
11148dffb485Schristos 	  return NULL;
11158dffb485Schristos 	}
11168dffb485Schristos       i->cu.ctn_arc = wrapper;
11178dffb485Schristos       i->ctn_iter_fun = (void (*) (void)) ctf_archive_next;
11188dffb485Schristos       *it = i;
11198dffb485Schristos     }
11208dffb485Schristos 
11218dffb485Schristos   if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun)
11228dffb485Schristos     {
11238dffb485Schristos       if (errp)
11248dffb485Schristos 	*errp = ECTF_NEXT_WRONGFUN;
11258dffb485Schristos       return NULL;
11268dffb485Schristos     }
11278dffb485Schristos 
11288dffb485Schristos   if (wrapper != i->cu.ctn_arc)
11298dffb485Schristos     {
11308dffb485Schristos       if (errp)
11318dffb485Schristos 	*errp = ECTF_NEXT_WRONGFP;
11328dffb485Schristos       return NULL;
11338dffb485Schristos     }
11348dffb485Schristos 
11354b169a6bSchristos   /* Iteration is made a bit more complex by the need to handle ctf_dict_t's
11368dffb485Schristos      transparently wrapped in a single-member archive.  These are parents: if
11378dffb485Schristos      skip_parent is on, they are skipped and the iterator terminates
11388dffb485Schristos      immediately.  */
11398dffb485Schristos 
11408dffb485Schristos   if (!wrapper->ctfi_is_archive && i->ctn_n == 0)
11418dffb485Schristos     {
11428dffb485Schristos       i->ctn_n++;
11438dffb485Schristos       if (!skip_parent)
11448dffb485Schristos 	{
11454b169a6bSchristos 	  wrapper->ctfi_dict->ctf_refcnt++;
11464b169a6bSchristos 	  if (name)
11474b169a6bSchristos 	    *name = _CTF_SECTION;
11484b169a6bSchristos 	  return wrapper->ctfi_dict;
11498dffb485Schristos 	}
11508dffb485Schristos     }
11518dffb485Schristos 
11528dffb485Schristos   arc = wrapper->ctfi_archive;
11538dffb485Schristos 
11548dffb485Schristos   /* The loop keeps going when skip_parent is on as long as the member we find
11558dffb485Schristos      is the parent (i.e. at most two iterations, but possibly an early return if
11568dffb485Schristos      *all* we have is a parent).  */
11578dffb485Schristos 
11588dffb485Schristos   do
11598dffb485Schristos     {
11604b169a6bSchristos       if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts)))
11618dffb485Schristos 	{
11628dffb485Schristos 	  ctf_next_destroy (i);
11638dffb485Schristos 	  *it = NULL;
11648dffb485Schristos 	  if (errp)
11658dffb485Schristos 	    *errp = ECTF_NEXT_END;
11668dffb485Schristos 	  return NULL;
11678dffb485Schristos 	}
11688dffb485Schristos 
11698dffb485Schristos       modent = (ctf_archive_modent_t *) ((char *) arc
11708dffb485Schristos 					 + sizeof (struct ctf_archive));
11718dffb485Schristos       nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
11728dffb485Schristos 
11738dffb485Schristos       name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
11748dffb485Schristos       i->ctn_n++;
11754b169a6bSchristos     }
11764b169a6bSchristos   while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
11778dffb485Schristos 
11788dffb485Schristos   if (name)
11798dffb485Schristos     *name = name_;
11808dffb485Schristos 
11814b169a6bSchristos   f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp);
11828dffb485Schristos   return f;
11838dffb485Schristos }
11848dffb485Schristos 
11858dffb485Schristos #ifdef HAVE_MMAP
11868dffb485Schristos /* Map the header in.  Only used on new, empty files.  */
11878dffb485Schristos static void *arc_mmap_header (int fd, size_t headersz)
11888dffb485Schristos {
11898dffb485Schristos   void *hdr;
11908dffb485Schristos   if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
11918dffb485Schristos 		   0)) == MAP_FAILED)
11928dffb485Schristos     return NULL;
11938dffb485Schristos   return hdr;
11948dffb485Schristos }
11958dffb485Schristos 
11968dffb485Schristos /* mmap() the whole file, for reading only.  (Map it writably, but privately: we
11978dffb485Schristos    need to modify the region, but don't need anyone else to see the
11988dffb485Schristos    modifications.)  */
11998dffb485Schristos static void *arc_mmap_file (int fd, size_t size)
12008dffb485Schristos {
12018dffb485Schristos   void *arc;
12028dffb485Schristos   if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
12038dffb485Schristos 		   fd, 0)) == MAP_FAILED)
12048dffb485Schristos     return NULL;
12058dffb485Schristos   return arc;
12068dffb485Schristos }
12078dffb485Schristos 
12088dffb485Schristos /* Persist the header to disk.  */
12098dffb485Schristos static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
12108dffb485Schristos 			      size_t headersz, const char **errmsg)
12118dffb485Schristos {
12128dffb485Schristos     if (msync (header, headersz, MS_ASYNC) < 0)
12138dffb485Schristos     {
12148dffb485Schristos       if (errmsg)
12158dffb485Schristos 	*errmsg = N_("arc_mmap_writeout(): cannot sync after writing "
12168dffb485Schristos 		     "to %s: %s");
12178dffb485Schristos       return -1;
12188dffb485Schristos     }
12198dffb485Schristos     return 0;
12208dffb485Schristos }
12218dffb485Schristos 
12228dffb485Schristos /* Unmap the region.  */
12238dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
12248dffb485Schristos {
12258dffb485Schristos   if (munmap (header, headersz) < 0)
12268dffb485Schristos     {
12278dffb485Schristos       if (errmsg)
12288dffb485Schristos 	*errmsg = N_("arc_mmap_munmap(): cannot unmap after writing "
12298dffb485Schristos 		     "to %s: %s");
12308dffb485Schristos       return -1;
12318dffb485Schristos     }
12328dffb485Schristos     return 0;
12338dffb485Schristos }
12348dffb485Schristos #else
12358dffb485Schristos /* Map the header in.  Only used on new, empty files.  */
12368dffb485Schristos static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz)
12378dffb485Schristos {
12388dffb485Schristos   void *hdr;
12398dffb485Schristos   if ((hdr = malloc (headersz)) == NULL)
12408dffb485Schristos     return NULL;
12418dffb485Schristos   return hdr;
12428dffb485Schristos }
12438dffb485Schristos 
12448dffb485Schristos /* Pull in the whole file, for reading only.  We assume the current file
12458dffb485Schristos    position is at the start of the file.  */
12468dffb485Schristos static void *arc_mmap_file (int fd, size_t size)
12478dffb485Schristos {
12488dffb485Schristos   char *data;
12498dffb485Schristos 
12508dffb485Schristos   if ((data = malloc (size)) == NULL)
12518dffb485Schristos     return NULL;
12528dffb485Schristos 
12538dffb485Schristos   if (ctf_pread (fd, data, size, 0) < 0)
12548dffb485Schristos     {
12558dffb485Schristos       free (data);
12568dffb485Schristos       return NULL;
12578dffb485Schristos     }
12588dffb485Schristos   return data;
12598dffb485Schristos }
12608dffb485Schristos 
12618dffb485Schristos /* Persist the header to disk.  */
12628dffb485Schristos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
12638dffb485Schristos 			      const char **errmsg)
12648dffb485Schristos {
12658dffb485Schristos   ssize_t len;
12668dffb485Schristos   char *data = (char *) header;
12678dffb485Schristos   ssize_t count = headersz;
12688dffb485Schristos 
12698dffb485Schristos   if ((lseek (fd, 0, SEEK_SET)) < 0)
12708dffb485Schristos     {
12718dffb485Schristos       if (errmsg)
12728dffb485Schristos 	*errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to "
12738dffb485Schristos 		     "%s: %s");
12748dffb485Schristos       return -1;
12758dffb485Schristos     }
12768dffb485Schristos 
12778dffb485Schristos   while (headersz > 0)
12788dffb485Schristos     {
12798dffb485Schristos       if ((len = write (fd, data, count)) < 0)
12808dffb485Schristos 	{
12818dffb485Schristos 	  if (errmsg)
12828dffb485Schristos 	    *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s");
12838dffb485Schristos 	  return len;
12848dffb485Schristos 	}
12858dffb485Schristos       if (len == EINTR)
12868dffb485Schristos 	continue;
12878dffb485Schristos 
12888dffb485Schristos       if (len == 0)				/* EOF.  */
12898dffb485Schristos 	break;
12908dffb485Schristos 
12918dffb485Schristos       count -= len;
12928dffb485Schristos       data += len;
12938dffb485Schristos     }
12948dffb485Schristos   return 0;
12958dffb485Schristos }
12968dffb485Schristos 
12978dffb485Schristos /* Unmap the region.  */
12988dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_,
12998dffb485Schristos 			   const char **errmsg _libctf_unused_)
13008dffb485Schristos {
13018dffb485Schristos   free (header);
13028dffb485Schristos   return 0;
13038dffb485Schristos }
13048dffb485Schristos #endif
1305