xref: /netbsd-src/external/gpl3/binutils.old/dist/libctf/ctf-archive.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1867d70fcSchristos /* CTF archive files.
2*c42dbd0eSchristos    Copyright (C) 2019-2022 Free Software Foundation, Inc.
3867d70fcSchristos 
4867d70fcSchristos    This file is part of libctf.
5867d70fcSchristos 
6867d70fcSchristos    libctf is free software; you can redistribute it and/or modify it under
7867d70fcSchristos    the terms of the GNU General Public License as published by the Free
8867d70fcSchristos    Software Foundation; either version 3, or (at your option) any later
9867d70fcSchristos    version.
10867d70fcSchristos 
11867d70fcSchristos    This program is distributed in the hope that it will be useful, but
12867d70fcSchristos    WITHOUT ANY WARRANTY; without even the implied warranty of
13867d70fcSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14867d70fcSchristos    See the GNU General Public License for more details.
15867d70fcSchristos 
16867d70fcSchristos    You should have received a copy of the GNU General Public License
17867d70fcSchristos    along with this program; see the file COPYING.  If not see
18867d70fcSchristos    <http://www.gnu.org/licenses/>.  */
19867d70fcSchristos 
20867d70fcSchristos #include <ctf-impl.h>
21867d70fcSchristos #include <sys/types.h>
22867d70fcSchristos #include <sys/stat.h>
23867d70fcSchristos #include <elf.h>
24867d70fcSchristos #include "ctf-endian.h"
25867d70fcSchristos #include <errno.h>
26867d70fcSchristos #include <fcntl.h>
27867d70fcSchristos #include <stdio.h>
28867d70fcSchristos #include <string.h>
29867d70fcSchristos #include <unistd.h>
30867d70fcSchristos 
31867d70fcSchristos #ifdef HAVE_MMAP
32867d70fcSchristos #include <sys/mman.h>
33867d70fcSchristos #endif
34867d70fcSchristos 
35*c42dbd0eSchristos static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold);
36*c42dbd0eSchristos static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc,
37867d70fcSchristos 					    const ctf_sect_t *symsect,
38867d70fcSchristos 					    const ctf_sect_t *strsect,
39*c42dbd0eSchristos 					    size_t offset, int little_endian,
40*c42dbd0eSchristos 					    int *errp);
41867d70fcSchristos static int sort_modent_by_name (const void *one, const void *two, void *n);
42867d70fcSchristos static void *arc_mmap_header (int fd, size_t headersz);
43867d70fcSchristos static void *arc_mmap_file (int fd, size_t size);
44867d70fcSchristos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
45867d70fcSchristos 			      const char **errmsg);
46867d70fcSchristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
47*c42dbd0eSchristos static void ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp);
48867d70fcSchristos 
49*c42dbd0eSchristos /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts
50*c42dbd0eSchristos    and ctfi_symnamedicts.  Never initialized.  */
51*c42dbd0eSchristos static ctf_dict_t enosym;
52867d70fcSchristos 
53867d70fcSchristos /* Write out a CTF archive to the start of the file referenced by the passed-in
54*c42dbd0eSchristos    fd.  The entries in CTF_DICTS are referenced by name: the names are passed in
55*c42dbd0eSchristos    the names array, which must have CTF_DICTS entries.
56867d70fcSchristos 
57867d70fcSchristos    Returns 0 on success, or an errno, or an ECTF_* value.  */
58867d70fcSchristos int
ctf_arc_write_fd(int fd,ctf_dict_t ** ctf_dicts,size_t ctf_dict_cnt,const char ** names,size_t threshold)59*c42dbd0eSchristos ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
60867d70fcSchristos 		  const char **names, size_t threshold)
61867d70fcSchristos {
62867d70fcSchristos   const char *errmsg;
63867d70fcSchristos   struct ctf_archive *archdr;
64867d70fcSchristos   size_t i;
65867d70fcSchristos   char dummy = 0;
66867d70fcSchristos   size_t headersz;
67867d70fcSchristos   ssize_t namesz;
68867d70fcSchristos   size_t ctf_startoffs;		/* Start of the section we are working over.  */
69867d70fcSchristos   char *nametbl = NULL;		/* The name table.  */
70867d70fcSchristos   char *np;
71867d70fcSchristos   off_t nameoffs;
72867d70fcSchristos   struct ctf_archive_modent *modent;
73867d70fcSchristos 
74867d70fcSchristos   ctf_dprintf ("Writing CTF archive with %lu files\n",
75*c42dbd0eSchristos 	       (unsigned long) ctf_dict_cnt);
76867d70fcSchristos 
77867d70fcSchristos   /* Figure out the size of the mmap()ed header, including the
78867d70fcSchristos      ctf_archive_modent array.  We assume that all of this needs no
79867d70fcSchristos      padding: a likely assumption, given that it's all made up of
80867d70fcSchristos      uint64_t's.  */
81867d70fcSchristos   headersz = sizeof (struct ctf_archive)
82*c42dbd0eSchristos     + (ctf_dict_cnt * sizeof (uint64_t) * 2);
83867d70fcSchristos   ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
84867d70fcSchristos 
85867d70fcSchristos   /* From now on we work in two pieces: an mmap()ed region from zero up to the
86867d70fcSchristos      headersz, and a region updated via write() starting after that, containing
87867d70fcSchristos      all the tables.  Platforms that do not support mmap() just use write().  */
88867d70fcSchristos   ctf_startoffs = headersz;
89867d70fcSchristos   if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
90867d70fcSchristos     {
91*c42dbd0eSchristos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
92867d70fcSchristos       goto err;
93867d70fcSchristos     }
94867d70fcSchristos 
95867d70fcSchristos   if (write (fd, &dummy, 1) < 0)
96867d70fcSchristos     {
97*c42dbd0eSchristos       errmsg = N_("ctf_arc_write(): cannot extend file while writing");
98867d70fcSchristos       goto err;
99867d70fcSchristos     }
100867d70fcSchristos 
101867d70fcSchristos   if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
102867d70fcSchristos     {
103*c42dbd0eSchristos       errmsg = N_("ctf_arc_write(): cannot mmap");
104867d70fcSchristos       goto err;
105867d70fcSchristos     }
106867d70fcSchristos 
107867d70fcSchristos   /* Fill in everything we can, which is everything other than the name
108867d70fcSchristos      table offset.  */
109867d70fcSchristos   archdr->ctfa_magic = htole64 (CTFA_MAGIC);
110*c42dbd0eSchristos   archdr->ctfa_ndicts = htole64 (ctf_dict_cnt);
111867d70fcSchristos   archdr->ctfa_ctfs = htole64 (ctf_startoffs);
112867d70fcSchristos 
113867d70fcSchristos   /* We could validate that all CTF files have the same data model, but
114867d70fcSchristos      since any reasonable construction process will be building things of
115867d70fcSchristos      only one bitness anyway, this is pretty pointless, so just use the
116867d70fcSchristos      model of the first CTF file for all of them.  (It *is* valid to
117867d70fcSchristos      create an empty archive: the value of ctfa_model is irrelevant in
118867d70fcSchristos      this case, but we must be sure not to dereference uninitialized
119867d70fcSchristos      memory.)  */
120867d70fcSchristos 
121*c42dbd0eSchristos   if (ctf_dict_cnt > 0)
122*c42dbd0eSchristos     archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0]));
123867d70fcSchristos 
124867d70fcSchristos   /* Now write out the CTFs: ctf_archive_modent array via the mapping,
125867d70fcSchristos      ctfs via write().  The names themselves have not been written yet: we
126867d70fcSchristos      track them in a local strtab until the time is right, and sort the
127867d70fcSchristos      modents array after construction.
128867d70fcSchristos 
129867d70fcSchristos     The name table is not sorted.  */
130867d70fcSchristos 
131*c42dbd0eSchristos   for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++)
132867d70fcSchristos     namesz += strlen (names[i]) + 1;
133867d70fcSchristos 
134867d70fcSchristos   nametbl = malloc (namesz);
135867d70fcSchristos   if (nametbl == NULL)
136867d70fcSchristos     {
137*c42dbd0eSchristos       errmsg = N_("ctf_arc_write(): error writing named CTF to archive");
138867d70fcSchristos       goto err_unmap;
139867d70fcSchristos     }
140867d70fcSchristos 
141867d70fcSchristos   for (i = 0, namesz = 0,
142867d70fcSchristos        modent = (ctf_archive_modent_t *) ((char *) archdr
143867d70fcSchristos 					  + sizeof (struct ctf_archive));
144*c42dbd0eSchristos        i < le64toh (archdr->ctfa_ndicts); i++)
145867d70fcSchristos     {
146867d70fcSchristos       off_t off;
147867d70fcSchristos 
148867d70fcSchristos       strcpy (&nametbl[namesz], names[i]);
149867d70fcSchristos 
150*c42dbd0eSchristos       off = arc_write_one_ctf (ctf_dicts[i], fd, threshold);
151867d70fcSchristos       if ((off < 0) && (off > -ECTF_BASE))
152867d70fcSchristos 	{
153*c42dbd0eSchristos 	  errmsg = N_("ctf_arc_write(): cannot determine file "
154*c42dbd0eSchristos 		      "position while writing to archive");
155867d70fcSchristos 	  goto err_free;
156867d70fcSchristos 	}
157867d70fcSchristos       if (off < 0)
158867d70fcSchristos 	{
159*c42dbd0eSchristos 	  errmsg = N_("ctf_arc_write(): cannot write CTF file to archive");
160867d70fcSchristos 	  errno = off * -1;
161867d70fcSchristos 	  goto err_free;
162867d70fcSchristos 	}
163867d70fcSchristos 
164867d70fcSchristos       modent->name_offset = htole64 (namesz);
165867d70fcSchristos       modent->ctf_offset = htole64 (off - ctf_startoffs);
166867d70fcSchristos       namesz += strlen (names[i]) + 1;
167867d70fcSchristos       modent++;
168867d70fcSchristos     }
169867d70fcSchristos 
170867d70fcSchristos   ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
171867d70fcSchristos 					 + sizeof (struct ctf_archive)),
172*c42dbd0eSchristos 	       le64toh (archdr->ctfa_ndicts),
173867d70fcSchristos 	       sizeof (struct ctf_archive_modent), sort_modent_by_name,
174867d70fcSchristos 	       nametbl);
175867d70fcSchristos 
176867d70fcSchristos    /* Now the name table.  */
177867d70fcSchristos 
178867d70fcSchristos   if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
179867d70fcSchristos     {
180*c42dbd0eSchristos       errmsg = N_("ctf_arc_write(): cannot get current file position "
181*c42dbd0eSchristos 		  "in archive");
182867d70fcSchristos       goto err_free;
183867d70fcSchristos     }
184867d70fcSchristos   archdr->ctfa_names = htole64 (nameoffs);
185867d70fcSchristos   np = nametbl;
186867d70fcSchristos   while (namesz > 0)
187867d70fcSchristos     {
188867d70fcSchristos       ssize_t len;
189867d70fcSchristos       if ((len = write (fd, np, namesz)) < 0)
190867d70fcSchristos 	{
191*c42dbd0eSchristos 	  errmsg = N_("ctf_arc_write(): cannot write name table to archive");
192867d70fcSchristos 	  goto err_free;
193867d70fcSchristos 	}
194867d70fcSchristos       namesz -= len;
195867d70fcSchristos       np += len;
196867d70fcSchristos     }
197867d70fcSchristos   free (nametbl);
198867d70fcSchristos 
199867d70fcSchristos   if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
200867d70fcSchristos     goto err_unmap;
201867d70fcSchristos   if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
202867d70fcSchristos     goto err;
203867d70fcSchristos   return 0;
204867d70fcSchristos 
205867d70fcSchristos err_free:
206867d70fcSchristos   free (nametbl);
207867d70fcSchristos err_unmap:
208867d70fcSchristos   arc_mmap_unmap (archdr, headersz, NULL);
209867d70fcSchristos err:
210*c42dbd0eSchristos   /* We report errors into the first file in the archive, if any: if this is a
211*c42dbd0eSchristos      zero-file archive, put it in the open-errors stream for lack of anywhere
212*c42dbd0eSchristos      else for it to go.  */
213*c42dbd0eSchristos   ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, "%s",
214*c42dbd0eSchristos 		gettext (errmsg));
215867d70fcSchristos   return errno;
216867d70fcSchristos }
217867d70fcSchristos 
218*c42dbd0eSchristos /* Write out a CTF archive.  The entries in CTF_DICTS are referenced by name:
219*c42dbd0eSchristos    the names are passed in the names array, which must have CTF_DICTS entries.
220867d70fcSchristos 
221867d70fcSchristos    If the filename is NULL, create a temporary file and return a pointer to it.
222867d70fcSchristos 
223867d70fcSchristos    Returns 0 on success, or an errno, or an ECTF_* value.  */
224867d70fcSchristos int
ctf_arc_write(const char * file,ctf_dict_t ** ctf_dicts,size_t ctf_dict_cnt,const char ** names,size_t threshold)225*c42dbd0eSchristos ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
226867d70fcSchristos 	       const char **names, size_t threshold)
227867d70fcSchristos {
228867d70fcSchristos   int err;
229867d70fcSchristos   int fd;
230867d70fcSchristos 
231867d70fcSchristos   if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
232867d70fcSchristos     {
233*c42dbd0eSchristos       ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
234*c42dbd0eSchristos 		    _("ctf_arc_write(): cannot create %s"), file);
235867d70fcSchristos       return errno;
236867d70fcSchristos     }
237867d70fcSchristos 
238*c42dbd0eSchristos   err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, names, threshold);
239867d70fcSchristos   if (err)
240*c42dbd0eSchristos     goto err_close;
241867d70fcSchristos 
242867d70fcSchristos   if ((err = close (fd)) < 0)
243*c42dbd0eSchristos     ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno,
244*c42dbd0eSchristos 		  _("ctf_arc_write(): cannot close after writing to archive"));
245*c42dbd0eSchristos   goto err;
246867d70fcSchristos 
247867d70fcSchristos  err_close:
248*c42dbd0eSchristos   (void) close (fd);
249*c42dbd0eSchristos  err:
250867d70fcSchristos   if (err < 0)
251867d70fcSchristos     unlink (file);
252867d70fcSchristos 
253867d70fcSchristos   return err;
254867d70fcSchristos }
255867d70fcSchristos 
256867d70fcSchristos /* Write one CTF file out.  Return the file position of the written file (or
257867d70fcSchristos    rather, of the file-size uint64_t that precedes it): negative return is a
258867d70fcSchristos    negative errno or ctf_errno value.  On error, the file position may no longer
259867d70fcSchristos    be at the end of the file.  */
260867d70fcSchristos static off_t
arc_write_one_ctf(ctf_dict_t * f,int fd,size_t threshold)261*c42dbd0eSchristos arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold)
262867d70fcSchristos {
263867d70fcSchristos   off_t off, end_off;
264867d70fcSchristos   uint64_t ctfsz = 0;
265867d70fcSchristos   char *ctfszp;
266867d70fcSchristos   size_t ctfsz_len;
267*c42dbd0eSchristos   int (*writefn) (ctf_dict_t * fp, int fd);
268867d70fcSchristos 
269867d70fcSchristos   if (ctf_serialize (f) < 0)
270867d70fcSchristos     return f->ctf_errno * -1;
271867d70fcSchristos 
272867d70fcSchristos   if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
273867d70fcSchristos     return errno * -1;
274867d70fcSchristos 
275867d70fcSchristos   if (f->ctf_size > threshold)
276867d70fcSchristos     writefn = ctf_compress_write;
277867d70fcSchristos   else
278867d70fcSchristos     writefn = ctf_write;
279867d70fcSchristos 
280867d70fcSchristos   /* This zero-write turns into the size in a moment. */
281867d70fcSchristos   ctfsz_len = sizeof (ctfsz);
282867d70fcSchristos   ctfszp = (char *) &ctfsz;
283867d70fcSchristos   while (ctfsz_len > 0)
284867d70fcSchristos     {
285867d70fcSchristos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
286867d70fcSchristos       if (writelen < 0)
287867d70fcSchristos 	return errno * -1;
288867d70fcSchristos       ctfsz_len -= writelen;
289867d70fcSchristos       ctfszp += writelen;
290867d70fcSchristos     }
291867d70fcSchristos 
292867d70fcSchristos   if (writefn (f, fd) != 0)
293867d70fcSchristos     return f->ctf_errno * -1;
294867d70fcSchristos 
295867d70fcSchristos   if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
296867d70fcSchristos     return errno * -1;
297867d70fcSchristos   ctfsz = htole64 (end_off - off);
298867d70fcSchristos 
299867d70fcSchristos   if ((lseek (fd, off, SEEK_SET)) < 0)
300867d70fcSchristos     return errno * -1;
301867d70fcSchristos 
302867d70fcSchristos   /* ... here.  */
303867d70fcSchristos   ctfsz_len = sizeof (ctfsz);
304867d70fcSchristos   ctfszp = (char *) &ctfsz;
305867d70fcSchristos   while (ctfsz_len > 0)
306867d70fcSchristos     {
307867d70fcSchristos       ssize_t writelen = write (fd, ctfszp, ctfsz_len);
308867d70fcSchristos       if (writelen < 0)
309867d70fcSchristos 	return errno * -1;
310867d70fcSchristos       ctfsz_len -= writelen;
311867d70fcSchristos       ctfszp += writelen;
312867d70fcSchristos     }
313867d70fcSchristos 
314867d70fcSchristos   end_off = LCTF_ALIGN_OFFS (end_off, 8);
315867d70fcSchristos   if ((lseek (fd, end_off, SEEK_SET)) < 0)
316867d70fcSchristos     return errno * -1;
317867d70fcSchristos 
318867d70fcSchristos   return off;
319867d70fcSchristos }
320867d70fcSchristos 
321867d70fcSchristos /* qsort() function to sort the array of struct ctf_archive_modents into
322867d70fcSchristos    ascending name order.  */
323867d70fcSchristos static int
sort_modent_by_name(const void * one,const void * two,void * n)324867d70fcSchristos sort_modent_by_name (const void *one, const void *two, void *n)
325867d70fcSchristos {
326867d70fcSchristos   const struct ctf_archive_modent *a = one;
327867d70fcSchristos   const struct ctf_archive_modent *b = two;
328867d70fcSchristos   char *nametbl = n;
329867d70fcSchristos 
330867d70fcSchristos   return strcmp (&nametbl[le64toh (a->name_offset)],
331867d70fcSchristos 		 &nametbl[le64toh (b->name_offset)]);
332867d70fcSchristos }
333867d70fcSchristos 
334*c42dbd0eSchristos /* bsearch_r() function to search for a given name in the sorted array of struct
335867d70fcSchristos    ctf_archive_modents.  */
336867d70fcSchristos static int
search_modent_by_name(const void * key,const void * ent,void * arg)337*c42dbd0eSchristos search_modent_by_name (const void *key, const void *ent, void *arg)
338867d70fcSchristos {
339867d70fcSchristos   const char *k = key;
340867d70fcSchristos   const struct ctf_archive_modent *v = ent;
341*c42dbd0eSchristos   const char *search_nametbl = arg;
342867d70fcSchristos 
343867d70fcSchristos   return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
344867d70fcSchristos }
345867d70fcSchristos 
346*c42dbd0eSchristos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
347*c42dbd0eSchristos    ctf_dict.  Closes ARC and/or FP on error.  Arrange to free the SYMSECT or
348*c42dbd0eSchristos    STRSECT, as needed, on close.  Possibly do not unmap on close.  */
349867d70fcSchristos 
350*c42dbd0eSchristos struct ctf_archive_internal *
ctf_new_archive_internal(int is_archive,int unmap_on_close,struct ctf_archive * arc,ctf_dict_t * fp,const ctf_sect_t * symsect,const ctf_sect_t * strsect,int * errp)351*c42dbd0eSchristos ctf_new_archive_internal (int is_archive, int unmap_on_close,
352*c42dbd0eSchristos 			  struct ctf_archive *arc,
353*c42dbd0eSchristos 			  ctf_dict_t *fp, const ctf_sect_t *symsect,
354*c42dbd0eSchristos 			  const ctf_sect_t *strsect,
355*c42dbd0eSchristos 			  int *errp)
356867d70fcSchristos {
357*c42dbd0eSchristos   struct ctf_archive_internal *arci;
358*c42dbd0eSchristos 
359*c42dbd0eSchristos   if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
360*c42dbd0eSchristos     {
361*c42dbd0eSchristos       if (is_archive)
362*c42dbd0eSchristos 	{
363*c42dbd0eSchristos 	  if (unmap_on_close)
364*c42dbd0eSchristos 	    ctf_arc_close_internal (arc);
365*c42dbd0eSchristos 	}
366*c42dbd0eSchristos       else
367*c42dbd0eSchristos 	ctf_dict_close (fp);
368*c42dbd0eSchristos       return (ctf_set_open_errno (errp, errno));
369*c42dbd0eSchristos     }
370*c42dbd0eSchristos   arci->ctfi_is_archive = is_archive;
371*c42dbd0eSchristos   if (is_archive)
372*c42dbd0eSchristos     arci->ctfi_archive = arc;
373*c42dbd0eSchristos   else
374*c42dbd0eSchristos     arci->ctfi_dict = fp;
375*c42dbd0eSchristos   if (symsect)
376*c42dbd0eSchristos      memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect));
377*c42dbd0eSchristos   if (strsect)
378*c42dbd0eSchristos      memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
379*c42dbd0eSchristos   arci->ctfi_free_symsect = 0;
380*c42dbd0eSchristos   arci->ctfi_free_strsect = 0;
381*c42dbd0eSchristos   arci->ctfi_unmap_on_close = unmap_on_close;
382*c42dbd0eSchristos   arci->ctfi_symsect_little_endian = -1;
383*c42dbd0eSchristos 
384*c42dbd0eSchristos   return arci;
385*c42dbd0eSchristos }
386*c42dbd0eSchristos 
387*c42dbd0eSchristos /* Set the symbol-table endianness of an archive (defaulting the symtab
388*c42dbd0eSchristos    endianness of all ctf_file_t's opened from that archive).  */
389*c42dbd0eSchristos void
ctf_arc_symsect_endianness(ctf_archive_t * arc,int little_endian)390*c42dbd0eSchristos ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian)
391*c42dbd0eSchristos {
392*c42dbd0eSchristos   arc->ctfi_symsect_little_endian = !!little_endian;
393*c42dbd0eSchristos   if (!arc->ctfi_is_archive)
394*c42dbd0eSchristos     ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian);
395*c42dbd0eSchristos }
396*c42dbd0eSchristos 
397*c42dbd0eSchristos /* Get the CTF preamble from data in a buffer, which may be either an archive or
398*c42dbd0eSchristos    a CTF dict.  If multiple dicts are present in an archive, the preamble comes
399*c42dbd0eSchristos    from an arbitrary dict.  The preamble is a pointer into the ctfsect passed
400*c42dbd0eSchristos    in.  */
401*c42dbd0eSchristos 
402*c42dbd0eSchristos const ctf_preamble_t *
ctf_arc_bufpreamble(const ctf_sect_t * ctfsect)403*c42dbd0eSchristos ctf_arc_bufpreamble (const ctf_sect_t *ctfsect)
404*c42dbd0eSchristos {
405*c42dbd0eSchristos   if (ctfsect->cts_size > sizeof (uint64_t) &&
406*c42dbd0eSchristos       (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
407*c42dbd0eSchristos     {
408*c42dbd0eSchristos       struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data;
409*c42dbd0eSchristos       return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs)
410*c42dbd0eSchristos 				       + sizeof (uint64_t));
411*c42dbd0eSchristos     }
412*c42dbd0eSchristos   else
413*c42dbd0eSchristos     return (const ctf_preamble_t *) ctfsect->cts_data;
414*c42dbd0eSchristos }
415*c42dbd0eSchristos 
416*c42dbd0eSchristos /* Open a CTF archive or dictionary from data in a buffer (which the caller must
417*c42dbd0eSchristos    preserve until ctf_arc_close() time).  Returns the archive, or NULL and an
418*c42dbd0eSchristos    error in *err (if not NULL).  */
419*c42dbd0eSchristos ctf_archive_t *
ctf_arc_bufopen(const ctf_sect_t * ctfsect,const ctf_sect_t * symsect,const ctf_sect_t * strsect,int * errp)420*c42dbd0eSchristos ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
421*c42dbd0eSchristos 		 const ctf_sect_t *strsect, int *errp)
422*c42dbd0eSchristos {
423*c42dbd0eSchristos   struct ctf_archive *arc = NULL;
424*c42dbd0eSchristos   int is_archive;
425*c42dbd0eSchristos   ctf_dict_t *fp = NULL;
426*c42dbd0eSchristos 
427*c42dbd0eSchristos   if (ctfsect->cts_size > sizeof (uint64_t) &&
428*c42dbd0eSchristos       (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC))
429*c42dbd0eSchristos     {
430*c42dbd0eSchristos       /* The archive is mmappable, so this operation is trivial.
431*c42dbd0eSchristos 
432*c42dbd0eSchristos 	 This buffer is nonmodifiable, so the trick involving mmapping only part
433*c42dbd0eSchristos 	 of it and storing the length in the magic number is not applicable: so
434*c42dbd0eSchristos 	 record this fact in the archive-wrapper header.  (We cannot record it
435*c42dbd0eSchristos 	 in the archive, because the archive may very well be a read-only
436*c42dbd0eSchristos 	 mapping.)  */
437*c42dbd0eSchristos 
438*c42dbd0eSchristos       is_archive = 1;
439*c42dbd0eSchristos       arc = (struct ctf_archive *) ctfsect->cts_data;
440*c42dbd0eSchristos     }
441*c42dbd0eSchristos   else
442*c42dbd0eSchristos     {
443*c42dbd0eSchristos       is_archive = 0;
444*c42dbd0eSchristos       if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL)
445*c42dbd0eSchristos 	{
446*c42dbd0eSchristos 	  ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF"));
447867d70fcSchristos 	  return NULL;
448867d70fcSchristos 	}
449*c42dbd0eSchristos     }
450*c42dbd0eSchristos   return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect,
451*c42dbd0eSchristos 				   errp);
452867d70fcSchristos }
453867d70fcSchristos 
454867d70fcSchristos /* Open a CTF archive.  Returns the archive, or NULL and an error in *err (if
455867d70fcSchristos    not NULL).  */
456867d70fcSchristos struct ctf_archive *
ctf_arc_open_internal(const char * filename,int * errp)457867d70fcSchristos ctf_arc_open_internal (const char *filename, int *errp)
458867d70fcSchristos {
459867d70fcSchristos   const char *errmsg;
460867d70fcSchristos   int fd;
461867d70fcSchristos   struct stat s;
462867d70fcSchristos   struct ctf_archive *arc;		/* (Actually the whole file.)  */
463867d70fcSchristos 
464867d70fcSchristos   libctf_init_debug();
465867d70fcSchristos   if ((fd = open (filename, O_RDONLY)) < 0)
466867d70fcSchristos     {
467*c42dbd0eSchristos       errmsg = N_("ctf_arc_open(): cannot open %s");
468867d70fcSchristos       goto err;
469867d70fcSchristos     }
470867d70fcSchristos   if (fstat (fd, &s) < 0)
471867d70fcSchristos     {
472*c42dbd0eSchristos       errmsg = N_("ctf_arc_open(): cannot stat %s");
473867d70fcSchristos       goto err_close;
474867d70fcSchristos     }
475867d70fcSchristos 
476867d70fcSchristos   if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
477867d70fcSchristos     {
478*c42dbd0eSchristos       errmsg = N_("ctf_arc_open(): cannot read in %s");
479867d70fcSchristos       goto err_close;
480867d70fcSchristos     }
481867d70fcSchristos 
482867d70fcSchristos   if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
483867d70fcSchristos     {
484*c42dbd0eSchristos       errmsg = N_("ctf_arc_open(): %s: invalid magic number");
485867d70fcSchristos       errno = ECTF_FMT;
486867d70fcSchristos       goto err_unmap;
487867d70fcSchristos     }
488867d70fcSchristos 
489867d70fcSchristos   /* This horrible hack lets us know how much to unmap when the file is
490867d70fcSchristos      closed.  (We no longer need the magic number, and the mapping
491867d70fcSchristos      is private.)  */
492867d70fcSchristos   arc->ctfa_magic = s.st_size;
493867d70fcSchristos   close (fd);
494867d70fcSchristos   return arc;
495867d70fcSchristos 
496867d70fcSchristos err_unmap:
497867d70fcSchristos   arc_mmap_unmap (arc, s.st_size, NULL);
498867d70fcSchristos err_close:
499867d70fcSchristos   close (fd);
500867d70fcSchristos err:
501867d70fcSchristos   if (errp)
502867d70fcSchristos     *errp = errno;
503*c42dbd0eSchristos   ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename);
504867d70fcSchristos   return NULL;
505867d70fcSchristos }
506867d70fcSchristos 
507867d70fcSchristos /* Close an archive.  */
508867d70fcSchristos void
ctf_arc_close_internal(struct ctf_archive * arc)509867d70fcSchristos ctf_arc_close_internal (struct ctf_archive *arc)
510867d70fcSchristos {
511867d70fcSchristos   if (arc == NULL)
512867d70fcSchristos     return;
513867d70fcSchristos 
514867d70fcSchristos   /* See the comment in ctf_arc_open().  */
515867d70fcSchristos   arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
516867d70fcSchristos }
517867d70fcSchristos 
518867d70fcSchristos /* Public entry point: close an archive, or CTF file.  */
519867d70fcSchristos void
ctf_arc_close(ctf_archive_t * arc)520867d70fcSchristos ctf_arc_close (ctf_archive_t *arc)
521867d70fcSchristos {
522867d70fcSchristos   if (arc == NULL)
523867d70fcSchristos     return;
524867d70fcSchristos 
525867d70fcSchristos   if (arc->ctfi_is_archive)
526*c42dbd0eSchristos     {
527*c42dbd0eSchristos       if (arc->ctfi_unmap_on_close)
528867d70fcSchristos 	ctf_arc_close_internal (arc->ctfi_archive);
529*c42dbd0eSchristos     }
530867d70fcSchristos   else
531*c42dbd0eSchristos     ctf_dict_close (arc->ctfi_dict);
532*c42dbd0eSchristos   free (arc->ctfi_symdicts);
533*c42dbd0eSchristos   free (arc->ctfi_symnamedicts);
534*c42dbd0eSchristos   ctf_dynhash_destroy (arc->ctfi_dicts);
535*c42dbd0eSchristos   if (arc->ctfi_free_symsect)
536867d70fcSchristos     free ((void *) arc->ctfi_symsect.cts_data);
537*c42dbd0eSchristos   if (arc->ctfi_free_strsect)
538*c42dbd0eSchristos     free ((void *) arc->ctfi_strsect.cts_data);
539867d70fcSchristos   free (arc->ctfi_data);
540867d70fcSchristos   if (arc->ctfi_bfd_close)
541867d70fcSchristos     arc->ctfi_bfd_close (arc);
542867d70fcSchristos   free (arc);
543867d70fcSchristos }
544867d70fcSchristos 
545*c42dbd0eSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
546867d70fcSchristos    non-NULL.  A name of NULL means to open the default file.  */
547*c42dbd0eSchristos static ctf_dict_t *
ctf_dict_open_internal(const struct ctf_archive * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,const char * name,int little_endian,int * errp)548*c42dbd0eSchristos ctf_dict_open_internal (const struct ctf_archive *arc,
549867d70fcSchristos 			const ctf_sect_t *symsect,
550867d70fcSchristos 			const ctf_sect_t *strsect,
551*c42dbd0eSchristos 			const char *name, int little_endian,
552*c42dbd0eSchristos 			int *errp)
553867d70fcSchristos {
554867d70fcSchristos   struct ctf_archive_modent *modent;
555*c42dbd0eSchristos   const char *search_nametbl;
556867d70fcSchristos 
557867d70fcSchristos   if (name == NULL)
558867d70fcSchristos     name = _CTF_SECTION;		 /* The default name.  */
559867d70fcSchristos 
560*c42dbd0eSchristos   ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name);
561867d70fcSchristos 
562867d70fcSchristos   modent = (ctf_archive_modent_t *) ((char *) arc
563867d70fcSchristos 				     + sizeof (struct ctf_archive));
564867d70fcSchristos 
565*c42dbd0eSchristos   search_nametbl = (const char *) arc + le64toh (arc->ctfa_names);
566*c42dbd0eSchristos   modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts),
567867d70fcSchristos 		      sizeof (struct ctf_archive_modent),
568*c42dbd0eSchristos 		      search_modent_by_name, (void *) search_nametbl);
569867d70fcSchristos 
570867d70fcSchristos   /* This is actually a common case and normal operation: no error
571867d70fcSchristos      debug output.  */
572867d70fcSchristos   if (modent == NULL)
573867d70fcSchristos     {
574867d70fcSchristos       if (errp)
575867d70fcSchristos 	*errp = ECTF_ARNNAME;
576867d70fcSchristos       return NULL;
577867d70fcSchristos     }
578867d70fcSchristos 
579*c42dbd0eSchristos   return ctf_dict_open_by_offset (arc, symsect, strsect,
580*c42dbd0eSchristos 				  le64toh (modent->ctf_offset),
581*c42dbd0eSchristos 				  little_endian, errp);
582867d70fcSchristos }
583867d70fcSchristos 
584*c42dbd0eSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
585867d70fcSchristos    non-NULL.  A name of NULL means to open the default file.
586867d70fcSchristos 
587867d70fcSchristos    Use the specified string and symbol table sections.
588867d70fcSchristos 
589867d70fcSchristos    Public entry point.  */
590*c42dbd0eSchristos ctf_dict_t *
ctf_dict_open_sections(const ctf_archive_t * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,const char * name,int * errp)591*c42dbd0eSchristos ctf_dict_open_sections (const ctf_archive_t *arc,
592867d70fcSchristos 			const ctf_sect_t *symsect,
593867d70fcSchristos 			const ctf_sect_t *strsect,
594867d70fcSchristos 			const char *name,
595867d70fcSchristos 			int *errp)
596867d70fcSchristos {
597867d70fcSchristos   if (arc->ctfi_is_archive)
598867d70fcSchristos     {
599*c42dbd0eSchristos       ctf_dict_t *ret;
600*c42dbd0eSchristos       ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect,
601*c42dbd0eSchristos 				    name, arc->ctfi_symsect_little_endian,
602*c42dbd0eSchristos 				    errp);
603867d70fcSchristos       if (ret)
604*c42dbd0eSchristos 	{
605867d70fcSchristos 	  ret->ctf_archive = (ctf_archive_t *) arc;
606*c42dbd0eSchristos 	  ctf_arc_import_parent (arc, ret);
607*c42dbd0eSchristos 	}
608867d70fcSchristos       return ret;
609867d70fcSchristos     }
610867d70fcSchristos 
611867d70fcSchristos   if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
612867d70fcSchristos     {
613867d70fcSchristos       if (errp)
614867d70fcSchristos 	*errp = ECTF_ARNNAME;
615867d70fcSchristos       return NULL;
616867d70fcSchristos     }
617*c42dbd0eSchristos   arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc;
618867d70fcSchristos 
619*c42dbd0eSchristos   /* Bump the refcount so that the user can ctf_dict_close() it.  */
620*c42dbd0eSchristos   arc->ctfi_dict->ctf_refcnt++;
621*c42dbd0eSchristos   return arc->ctfi_dict;
622867d70fcSchristos }
623867d70fcSchristos 
624*c42dbd0eSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if
625867d70fcSchristos    non-NULL.  A name of NULL means to open the default file.
626867d70fcSchristos 
627867d70fcSchristos    Public entry point.  */
628*c42dbd0eSchristos ctf_dict_t *
ctf_dict_open(const ctf_archive_t * arc,const char * name,int * errp)629*c42dbd0eSchristos ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp)
630867d70fcSchristos {
631867d70fcSchristos   const ctf_sect_t *symsect = &arc->ctfi_symsect;
632867d70fcSchristos   const ctf_sect_t *strsect = &arc->ctfi_strsect;
633867d70fcSchristos 
634867d70fcSchristos   if (symsect->cts_name == NULL)
635867d70fcSchristos     symsect = NULL;
636867d70fcSchristos   if (strsect->cts_name == NULL)
637867d70fcSchristos     strsect = NULL;
638867d70fcSchristos 
639*c42dbd0eSchristos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
640867d70fcSchristos }
641867d70fcSchristos 
642*c42dbd0eSchristos static void
ctf_cached_dict_close(void * fp)643*c42dbd0eSchristos ctf_cached_dict_close (void *fp)
644*c42dbd0eSchristos {
645*c42dbd0eSchristos   ctf_dict_close ((ctf_dict_t *) fp);
646*c42dbd0eSchristos }
647*c42dbd0eSchristos 
648*c42dbd0eSchristos /* Return the ctf_dict_t with the given name and cache it in the archive's
649*c42dbd0eSchristos    ctfi_dicts.  If this is the first cached dict, designate it the
650*c42dbd0eSchristos    crossdict_cache.  */
651*c42dbd0eSchristos static ctf_dict_t *
ctf_dict_open_cached(ctf_archive_t * arc,const char * name,int * errp)652*c42dbd0eSchristos ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
653*c42dbd0eSchristos {
654*c42dbd0eSchristos   ctf_dict_t *fp;
655*c42dbd0eSchristos   char *dupname;
656*c42dbd0eSchristos 
657*c42dbd0eSchristos   /* Just return from the cache if possible.  */
658*c42dbd0eSchristos   if (arc->ctfi_dicts
659*c42dbd0eSchristos       && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL))
660*c42dbd0eSchristos     {
661*c42dbd0eSchristos       fp->ctf_refcnt++;
662*c42dbd0eSchristos       return fp;
663*c42dbd0eSchristos     }
664*c42dbd0eSchristos 
665*c42dbd0eSchristos   /* Not yet cached: open it.  */
666*c42dbd0eSchristos   fp = ctf_dict_open (arc, name, errp);
667*c42dbd0eSchristos   dupname = strdup (name);
668*c42dbd0eSchristos 
669*c42dbd0eSchristos   if (!fp || !dupname)
670*c42dbd0eSchristos     goto oom;
671*c42dbd0eSchristos 
672*c42dbd0eSchristos   if (arc->ctfi_dicts == NULL)
673*c42dbd0eSchristos     if ((arc->ctfi_dicts
674*c42dbd0eSchristos 	 = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
675*c42dbd0eSchristos 			       free, ctf_cached_dict_close)) == NULL)
676*c42dbd0eSchristos       goto oom;
677*c42dbd0eSchristos 
678*c42dbd0eSchristos   if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0)
679*c42dbd0eSchristos     goto oom;
680*c42dbd0eSchristos   fp->ctf_refcnt++;
681*c42dbd0eSchristos 
682*c42dbd0eSchristos   if (arc->ctfi_crossdict_cache == NULL)
683*c42dbd0eSchristos     arc->ctfi_crossdict_cache = fp;
684*c42dbd0eSchristos 
685*c42dbd0eSchristos   return fp;
686*c42dbd0eSchristos 
687*c42dbd0eSchristos  oom:
688*c42dbd0eSchristos   ctf_dict_close (fp);
689*c42dbd0eSchristos   free (dupname);
690*c42dbd0eSchristos   if (errp)
691*c42dbd0eSchristos     *errp = ENOMEM;
692*c42dbd0eSchristos   return NULL;
693*c42dbd0eSchristos }
694*c42dbd0eSchristos 
695*c42dbd0eSchristos /* Flush any caches the CTF archive may have open.  */
696*c42dbd0eSchristos void
ctf_arc_flush_caches(ctf_archive_t * wrapper)697*c42dbd0eSchristos ctf_arc_flush_caches (ctf_archive_t *wrapper)
698*c42dbd0eSchristos {
699*c42dbd0eSchristos   free (wrapper->ctfi_symdicts);
700*c42dbd0eSchristos   free (wrapper->ctfi_symnamedicts);
701*c42dbd0eSchristos   ctf_dynhash_destroy (wrapper->ctfi_dicts);
702*c42dbd0eSchristos   wrapper->ctfi_symdicts = NULL;
703*c42dbd0eSchristos   wrapper->ctfi_symnamedicts = NULL;
704*c42dbd0eSchristos   wrapper->ctfi_dicts = NULL;
705*c42dbd0eSchristos   wrapper->ctfi_crossdict_cache = NULL;
706*c42dbd0eSchristos }
707*c42dbd0eSchristos 
708*c42dbd0eSchristos /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if
709867d70fcSchristos    none, setting 'err' if non-NULL.  */
710*c42dbd0eSchristos static ctf_dict_t *
ctf_dict_open_by_offset(const struct ctf_archive * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,size_t offset,int little_endian,int * errp)711*c42dbd0eSchristos ctf_dict_open_by_offset (const struct ctf_archive *arc,
712867d70fcSchristos 			 const ctf_sect_t *symsect,
713867d70fcSchristos 			 const ctf_sect_t *strsect, size_t offset,
714*c42dbd0eSchristos 			 int little_endian, int *errp)
715867d70fcSchristos {
716867d70fcSchristos   ctf_sect_t ctfsect;
717*c42dbd0eSchristos   ctf_dict_t *fp;
718867d70fcSchristos 
719*c42dbd0eSchristos   ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset);
720867d70fcSchristos 
721867d70fcSchristos   memset (&ctfsect, 0, sizeof (ctf_sect_t));
722867d70fcSchristos 
723867d70fcSchristos   offset += le64toh (arc->ctfa_ctfs);
724867d70fcSchristos 
725867d70fcSchristos   ctfsect.cts_name = _CTF_SECTION;
726867d70fcSchristos   ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
727867d70fcSchristos   ctfsect.cts_entsize = 1;
728867d70fcSchristos   ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
729867d70fcSchristos   fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
730867d70fcSchristos   if (fp)
731*c42dbd0eSchristos     {
732867d70fcSchristos       ctf_setmodel (fp, le64toh (arc->ctfa_model));
733*c42dbd0eSchristos       if (little_endian >= 0)
734*c42dbd0eSchristos 	ctf_symsect_endianness (fp, little_endian);
735*c42dbd0eSchristos     }
736867d70fcSchristos   return fp;
737867d70fcSchristos }
738867d70fcSchristos 
739*c42dbd0eSchristos /* Backward compatibility.  */
740*c42dbd0eSchristos ctf_dict_t *
ctf_arc_open_by_name(const ctf_archive_t * arc,const char * name,int * errp)741*c42dbd0eSchristos ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name,
742*c42dbd0eSchristos 		      int *errp)
743*c42dbd0eSchristos {
744*c42dbd0eSchristos   return ctf_dict_open (arc, name, errp);
745*c42dbd0eSchristos }
746*c42dbd0eSchristos 
747*c42dbd0eSchristos ctf_dict_t *
ctf_arc_open_by_name_sections(const ctf_archive_t * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,const char * name,int * errp)748*c42dbd0eSchristos ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
749*c42dbd0eSchristos 			       const ctf_sect_t *symsect,
750*c42dbd0eSchristos 			       const ctf_sect_t *strsect,
751*c42dbd0eSchristos 			       const char *name,
752*c42dbd0eSchristos 			       int *errp)
753*c42dbd0eSchristos {
754*c42dbd0eSchristos   return ctf_dict_open_sections (arc, symsect, strsect, name, errp);
755*c42dbd0eSchristos }
756*c42dbd0eSchristos 
757*c42dbd0eSchristos /* Import the parent into a ctf archive, if this is a child, the parent is not
758*c42dbd0eSchristos    already set, and a suitable archive member exists.  No error is raised if
759*c42dbd0eSchristos    this is not possible: this is just a best-effort helper operation to give
760*c42dbd0eSchristos    people useful dicts to start with.  */
761*c42dbd0eSchristos static void
ctf_arc_import_parent(const ctf_archive_t * arc,ctf_dict_t * fp)762*c42dbd0eSchristos ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp)
763*c42dbd0eSchristos {
764*c42dbd0eSchristos   if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent)
765*c42dbd0eSchristos     {
766*c42dbd0eSchristos       ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc,
767*c42dbd0eSchristos 						 fp->ctf_parname, NULL);
768*c42dbd0eSchristos       if (parent)
769*c42dbd0eSchristos 	{
770*c42dbd0eSchristos 	  ctf_import (fp, parent);
771*c42dbd0eSchristos 	  ctf_dict_close (parent);
772*c42dbd0eSchristos 	}
773*c42dbd0eSchristos     }
774*c42dbd0eSchristos }
775*c42dbd0eSchristos 
776*c42dbd0eSchristos /* Return the number of members in an archive.  */
777*c42dbd0eSchristos size_t
ctf_archive_count(const ctf_archive_t * wrapper)778*c42dbd0eSchristos ctf_archive_count (const ctf_archive_t *wrapper)
779*c42dbd0eSchristos {
780*c42dbd0eSchristos   if (!wrapper->ctfi_is_archive)
781*c42dbd0eSchristos     return 1;
782*c42dbd0eSchristos 
783*c42dbd0eSchristos   return wrapper->ctfi_archive->ctfa_ndicts;
784*c42dbd0eSchristos }
785*c42dbd0eSchristos 
786*c42dbd0eSchristos /* Look up a symbol in an archive by name or index (if the name is set, a lookup
787*c42dbd0eSchristos    by name is done).  Return the dict in the archive that the symbol is found
788*c42dbd0eSchristos    in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't
789*c42dbd0eSchristos    have to look it up yourself).  The dict is cached, so repeated lookups are
790*c42dbd0eSchristos    nearly free.
791*c42dbd0eSchristos 
792*c42dbd0eSchristos    As usual, you should ctf_dict_close() the returned dict once you are done
793*c42dbd0eSchristos    with it.
794*c42dbd0eSchristos 
795*c42dbd0eSchristos    Returns NULL on error, and an error in errp (if set).  */
796*c42dbd0eSchristos 
797*c42dbd0eSchristos static ctf_dict_t *
ctf_arc_lookup_sym_or_name(ctf_archive_t * wrapper,unsigned long symidx,const char * symname,ctf_id_t * typep,int * errp)798*c42dbd0eSchristos ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
799*c42dbd0eSchristos 			    const char *symname, ctf_id_t *typep, int *errp)
800*c42dbd0eSchristos {
801*c42dbd0eSchristos   ctf_dict_t *fp;
802*c42dbd0eSchristos   void *fpkey;
803*c42dbd0eSchristos   ctf_id_t type;
804*c42dbd0eSchristos 
805*c42dbd0eSchristos   /* The usual non-archive-transparent-wrapper special case.  */
806*c42dbd0eSchristos   if (!wrapper->ctfi_is_archive)
807*c42dbd0eSchristos     {
808*c42dbd0eSchristos       if (!symname)
809*c42dbd0eSchristos 	{
810*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
811*c42dbd0eSchristos 	    {
812*c42dbd0eSchristos 	      if (errp)
813*c42dbd0eSchristos 		*errp = ctf_errno (wrapper->ctfi_dict);
814*c42dbd0eSchristos 	      return NULL;
815*c42dbd0eSchristos 	    }
816*c42dbd0eSchristos 	}
817*c42dbd0eSchristos       else
818*c42dbd0eSchristos 	{
819*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict,
820*c42dbd0eSchristos 						 symname)) == CTF_ERR)
821*c42dbd0eSchristos 	    {
822*c42dbd0eSchristos 	      if (errp)
823*c42dbd0eSchristos 		*errp = ctf_errno (wrapper->ctfi_dict);
824*c42dbd0eSchristos 	      return NULL;
825*c42dbd0eSchristos 	    }
826*c42dbd0eSchristos 	}
827*c42dbd0eSchristos       if (typep)
828*c42dbd0eSchristos 	*typep = type;
829*c42dbd0eSchristos       wrapper->ctfi_dict->ctf_refcnt++;
830*c42dbd0eSchristos       return wrapper->ctfi_dict;
831*c42dbd0eSchristos     }
832*c42dbd0eSchristos 
833*c42dbd0eSchristos   if (wrapper->ctfi_symsect.cts_name == NULL
834*c42dbd0eSchristos       || wrapper->ctfi_symsect.cts_data == NULL
835*c42dbd0eSchristos       || wrapper->ctfi_symsect.cts_size == 0
836*c42dbd0eSchristos       || wrapper->ctfi_symsect.cts_entsize == 0)
837*c42dbd0eSchristos     {
838*c42dbd0eSchristos       if (errp)
839*c42dbd0eSchristos 	*errp = ECTF_NOSYMTAB;
840*c42dbd0eSchristos       return NULL;
841*c42dbd0eSchristos     }
842*c42dbd0eSchristos 
843*c42dbd0eSchristos   /* Make enough space for all possible symbol indexes, if not already done.  We
844*c42dbd0eSchristos      cache the originating dictionary of all symbols.  The dict links are weak,
845*c42dbd0eSchristos      to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped.
846*c42dbd0eSchristos      We also cache similar mappings for symbol names: these are ordinary
847*c42dbd0eSchristos      dynhashes, with weak links to dicts.  */
848*c42dbd0eSchristos 
849*c42dbd0eSchristos   if (!wrapper->ctfi_symdicts)
850*c42dbd0eSchristos     {
851*c42dbd0eSchristos       if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
852*c42dbd0eSchristos 					    / wrapper->ctfi_symsect.cts_entsize,
853*c42dbd0eSchristos 					    sizeof (ctf_dict_t *))) == NULL)
854*c42dbd0eSchristos 	{
855*c42dbd0eSchristos 	  if (errp)
856*c42dbd0eSchristos 	    *errp = ENOMEM;
857*c42dbd0eSchristos 	  return NULL;
858*c42dbd0eSchristos 	}
859*c42dbd0eSchristos     }
860*c42dbd0eSchristos   if (!wrapper->ctfi_symnamedicts)
861*c42dbd0eSchristos     {
862*c42dbd0eSchristos       if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
863*c42dbd0eSchristos 							    ctf_hash_eq_string,
864*c42dbd0eSchristos 							    free, NULL)) == NULL)
865*c42dbd0eSchristos 	{
866*c42dbd0eSchristos 	  if (errp)
867*c42dbd0eSchristos 	    *errp = ENOMEM;
868*c42dbd0eSchristos 	  return NULL;
869*c42dbd0eSchristos 	}
870*c42dbd0eSchristos     }
871*c42dbd0eSchristos 
872*c42dbd0eSchristos   /* Perhaps the dict in which we found a previous lookup is cached.  If it's
873*c42dbd0eSchristos      supposed to be cached but we don't find it, pretend it was always not
874*c42dbd0eSchristos      found: this should never happen, but shouldn't be allowed to cause trouble
875*c42dbd0eSchristos      if it does.  */
876*c42dbd0eSchristos 
877*c42dbd0eSchristos   if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts,
878*c42dbd0eSchristos 					 symname, NULL, &fpkey))
879*c42dbd0eSchristos       || (!symname && wrapper->ctfi_symdicts[symidx] != NULL))
880*c42dbd0eSchristos     {
881*c42dbd0eSchristos       if (symname)
882*c42dbd0eSchristos 	fp = (ctf_dict_t *) fpkey;
883*c42dbd0eSchristos       else
884*c42dbd0eSchristos 	fp = wrapper->ctfi_symdicts[symidx];
885*c42dbd0eSchristos 
886*c42dbd0eSchristos       if (fp == &enosym)
887*c42dbd0eSchristos 	goto no_sym;
888*c42dbd0eSchristos 
889*c42dbd0eSchristos       if (symname)
890*c42dbd0eSchristos 	{
891*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR)
892*c42dbd0eSchristos 	    goto cache_no_sym;
893*c42dbd0eSchristos 	}
894*c42dbd0eSchristos       else
895*c42dbd0eSchristos 	{
896*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
897*c42dbd0eSchristos 	    goto cache_no_sym;
898*c42dbd0eSchristos 	}
899*c42dbd0eSchristos 
900*c42dbd0eSchristos       if (typep)
901*c42dbd0eSchristos 	*typep = type;
902*c42dbd0eSchristos       fp->ctf_refcnt++;
903*c42dbd0eSchristos       return fp;
904*c42dbd0eSchristos     }
905*c42dbd0eSchristos 
906*c42dbd0eSchristos   /* Not cached: find it and cache it.  We must track open errors ourselves even
907*c42dbd0eSchristos      if our caller doesn't, to be able to distinguish no-error end-of-iteration
908*c42dbd0eSchristos      from open errors.  */
909*c42dbd0eSchristos 
910*c42dbd0eSchristos   int local_err;
911*c42dbd0eSchristos   int *local_errp;
912*c42dbd0eSchristos   ctf_next_t *i = NULL;
913*c42dbd0eSchristos   const char *name;
914*c42dbd0eSchristos 
915*c42dbd0eSchristos   if (errp)
916*c42dbd0eSchristos     local_errp = errp;
917*c42dbd0eSchristos   else
918*c42dbd0eSchristos     local_errp = &local_err;
919*c42dbd0eSchristos 
920*c42dbd0eSchristos   while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL)
921*c42dbd0eSchristos     {
922*c42dbd0eSchristos       if (!symname)
923*c42dbd0eSchristos 	{
924*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
925*c42dbd0eSchristos 	    wrapper->ctfi_symdicts[symidx] = fp;
926*c42dbd0eSchristos 	}
927*c42dbd0eSchristos       else
928*c42dbd0eSchristos 	{
929*c42dbd0eSchristos 	  if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR)
930*c42dbd0eSchristos 	    {
931*c42dbd0eSchristos 	      char *tmp;
932*c42dbd0eSchristos 	      /* No error checking, as above.  */
933*c42dbd0eSchristos 	      if ((tmp = strdup (symname)) != NULL)
934*c42dbd0eSchristos 		ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp);
935*c42dbd0eSchristos 	    }
936*c42dbd0eSchristos 	}
937*c42dbd0eSchristos 
938*c42dbd0eSchristos       if (type != CTF_ERR)
939*c42dbd0eSchristos 	{
940*c42dbd0eSchristos 	  if (typep)
941*c42dbd0eSchristos 	    *typep = type;
942*c42dbd0eSchristos 	  ctf_next_destroy (i);
943*c42dbd0eSchristos 	  return fp;
944*c42dbd0eSchristos 	}
945*c42dbd0eSchristos       if (ctf_errno (fp) != ECTF_NOTYPEDAT)
946*c42dbd0eSchristos 	{
947*c42dbd0eSchristos 	  if (errp)
948*c42dbd0eSchristos 	    *errp = ctf_errno (fp);
949*c42dbd0eSchristos 	  ctf_next_destroy (i);
950*c42dbd0eSchristos 	  return NULL;				/* errno is set for us.  */
951*c42dbd0eSchristos 	}
952*c42dbd0eSchristos       ctf_dict_close (fp);
953*c42dbd0eSchristos     }
954*c42dbd0eSchristos   if (*local_errp != ECTF_NEXT_END)
955*c42dbd0eSchristos     {
956*c42dbd0eSchristos       ctf_next_destroy (i);
957*c42dbd0eSchristos       return NULL;
958*c42dbd0eSchristos     }
959*c42dbd0eSchristos 
960*c42dbd0eSchristos   /* Don't leak end-of-iteration to the caller.  */
961*c42dbd0eSchristos   *local_errp = 0;
962*c42dbd0eSchristos 
963*c42dbd0eSchristos  cache_no_sym:
964*c42dbd0eSchristos   if (!symname)
965*c42dbd0eSchristos     wrapper->ctfi_symdicts[symidx] = &enosym;
966*c42dbd0eSchristos   else
967*c42dbd0eSchristos     {
968*c42dbd0eSchristos       char *tmp;
969*c42dbd0eSchristos 
970*c42dbd0eSchristos       /* No error checking: if caching fails, there is only a slight performance
971*c42dbd0eSchristos 	 impact.  */
972*c42dbd0eSchristos       if ((tmp = strdup (symname)) != NULL)
973*c42dbd0eSchristos 	if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0)
974*c42dbd0eSchristos 	  free (tmp);
975*c42dbd0eSchristos     }
976*c42dbd0eSchristos 
977*c42dbd0eSchristos  no_sym:
978*c42dbd0eSchristos   if (errp)
979*c42dbd0eSchristos     *errp = ECTF_NOTYPEDAT;
980*c42dbd0eSchristos   if (typep)
981*c42dbd0eSchristos     *typep = CTF_ERR;
982*c42dbd0eSchristos   return NULL;
983*c42dbd0eSchristos }
984*c42dbd0eSchristos 
985*c42dbd0eSchristos /* The public API for looking up a symbol by index.  */
986*c42dbd0eSchristos ctf_dict_t *
ctf_arc_lookup_symbol(ctf_archive_t * wrapper,unsigned long symidx,ctf_id_t * typep,int * errp)987*c42dbd0eSchristos ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
988*c42dbd0eSchristos 		       ctf_id_t *typep, int *errp)
989*c42dbd0eSchristos {
990*c42dbd0eSchristos   return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp);
991*c42dbd0eSchristos }
992*c42dbd0eSchristos 
993*c42dbd0eSchristos /* The public API for looking up a symbol by name. */
994*c42dbd0eSchristos 
995*c42dbd0eSchristos ctf_dict_t *
ctf_arc_lookup_symbol_name(ctf_archive_t * wrapper,const char * symname,ctf_id_t * typep,int * errp)996*c42dbd0eSchristos ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
997*c42dbd0eSchristos 			    ctf_id_t *typep, int *errp)
998*c42dbd0eSchristos {
999*c42dbd0eSchristos   return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
1000*c42dbd0eSchristos }
1001*c42dbd0eSchristos 
1002867d70fcSchristos /* Raw iteration over all CTF files in an archive.  We pass the raw data for all
1003867d70fcSchristos    CTF files in turn to the specified callback function.  */
1004867d70fcSchristos static int
ctf_archive_raw_iter_internal(const struct ctf_archive * arc,ctf_archive_raw_member_f * func,void * data)1005867d70fcSchristos ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
1006867d70fcSchristos 			       ctf_archive_raw_member_f *func, void *data)
1007867d70fcSchristos {
1008867d70fcSchristos   int rc;
1009867d70fcSchristos   size_t i;
1010867d70fcSchristos   struct ctf_archive_modent *modent;
1011867d70fcSchristos   const char *nametbl;
1012867d70fcSchristos 
1013867d70fcSchristos   modent = (ctf_archive_modent_t *) ((char *) arc
1014867d70fcSchristos 				     + sizeof (struct ctf_archive));
1015867d70fcSchristos   nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
1016867d70fcSchristos 
1017*c42dbd0eSchristos   for (i = 0; i < le64toh (arc->ctfa_ndicts); i++)
1018867d70fcSchristos     {
1019867d70fcSchristos       const char *name;
1020867d70fcSchristos       char *fp;
1021867d70fcSchristos 
1022867d70fcSchristos       name = &nametbl[le64toh (modent[i].name_offset)];
1023867d70fcSchristos       fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
1024867d70fcSchristos 	    + le64toh (modent[i].ctf_offset));
1025867d70fcSchristos 
1026867d70fcSchristos       if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
1027867d70fcSchristos 		      le64toh (*((uint64_t *) fp)), data)) != 0)
1028867d70fcSchristos 	return rc;
1029867d70fcSchristos     }
1030867d70fcSchristos   return 0;
1031867d70fcSchristos }
1032867d70fcSchristos 
1033867d70fcSchristos /* Raw iteration over all CTF files in an archive: public entry point.
1034867d70fcSchristos 
1035867d70fcSchristos    Returns -EINVAL if not supported for this sort of archive.  */
1036867d70fcSchristos int
ctf_archive_raw_iter(const ctf_archive_t * arc,ctf_archive_raw_member_f * func,void * data)1037867d70fcSchristos ctf_archive_raw_iter (const ctf_archive_t *arc,
1038867d70fcSchristos 		      ctf_archive_raw_member_f * func, void *data)
1039867d70fcSchristos {
1040867d70fcSchristos   if (arc->ctfi_is_archive)
1041867d70fcSchristos     return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
1042867d70fcSchristos 
1043867d70fcSchristos   return -EINVAL;			 /* Not supported. */
1044867d70fcSchristos }
1045867d70fcSchristos 
1046867d70fcSchristos /* Iterate over all CTF files in an archive: public entry point.  We pass all
1047867d70fcSchristos    CTF files in turn to the specified callback function.  */
1048867d70fcSchristos int
ctf_archive_iter(const ctf_archive_t * arc,ctf_archive_member_f * func,void * data)1049867d70fcSchristos ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
1050867d70fcSchristos 		  void *data)
1051867d70fcSchristos {
1052*c42dbd0eSchristos   ctf_next_t *i = NULL;
1053*c42dbd0eSchristos   ctf_dict_t *fp;
1054*c42dbd0eSchristos   const char *name;
1055*c42dbd0eSchristos   int err;
1056867d70fcSchristos 
1057*c42dbd0eSchristos   while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL)
1058*c42dbd0eSchristos     {
1059*c42dbd0eSchristos       int rc;
1060867d70fcSchristos 
1061*c42dbd0eSchristos       if ((rc = func (fp, name, data)) != 0)
1062*c42dbd0eSchristos 	{
1063*c42dbd0eSchristos 	  ctf_dict_close (fp);
1064*c42dbd0eSchristos 	  ctf_next_destroy (i);
1065*c42dbd0eSchristos 	  return rc;
1066*c42dbd0eSchristos 	}
1067*c42dbd0eSchristos       ctf_dict_close (fp);
1068*c42dbd0eSchristos     }
1069*c42dbd0eSchristos   return 0;
1070*c42dbd0eSchristos }
1071867d70fcSchristos 
1072*c42dbd0eSchristos /* Iterate over all CTF files in an archive, returning each dict in turn as a
1073*c42dbd0eSchristos    ctf_dict_t, and NULL on error or end of iteration.  It is the caller's
1074*c42dbd0eSchristos    responsibility to close it.  Parent dicts may be skipped.
1075*c42dbd0eSchristos 
1076*c42dbd0eSchristos    The archive member is cached for rapid return on future calls.
1077*c42dbd0eSchristos 
1078*c42dbd0eSchristos    We identify parents by name rather than by flag value: for now, with the
1079*c42dbd0eSchristos    linker only emitting parents named _CTF_SECTION, this works well enough.  */
1080*c42dbd0eSchristos 
1081*c42dbd0eSchristos ctf_dict_t *
ctf_archive_next(const ctf_archive_t * wrapper,ctf_next_t ** it,const char ** name,int skip_parent,int * errp)1082*c42dbd0eSchristos ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name,
1083*c42dbd0eSchristos 		  int skip_parent, int *errp)
1084*c42dbd0eSchristos {
1085*c42dbd0eSchristos   ctf_dict_t *f;
1086*c42dbd0eSchristos   ctf_next_t *i = *it;
1087*c42dbd0eSchristos   struct ctf_archive *arc;
1088*c42dbd0eSchristos   struct ctf_archive_modent *modent;
1089*c42dbd0eSchristos   const char *nametbl;
1090*c42dbd0eSchristos   const char *name_;
1091*c42dbd0eSchristos 
1092*c42dbd0eSchristos   if (!i)
1093*c42dbd0eSchristos     {
1094*c42dbd0eSchristos       if ((i = ctf_next_create()) == NULL)
1095*c42dbd0eSchristos 	{
1096*c42dbd0eSchristos 	  if (errp)
1097*c42dbd0eSchristos 	    *errp = ENOMEM;
1098*c42dbd0eSchristos 	  return NULL;
1099*c42dbd0eSchristos 	}
1100*c42dbd0eSchristos       i->cu.ctn_arc = wrapper;
1101*c42dbd0eSchristos       i->ctn_iter_fun = (void (*) (void)) ctf_archive_next;
1102*c42dbd0eSchristos       *it = i;
1103*c42dbd0eSchristos     }
1104*c42dbd0eSchristos 
1105*c42dbd0eSchristos   if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun)
1106*c42dbd0eSchristos     {
1107*c42dbd0eSchristos       if (errp)
1108*c42dbd0eSchristos 	*errp = ECTF_NEXT_WRONGFUN;
1109*c42dbd0eSchristos       return NULL;
1110*c42dbd0eSchristos     }
1111*c42dbd0eSchristos 
1112*c42dbd0eSchristos   if (wrapper != i->cu.ctn_arc)
1113*c42dbd0eSchristos     {
1114*c42dbd0eSchristos       if (errp)
1115*c42dbd0eSchristos 	*errp = ECTF_NEXT_WRONGFP;
1116*c42dbd0eSchristos       return NULL;
1117*c42dbd0eSchristos     }
1118*c42dbd0eSchristos 
1119*c42dbd0eSchristos   /* Iteration is made a bit more complex by the need to handle ctf_dict_t's
1120*c42dbd0eSchristos      transparently wrapped in a single-member archive.  These are parents: if
1121*c42dbd0eSchristos      skip_parent is on, they are skipped and the iterator terminates
1122*c42dbd0eSchristos      immediately.  */
1123*c42dbd0eSchristos 
1124*c42dbd0eSchristos   if (!wrapper->ctfi_is_archive && i->ctn_n == 0)
1125*c42dbd0eSchristos     {
1126*c42dbd0eSchristos       i->ctn_n++;
1127*c42dbd0eSchristos       if (!skip_parent)
1128*c42dbd0eSchristos 	{
1129*c42dbd0eSchristos 	  wrapper->ctfi_dict->ctf_refcnt++;
1130*c42dbd0eSchristos 	  if (name)
1131*c42dbd0eSchristos 	    *name = _CTF_SECTION;
1132*c42dbd0eSchristos 	  return wrapper->ctfi_dict;
1133*c42dbd0eSchristos 	}
1134*c42dbd0eSchristos     }
1135*c42dbd0eSchristos 
1136*c42dbd0eSchristos   arc = wrapper->ctfi_archive;
1137*c42dbd0eSchristos 
1138*c42dbd0eSchristos   /* The loop keeps going when skip_parent is on as long as the member we find
1139*c42dbd0eSchristos      is the parent (i.e. at most two iterations, but possibly an early return if
1140*c42dbd0eSchristos      *all* we have is a parent).  */
1141*c42dbd0eSchristos 
1142*c42dbd0eSchristos   do
1143*c42dbd0eSchristos     {
1144*c42dbd0eSchristos       if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts)))
1145*c42dbd0eSchristos 	{
1146*c42dbd0eSchristos 	  ctf_next_destroy (i);
1147*c42dbd0eSchristos 	  *it = NULL;
1148*c42dbd0eSchristos 	  if (errp)
1149*c42dbd0eSchristos 	    *errp = ECTF_NEXT_END;
1150*c42dbd0eSchristos 	  return NULL;
1151*c42dbd0eSchristos 	}
1152*c42dbd0eSchristos 
1153*c42dbd0eSchristos       modent = (ctf_archive_modent_t *) ((char *) arc
1154*c42dbd0eSchristos 					 + sizeof (struct ctf_archive));
1155*c42dbd0eSchristos       nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
1156*c42dbd0eSchristos 
1157*c42dbd0eSchristos       name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
1158*c42dbd0eSchristos       i->ctn_n++;
1159*c42dbd0eSchristos     }
1160*c42dbd0eSchristos   while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
1161*c42dbd0eSchristos 
1162*c42dbd0eSchristos   if (name)
1163*c42dbd0eSchristos     *name = name_;
1164*c42dbd0eSchristos 
1165*c42dbd0eSchristos   f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp);
1166*c42dbd0eSchristos   return f;
1167867d70fcSchristos }
1168867d70fcSchristos 
1169867d70fcSchristos #ifdef HAVE_MMAP
1170867d70fcSchristos /* Map the header in.  Only used on new, empty files.  */
arc_mmap_header(int fd,size_t headersz)1171867d70fcSchristos static void *arc_mmap_header (int fd, size_t headersz)
1172867d70fcSchristos {
1173867d70fcSchristos   void *hdr;
1174867d70fcSchristos   if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1175867d70fcSchristos 		   0)) == MAP_FAILED)
1176867d70fcSchristos     return NULL;
1177867d70fcSchristos   return hdr;
1178867d70fcSchristos }
1179867d70fcSchristos 
1180867d70fcSchristos /* mmap() the whole file, for reading only.  (Map it writably, but privately: we
1181867d70fcSchristos    need to modify the region, but don't need anyone else to see the
1182867d70fcSchristos    modifications.)  */
arc_mmap_file(int fd,size_t size)1183867d70fcSchristos static void *arc_mmap_file (int fd, size_t size)
1184867d70fcSchristos {
1185867d70fcSchristos   void *arc;
1186867d70fcSchristos   if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
1187867d70fcSchristos 		   fd, 0)) == MAP_FAILED)
1188867d70fcSchristos     return NULL;
1189867d70fcSchristos   return arc;
1190867d70fcSchristos }
1191867d70fcSchristos 
1192867d70fcSchristos /* Persist the header to disk.  */
arc_mmap_writeout(int fd _libctf_unused_,void * header,size_t headersz,const char ** errmsg)1193867d70fcSchristos static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
1194867d70fcSchristos 			      size_t headersz, const char **errmsg)
1195867d70fcSchristos {
1196867d70fcSchristos     if (msync (header, headersz, MS_ASYNC) < 0)
1197867d70fcSchristos     {
1198867d70fcSchristos       if (errmsg)
1199*c42dbd0eSchristos 	*errmsg = N_("arc_mmap_writeout(): cannot sync after writing "
1200*c42dbd0eSchristos 		     "to %s: %s");
1201867d70fcSchristos       return -1;
1202867d70fcSchristos     }
1203867d70fcSchristos     return 0;
1204867d70fcSchristos }
1205867d70fcSchristos 
1206867d70fcSchristos /* Unmap the region.  */
arc_mmap_unmap(void * header,size_t headersz,const char ** errmsg)1207867d70fcSchristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
1208867d70fcSchristos {
1209867d70fcSchristos   if (munmap (header, headersz) < 0)
1210867d70fcSchristos     {
1211867d70fcSchristos       if (errmsg)
1212*c42dbd0eSchristos 	*errmsg = N_("arc_mmap_munmap(): cannot unmap after writing "
1213*c42dbd0eSchristos 		     "to %s: %s");
1214867d70fcSchristos       return -1;
1215867d70fcSchristos     }
1216867d70fcSchristos     return 0;
1217867d70fcSchristos }
1218867d70fcSchristos #else
1219867d70fcSchristos /* Map the header in.  Only used on new, empty files.  */
arc_mmap_header(int fd _libctf_unused_,size_t headersz)1220867d70fcSchristos static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz)
1221867d70fcSchristos {
1222867d70fcSchristos   void *hdr;
1223867d70fcSchristos   if ((hdr = malloc (headersz)) == NULL)
1224867d70fcSchristos     return NULL;
1225867d70fcSchristos   return hdr;
1226867d70fcSchristos }
1227867d70fcSchristos 
1228867d70fcSchristos /* Pull in the whole file, for reading only.  We assume the current file
1229867d70fcSchristos    position is at the start of the file.  */
arc_mmap_file(int fd,size_t size)1230867d70fcSchristos static void *arc_mmap_file (int fd, size_t size)
1231867d70fcSchristos {
1232867d70fcSchristos   char *data;
1233867d70fcSchristos 
1234867d70fcSchristos   if ((data = malloc (size)) == NULL)
1235867d70fcSchristos     return NULL;
1236867d70fcSchristos 
1237867d70fcSchristos   if (ctf_pread (fd, data, size, 0) < 0)
1238867d70fcSchristos     {
1239867d70fcSchristos       free (data);
1240867d70fcSchristos       return NULL;
1241867d70fcSchristos     }
1242867d70fcSchristos   return data;
1243867d70fcSchristos }
1244867d70fcSchristos 
1245867d70fcSchristos /* Persist the header to disk.  */
arc_mmap_writeout(int fd,void * header,size_t headersz,const char ** errmsg)1246867d70fcSchristos static int arc_mmap_writeout (int fd, void *header, size_t headersz,
1247867d70fcSchristos 			      const char **errmsg)
1248867d70fcSchristos {
1249867d70fcSchristos   ssize_t len;
1250867d70fcSchristos   size_t acc = 0;
1251867d70fcSchristos   char *data = (char *) header;
1252867d70fcSchristos   ssize_t count = headersz;
1253867d70fcSchristos 
1254867d70fcSchristos   if ((lseek (fd, 0, SEEK_SET)) < 0)
1255867d70fcSchristos     {
1256867d70fcSchristos       if (errmsg)
1257*c42dbd0eSchristos 	*errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to "
1258*c42dbd0eSchristos 		     "%s: %s");
1259867d70fcSchristos       return -1;
1260867d70fcSchristos     }
1261867d70fcSchristos 
1262867d70fcSchristos   while (headersz > 0)
1263867d70fcSchristos     {
1264867d70fcSchristos       if ((len = write (fd, data, count)) < 0)
1265867d70fcSchristos 	{
1266867d70fcSchristos 	  if (errmsg)
1267*c42dbd0eSchristos 	    *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s");
1268867d70fcSchristos 	  return len;
1269867d70fcSchristos 	}
1270867d70fcSchristos       if (len == EINTR)
1271867d70fcSchristos 	continue;
1272867d70fcSchristos 
1273867d70fcSchristos       acc += len;
1274867d70fcSchristos       if (len == 0)				/* EOF.  */
1275867d70fcSchristos 	break;
1276867d70fcSchristos 
1277867d70fcSchristos       count -= len;
1278867d70fcSchristos       data += len;
1279867d70fcSchristos     }
1280867d70fcSchristos   return 0;
1281867d70fcSchristos }
1282867d70fcSchristos 
1283867d70fcSchristos /* Unmap the region.  */
arc_mmap_unmap(void * header,size_t headersz _libctf_unused_,const char ** errmsg _libctf_unused_)1284867d70fcSchristos static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_,
1285867d70fcSchristos 			   const char **errmsg _libctf_unused_)
1286867d70fcSchristos {
1287867d70fcSchristos   free (header);
1288867d70fcSchristos   return 0;
1289867d70fcSchristos }
1290867d70fcSchristos #endif
1291