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