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