1*fae548d3Szrj /* CTF archive files.
2*fae548d3Szrj Copyright (C) 2019-2020 Free Software Foundation, Inc.
3*fae548d3Szrj
4*fae548d3Szrj This file is part of libctf.
5*fae548d3Szrj
6*fae548d3Szrj libctf is free software; you can redistribute it and/or modify it under
7*fae548d3Szrj the terms of the GNU General Public License as published by the Free
8*fae548d3Szrj Software Foundation; either version 3, or (at your option) any later
9*fae548d3Szrj version.
10*fae548d3Szrj
11*fae548d3Szrj This program is distributed in the hope that it will be useful, but
12*fae548d3Szrj WITHOUT ANY WARRANTY; without even the implied warranty of
13*fae548d3Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14*fae548d3Szrj See the GNU General Public License for more details.
15*fae548d3Szrj
16*fae548d3Szrj You should have received a copy of the GNU General Public License
17*fae548d3Szrj along with this program; see the file COPYING. If not see
18*fae548d3Szrj <http://www.gnu.org/licenses/>. */
19*fae548d3Szrj
20*fae548d3Szrj #include <ctf-impl.h>
21*fae548d3Szrj #include <sys/types.h>
22*fae548d3Szrj #include <sys/stat.h>
23*fae548d3Szrj #include <elf.h>
24*fae548d3Szrj #include "ctf-endian.h"
25*fae548d3Szrj #include <errno.h>
26*fae548d3Szrj #include <fcntl.h>
27*fae548d3Szrj #include <stdio.h>
28*fae548d3Szrj #include <string.h>
29*fae548d3Szrj #include <unistd.h>
30*fae548d3Szrj
31*fae548d3Szrj #ifdef HAVE_MMAP
32*fae548d3Szrj #include <sys/mman.h>
33*fae548d3Szrj #endif
34*fae548d3Szrj
35*fae548d3Szrj static off_t arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold);
36*fae548d3Szrj static ctf_file_t *ctf_arc_open_by_offset (const struct ctf_archive *arc,
37*fae548d3Szrj const ctf_sect_t *symsect,
38*fae548d3Szrj const ctf_sect_t *strsect,
39*fae548d3Szrj size_t offset, int *errp);
40*fae548d3Szrj static int sort_modent_by_name (const void *one, const void *two, void *n);
41*fae548d3Szrj static void *arc_mmap_header (int fd, size_t headersz);
42*fae548d3Szrj static void *arc_mmap_file (int fd, size_t size);
43*fae548d3Szrj static int arc_mmap_writeout (int fd, void *header, size_t headersz,
44*fae548d3Szrj const char **errmsg);
45*fae548d3Szrj static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
46*fae548d3Szrj
47*fae548d3Szrj /* bsearch() internal state. */
48*fae548d3Szrj static __thread char *search_nametbl;
49*fae548d3Szrj
50*fae548d3Szrj /* Write out a CTF archive to the start of the file referenced by the passed-in
51*fae548d3Szrj fd. The entries in CTF_FILES are referenced by name: the names are passed in
52*fae548d3Szrj the names array, which must have CTF_FILES entries.
53*fae548d3Szrj
54*fae548d3Szrj Returns 0 on success, or an errno, or an ECTF_* value. */
55*fae548d3Szrj int
ctf_arc_write_fd(int fd,ctf_file_t ** ctf_files,size_t ctf_file_cnt,const char ** names,size_t threshold)56*fae548d3Szrj ctf_arc_write_fd (int fd, ctf_file_t **ctf_files, size_t ctf_file_cnt,
57*fae548d3Szrj const char **names, size_t threshold)
58*fae548d3Szrj {
59*fae548d3Szrj const char *errmsg;
60*fae548d3Szrj struct ctf_archive *archdr;
61*fae548d3Szrj size_t i;
62*fae548d3Szrj char dummy = 0;
63*fae548d3Szrj size_t headersz;
64*fae548d3Szrj ssize_t namesz;
65*fae548d3Szrj size_t ctf_startoffs; /* Start of the section we are working over. */
66*fae548d3Szrj char *nametbl = NULL; /* The name table. */
67*fae548d3Szrj char *np;
68*fae548d3Szrj off_t nameoffs;
69*fae548d3Szrj struct ctf_archive_modent *modent;
70*fae548d3Szrj
71*fae548d3Szrj ctf_dprintf ("Writing CTF archive with %lu files\n",
72*fae548d3Szrj (unsigned long) ctf_file_cnt);
73*fae548d3Szrj
74*fae548d3Szrj /* Figure out the size of the mmap()ed header, including the
75*fae548d3Szrj ctf_archive_modent array. We assume that all of this needs no
76*fae548d3Szrj padding: a likely assumption, given that it's all made up of
77*fae548d3Szrj uint64_t's. */
78*fae548d3Szrj headersz = sizeof (struct ctf_archive)
79*fae548d3Szrj + (ctf_file_cnt * sizeof (uint64_t) * 2);
80*fae548d3Szrj ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz);
81*fae548d3Szrj
82*fae548d3Szrj /* From now on we work in two pieces: an mmap()ed region from zero up to the
83*fae548d3Szrj headersz, and a region updated via write() starting after that, containing
84*fae548d3Szrj all the tables. Platforms that do not support mmap() just use write(). */
85*fae548d3Szrj ctf_startoffs = headersz;
86*fae548d3Szrj if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0)
87*fae548d3Szrj {
88*fae548d3Szrj errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
89*fae548d3Szrj goto err;
90*fae548d3Szrj }
91*fae548d3Szrj
92*fae548d3Szrj if (write (fd, &dummy, 1) < 0)
93*fae548d3Szrj {
94*fae548d3Szrj errmsg = "ctf_arc_write(): cannot extend file while writing: %s\n";
95*fae548d3Szrj goto err;
96*fae548d3Szrj }
97*fae548d3Szrj
98*fae548d3Szrj if ((archdr = arc_mmap_header (fd, headersz)) == NULL)
99*fae548d3Szrj {
100*fae548d3Szrj errmsg = "ctf_arc_write(): Cannot mmap(): %s\n";
101*fae548d3Szrj goto err;
102*fae548d3Szrj }
103*fae548d3Szrj
104*fae548d3Szrj /* Fill in everything we can, which is everything other than the name
105*fae548d3Szrj table offset. */
106*fae548d3Szrj archdr->ctfa_magic = htole64 (CTFA_MAGIC);
107*fae548d3Szrj archdr->ctfa_nfiles = htole64 (ctf_file_cnt);
108*fae548d3Szrj archdr->ctfa_ctfs = htole64 (ctf_startoffs);
109*fae548d3Szrj
110*fae548d3Szrj /* We could validate that all CTF files have the same data model, but
111*fae548d3Szrj since any reasonable construction process will be building things of
112*fae548d3Szrj only one bitness anyway, this is pretty pointless, so just use the
113*fae548d3Szrj model of the first CTF file for all of them. (It *is* valid to
114*fae548d3Szrj create an empty archive: the value of ctfa_model is irrelevant in
115*fae548d3Szrj this case, but we must be sure not to dereference uninitialized
116*fae548d3Szrj memory.) */
117*fae548d3Szrj
118*fae548d3Szrj if (ctf_file_cnt > 0)
119*fae548d3Szrj archdr->ctfa_model = htole64 (ctf_getmodel (ctf_files[0]));
120*fae548d3Szrj
121*fae548d3Szrj /* Now write out the CTFs: ctf_archive_modent array via the mapping,
122*fae548d3Szrj ctfs via write(). The names themselves have not been written yet: we
123*fae548d3Szrj track them in a local strtab until the time is right, and sort the
124*fae548d3Szrj modents array after construction.
125*fae548d3Szrj
126*fae548d3Szrj The name table is not sorted. */
127*fae548d3Szrj
128*fae548d3Szrj for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_nfiles); i++)
129*fae548d3Szrj namesz += strlen (names[i]) + 1;
130*fae548d3Szrj
131*fae548d3Szrj nametbl = malloc (namesz);
132*fae548d3Szrj if (nametbl == NULL)
133*fae548d3Szrj {
134*fae548d3Szrj errmsg = "Error writing named CTF to archive: %s\n";
135*fae548d3Szrj goto err_unmap;
136*fae548d3Szrj }
137*fae548d3Szrj
138*fae548d3Szrj for (i = 0, namesz = 0,
139*fae548d3Szrj modent = (ctf_archive_modent_t *) ((char *) archdr
140*fae548d3Szrj + sizeof (struct ctf_archive));
141*fae548d3Szrj i < le64toh (archdr->ctfa_nfiles); i++)
142*fae548d3Szrj {
143*fae548d3Szrj off_t off;
144*fae548d3Szrj
145*fae548d3Szrj strcpy (&nametbl[namesz], names[i]);
146*fae548d3Szrj
147*fae548d3Szrj off = arc_write_one_ctf (ctf_files[i], fd, threshold);
148*fae548d3Szrj if ((off < 0) && (off > -ECTF_BASE))
149*fae548d3Szrj {
150*fae548d3Szrj errmsg = "ctf_arc_write(): Cannot determine file "
151*fae548d3Szrj "position while writing to archive: %s";
152*fae548d3Szrj goto err_free;
153*fae548d3Szrj }
154*fae548d3Szrj if (off < 0)
155*fae548d3Szrj {
156*fae548d3Szrj errmsg = "ctf_arc_write(): Cannot write CTF file to archive: %s\n";
157*fae548d3Szrj errno = off * -1;
158*fae548d3Szrj goto err_free;
159*fae548d3Szrj }
160*fae548d3Szrj
161*fae548d3Szrj modent->name_offset = htole64 (namesz);
162*fae548d3Szrj modent->ctf_offset = htole64 (off - ctf_startoffs);
163*fae548d3Szrj namesz += strlen (names[i]) + 1;
164*fae548d3Szrj modent++;
165*fae548d3Szrj }
166*fae548d3Szrj
167*fae548d3Szrj ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr
168*fae548d3Szrj + sizeof (struct ctf_archive)),
169*fae548d3Szrj le64toh (archdr->ctfa_nfiles),
170*fae548d3Szrj sizeof (struct ctf_archive_modent), sort_modent_by_name,
171*fae548d3Szrj nametbl);
172*fae548d3Szrj
173*fae548d3Szrj /* Now the name table. */
174*fae548d3Szrj
175*fae548d3Szrj if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0)
176*fae548d3Szrj {
177*fae548d3Szrj errmsg = "ctf_arc_write(): Cannot get current file position "
178*fae548d3Szrj "in archive: %s\n";
179*fae548d3Szrj goto err_free;
180*fae548d3Szrj }
181*fae548d3Szrj archdr->ctfa_names = htole64 (nameoffs);
182*fae548d3Szrj np = nametbl;
183*fae548d3Szrj while (namesz > 0)
184*fae548d3Szrj {
185*fae548d3Szrj ssize_t len;
186*fae548d3Szrj if ((len = write (fd, np, namesz)) < 0)
187*fae548d3Szrj {
188*fae548d3Szrj errmsg = "ctf_arc_write(): Cannot write name table to archive: %s\n";
189*fae548d3Szrj goto err_free;
190*fae548d3Szrj }
191*fae548d3Szrj namesz -= len;
192*fae548d3Szrj np += len;
193*fae548d3Szrj }
194*fae548d3Szrj free (nametbl);
195*fae548d3Szrj
196*fae548d3Szrj if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0)
197*fae548d3Szrj goto err_unmap;
198*fae548d3Szrj if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0)
199*fae548d3Szrj goto err;
200*fae548d3Szrj return 0;
201*fae548d3Szrj
202*fae548d3Szrj err_free:
203*fae548d3Szrj free (nametbl);
204*fae548d3Szrj err_unmap:
205*fae548d3Szrj arc_mmap_unmap (archdr, headersz, NULL);
206*fae548d3Szrj err:
207*fae548d3Szrj ctf_dprintf (errmsg, errno < ECTF_BASE ? strerror (errno) :
208*fae548d3Szrj ctf_errmsg (errno));
209*fae548d3Szrj return errno;
210*fae548d3Szrj }
211*fae548d3Szrj
212*fae548d3Szrj /* Write out a CTF archive. The entries in CTF_FILES are referenced by name:
213*fae548d3Szrj the names are passed in the names array, which must have CTF_FILES entries.
214*fae548d3Szrj
215*fae548d3Szrj If the filename is NULL, create a temporary file and return a pointer to it.
216*fae548d3Szrj
217*fae548d3Szrj Returns 0 on success, or an errno, or an ECTF_* value. */
218*fae548d3Szrj int
ctf_arc_write(const char * file,ctf_file_t ** ctf_files,size_t ctf_file_cnt,const char ** names,size_t threshold)219*fae548d3Szrj ctf_arc_write (const char *file, ctf_file_t ** ctf_files, size_t ctf_file_cnt,
220*fae548d3Szrj const char **names, size_t threshold)
221*fae548d3Szrj {
222*fae548d3Szrj int err;
223*fae548d3Szrj int fd;
224*fae548d3Szrj
225*fae548d3Szrj if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0)
226*fae548d3Szrj {
227*fae548d3Szrj ctf_dprintf ("ctf_arc_write(): cannot create %s: %s\n", file,
228*fae548d3Szrj strerror (errno));
229*fae548d3Szrj return errno;
230*fae548d3Szrj }
231*fae548d3Szrj
232*fae548d3Szrj err = ctf_arc_write_fd (fd, ctf_files, ctf_file_cnt, names, threshold);
233*fae548d3Szrj if (err)
234*fae548d3Szrj goto err;
235*fae548d3Szrj
236*fae548d3Szrj if ((err = close (fd)) < 0)
237*fae548d3Szrj {
238*fae548d3Szrj ctf_dprintf ("ctf_arc_write(): Cannot close after writing to archive: "
239*fae548d3Szrj "%s\n", strerror (errno));
240*fae548d3Szrj goto err_close;
241*fae548d3Szrj }
242*fae548d3Szrj
243*fae548d3Szrj err:
244*fae548d3Szrj close (fd);
245*fae548d3Szrj if (err < 0)
246*fae548d3Szrj unlink (file);
247*fae548d3Szrj
248*fae548d3Szrj return err;
249*fae548d3Szrj
250*fae548d3Szrj err_close:
251*fae548d3Szrj if (err < 0)
252*fae548d3Szrj unlink (file);
253*fae548d3Szrj
254*fae548d3Szrj return err;
255*fae548d3Szrj }
256*fae548d3Szrj
257*fae548d3Szrj /* Write one CTF file out. Return the file position of the written file (or
258*fae548d3Szrj rather, of the file-size uint64_t that precedes it): negative return is a
259*fae548d3Szrj negative errno or ctf_errno value. On error, the file position may no longer
260*fae548d3Szrj be at the end of the file. */
261*fae548d3Szrj static off_t
arc_write_one_ctf(ctf_file_t * f,int fd,size_t threshold)262*fae548d3Szrj arc_write_one_ctf (ctf_file_t * f, int fd, size_t threshold)
263*fae548d3Szrj {
264*fae548d3Szrj off_t off, end_off;
265*fae548d3Szrj uint64_t ctfsz = 0;
266*fae548d3Szrj char *ctfszp;
267*fae548d3Szrj size_t ctfsz_len;
268*fae548d3Szrj int (*writefn) (ctf_file_t * fp, int fd);
269*fae548d3Szrj
270*fae548d3Szrj if (ctf_serialize (f) < 0)
271*fae548d3Szrj return f->ctf_errno * -1;
272*fae548d3Szrj
273*fae548d3Szrj if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
274*fae548d3Szrj return errno * -1;
275*fae548d3Szrj
276*fae548d3Szrj if (f->ctf_size > threshold)
277*fae548d3Szrj writefn = ctf_compress_write;
278*fae548d3Szrj else
279*fae548d3Szrj writefn = ctf_write;
280*fae548d3Szrj
281*fae548d3Szrj /* This zero-write turns into the size in a moment. */
282*fae548d3Szrj ctfsz_len = sizeof (ctfsz);
283*fae548d3Szrj ctfszp = (char *) &ctfsz;
284*fae548d3Szrj while (ctfsz_len > 0)
285*fae548d3Szrj {
286*fae548d3Szrj ssize_t writelen = write (fd, ctfszp, ctfsz_len);
287*fae548d3Szrj if (writelen < 0)
288*fae548d3Szrj return errno * -1;
289*fae548d3Szrj ctfsz_len -= writelen;
290*fae548d3Szrj ctfszp += writelen;
291*fae548d3Szrj }
292*fae548d3Szrj
293*fae548d3Szrj if (writefn (f, fd) != 0)
294*fae548d3Szrj return f->ctf_errno * -1;
295*fae548d3Szrj
296*fae548d3Szrj if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0)
297*fae548d3Szrj return errno * -1;
298*fae548d3Szrj ctfsz = htole64 (end_off - off);
299*fae548d3Szrj
300*fae548d3Szrj if ((lseek (fd, off, SEEK_SET)) < 0)
301*fae548d3Szrj return errno * -1;
302*fae548d3Szrj
303*fae548d3Szrj /* ... here. */
304*fae548d3Szrj ctfsz_len = sizeof (ctfsz);
305*fae548d3Szrj ctfszp = (char *) &ctfsz;
306*fae548d3Szrj while (ctfsz_len > 0)
307*fae548d3Szrj {
308*fae548d3Szrj ssize_t writelen = write (fd, ctfszp, ctfsz_len);
309*fae548d3Szrj if (writelen < 0)
310*fae548d3Szrj return errno * -1;
311*fae548d3Szrj ctfsz_len -= writelen;
312*fae548d3Szrj ctfszp += writelen;
313*fae548d3Szrj }
314*fae548d3Szrj
315*fae548d3Szrj end_off = LCTF_ALIGN_OFFS (end_off, 8);
316*fae548d3Szrj if ((lseek (fd, end_off, SEEK_SET)) < 0)
317*fae548d3Szrj return errno * -1;
318*fae548d3Szrj
319*fae548d3Szrj return off;
320*fae548d3Szrj }
321*fae548d3Szrj
322*fae548d3Szrj /* qsort() function to sort the array of struct ctf_archive_modents into
323*fae548d3Szrj ascending name order. */
324*fae548d3Szrj static int
sort_modent_by_name(const void * one,const void * two,void * n)325*fae548d3Szrj sort_modent_by_name (const void *one, const void *two, void *n)
326*fae548d3Szrj {
327*fae548d3Szrj const struct ctf_archive_modent *a = one;
328*fae548d3Szrj const struct ctf_archive_modent *b = two;
329*fae548d3Szrj char *nametbl = n;
330*fae548d3Szrj
331*fae548d3Szrj return strcmp (&nametbl[le64toh (a->name_offset)],
332*fae548d3Szrj &nametbl[le64toh (b->name_offset)]);
333*fae548d3Szrj }
334*fae548d3Szrj
335*fae548d3Szrj /* bsearch() function to search for a given name in the sorted array of struct
336*fae548d3Szrj ctf_archive_modents. */
337*fae548d3Szrj static int
search_modent_by_name(const void * key,const void * ent)338*fae548d3Szrj search_modent_by_name (const void *key, const void *ent)
339*fae548d3Szrj {
340*fae548d3Szrj const char *k = key;
341*fae548d3Szrj const struct ctf_archive_modent *v = ent;
342*fae548d3Szrj
343*fae548d3Szrj return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
344*fae548d3Szrj }
345*fae548d3Szrj
346*fae548d3Szrj /* A trivial wrapper: open a CTF archive, from data in a buffer (which the
347*fae548d3Szrj caller must preserve until ctf_arc_close() time). Returns the archive, or
348*fae548d3Szrj NULL and an error in *err (if not NULL). */
349*fae548d3Szrj struct ctf_archive *
ctf_arc_bufopen(const void * buf,size_t size _libctf_unused_,int * errp)350*fae548d3Szrj ctf_arc_bufopen (const void *buf, size_t size _libctf_unused_, int *errp)
351*fae548d3Szrj {
352*fae548d3Szrj struct ctf_archive *arc = (struct ctf_archive *) buf;
353*fae548d3Szrj
354*fae548d3Szrj if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
355*fae548d3Szrj {
356*fae548d3Szrj if (errp)
357*fae548d3Szrj *errp = ECTF_FMT;
358*fae548d3Szrj return NULL;
359*fae548d3Szrj }
360*fae548d3Szrj return arc;
361*fae548d3Szrj }
362*fae548d3Szrj
363*fae548d3Szrj /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if
364*fae548d3Szrj not NULL). */
365*fae548d3Szrj struct ctf_archive *
ctf_arc_open_internal(const char * filename,int * errp)366*fae548d3Szrj ctf_arc_open_internal (const char *filename, int *errp)
367*fae548d3Szrj {
368*fae548d3Szrj const char *errmsg;
369*fae548d3Szrj int fd;
370*fae548d3Szrj struct stat s;
371*fae548d3Szrj struct ctf_archive *arc; /* (Actually the whole file.) */
372*fae548d3Szrj
373*fae548d3Szrj libctf_init_debug();
374*fae548d3Szrj if ((fd = open (filename, O_RDONLY)) < 0)
375*fae548d3Szrj {
376*fae548d3Szrj errmsg = "ctf_arc_open(): cannot open %s: %s\n";
377*fae548d3Szrj goto err;
378*fae548d3Szrj }
379*fae548d3Szrj if (fstat (fd, &s) < 0)
380*fae548d3Szrj {
381*fae548d3Szrj errmsg = "ctf_arc_open(): cannot stat %s: %s\n";
382*fae548d3Szrj goto err_close;
383*fae548d3Szrj }
384*fae548d3Szrj
385*fae548d3Szrj if ((arc = arc_mmap_file (fd, s.st_size)) == NULL)
386*fae548d3Szrj {
387*fae548d3Szrj errmsg = "ctf_arc_open(): Cannot read in %s: %s\n";
388*fae548d3Szrj goto err_close;
389*fae548d3Szrj }
390*fae548d3Szrj
391*fae548d3Szrj if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
392*fae548d3Szrj {
393*fae548d3Szrj errmsg = "ctf_arc_open(): Invalid magic number";
394*fae548d3Szrj errno = ECTF_FMT;
395*fae548d3Szrj goto err_unmap;
396*fae548d3Szrj }
397*fae548d3Szrj
398*fae548d3Szrj /* This horrible hack lets us know how much to unmap when the file is
399*fae548d3Szrj closed. (We no longer need the magic number, and the mapping
400*fae548d3Szrj is private.) */
401*fae548d3Szrj arc->ctfa_magic = s.st_size;
402*fae548d3Szrj close (fd);
403*fae548d3Szrj return arc;
404*fae548d3Szrj
405*fae548d3Szrj err_unmap:
406*fae548d3Szrj arc_mmap_unmap (arc, s.st_size, NULL);
407*fae548d3Szrj err_close:
408*fae548d3Szrj close (fd);
409*fae548d3Szrj err:
410*fae548d3Szrj if (errp)
411*fae548d3Szrj *errp = errno;
412*fae548d3Szrj ctf_dprintf (errmsg, filename, errno < ECTF_BASE ? strerror (errno) :
413*fae548d3Szrj ctf_errmsg (errno));
414*fae548d3Szrj return NULL;
415*fae548d3Szrj }
416*fae548d3Szrj
417*fae548d3Szrj /* Close an archive. */
418*fae548d3Szrj void
ctf_arc_close_internal(struct ctf_archive * arc)419*fae548d3Szrj ctf_arc_close_internal (struct ctf_archive *arc)
420*fae548d3Szrj {
421*fae548d3Szrj if (arc == NULL)
422*fae548d3Szrj return;
423*fae548d3Szrj
424*fae548d3Szrj /* See the comment in ctf_arc_open(). */
425*fae548d3Szrj arc_mmap_unmap (arc, arc->ctfa_magic, NULL);
426*fae548d3Szrj }
427*fae548d3Szrj
428*fae548d3Szrj /* Public entry point: close an archive, or CTF file. */
429*fae548d3Szrj void
ctf_arc_close(ctf_archive_t * arc)430*fae548d3Szrj ctf_arc_close (ctf_archive_t *arc)
431*fae548d3Szrj {
432*fae548d3Szrj if (arc == NULL)
433*fae548d3Szrj return;
434*fae548d3Szrj
435*fae548d3Szrj if (arc->ctfi_is_archive)
436*fae548d3Szrj ctf_arc_close_internal (arc->ctfi_archive);
437*fae548d3Szrj else
438*fae548d3Szrj ctf_file_close (arc->ctfi_file);
439*fae548d3Szrj free ((void *) arc->ctfi_symsect.cts_data);
440*fae548d3Szrj /* Do not free the ctfi_strsect: it is bound to the bfd. */
441*fae548d3Szrj free (arc->ctfi_data);
442*fae548d3Szrj if (arc->ctfi_bfd_close)
443*fae548d3Szrj arc->ctfi_bfd_close (arc);
444*fae548d3Szrj free (arc);
445*fae548d3Szrj }
446*fae548d3Szrj
447*fae548d3Szrj /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
448*fae548d3Szrj non-NULL. A name of NULL means to open the default file. */
449*fae548d3Szrj static ctf_file_t *
ctf_arc_open_by_name_internal(const struct ctf_archive * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,const char * name,int * errp)450*fae548d3Szrj ctf_arc_open_by_name_internal (const struct ctf_archive *arc,
451*fae548d3Szrj const ctf_sect_t *symsect,
452*fae548d3Szrj const ctf_sect_t *strsect,
453*fae548d3Szrj const char *name, int *errp)
454*fae548d3Szrj {
455*fae548d3Szrj struct ctf_archive_modent *modent;
456*fae548d3Szrj
457*fae548d3Szrj if (name == NULL)
458*fae548d3Szrj name = _CTF_SECTION; /* The default name. */
459*fae548d3Szrj
460*fae548d3Szrj ctf_dprintf ("ctf_arc_open_by_name(%s): opening\n", name);
461*fae548d3Szrj
462*fae548d3Szrj modent = (ctf_archive_modent_t *) ((char *) arc
463*fae548d3Szrj + sizeof (struct ctf_archive));
464*fae548d3Szrj
465*fae548d3Szrj search_nametbl = (char *) arc + le64toh (arc->ctfa_names);
466*fae548d3Szrj modent = bsearch (name, modent, le64toh (arc->ctfa_nfiles),
467*fae548d3Szrj sizeof (struct ctf_archive_modent),
468*fae548d3Szrj search_modent_by_name);
469*fae548d3Szrj
470*fae548d3Szrj /* This is actually a common case and normal operation: no error
471*fae548d3Szrj debug output. */
472*fae548d3Szrj if (modent == NULL)
473*fae548d3Szrj {
474*fae548d3Szrj if (errp)
475*fae548d3Szrj *errp = ECTF_ARNNAME;
476*fae548d3Szrj return NULL;
477*fae548d3Szrj }
478*fae548d3Szrj
479*fae548d3Szrj return ctf_arc_open_by_offset (arc, symsect, strsect,
480*fae548d3Szrj le64toh (modent->ctf_offset), errp);
481*fae548d3Szrj }
482*fae548d3Szrj
483*fae548d3Szrj /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
484*fae548d3Szrj non-NULL. A name of NULL means to open the default file.
485*fae548d3Szrj
486*fae548d3Szrj Use the specified string and symbol table sections.
487*fae548d3Szrj
488*fae548d3Szrj Public entry point. */
489*fae548d3Szrj ctf_file_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)490*fae548d3Szrj ctf_arc_open_by_name_sections (const ctf_archive_t *arc,
491*fae548d3Szrj const ctf_sect_t *symsect,
492*fae548d3Szrj const ctf_sect_t *strsect,
493*fae548d3Szrj const char *name,
494*fae548d3Szrj int *errp)
495*fae548d3Szrj {
496*fae548d3Szrj if (arc->ctfi_is_archive)
497*fae548d3Szrj {
498*fae548d3Szrj ctf_file_t *ret;
499*fae548d3Szrj ret = ctf_arc_open_by_name_internal (arc->ctfi_archive, symsect, strsect,
500*fae548d3Szrj name, errp);
501*fae548d3Szrj if (ret)
502*fae548d3Szrj ret->ctf_archive = (ctf_archive_t *) arc;
503*fae548d3Szrj return ret;
504*fae548d3Szrj }
505*fae548d3Szrj
506*fae548d3Szrj if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0))
507*fae548d3Szrj {
508*fae548d3Szrj if (errp)
509*fae548d3Szrj *errp = ECTF_ARNNAME;
510*fae548d3Szrj return NULL;
511*fae548d3Szrj }
512*fae548d3Szrj arc->ctfi_file->ctf_archive = (ctf_archive_t *) arc;
513*fae548d3Szrj
514*fae548d3Szrj /* Bump the refcount so that the user can ctf_file_close() it. */
515*fae548d3Szrj arc->ctfi_file->ctf_refcnt++;
516*fae548d3Szrj return arc->ctfi_file;
517*fae548d3Szrj }
518*fae548d3Szrj
519*fae548d3Szrj /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
520*fae548d3Szrj non-NULL. A name of NULL means to open the default file.
521*fae548d3Szrj
522*fae548d3Szrj Public entry point. */
523*fae548d3Szrj ctf_file_t *
ctf_arc_open_by_name(const ctf_archive_t * arc,const char * name,int * errp)524*fae548d3Szrj ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name, int *errp)
525*fae548d3Szrj {
526*fae548d3Szrj const ctf_sect_t *symsect = &arc->ctfi_symsect;
527*fae548d3Szrj const ctf_sect_t *strsect = &arc->ctfi_strsect;
528*fae548d3Szrj
529*fae548d3Szrj if (symsect->cts_name == NULL)
530*fae548d3Szrj symsect = NULL;
531*fae548d3Szrj if (strsect->cts_name == NULL)
532*fae548d3Szrj strsect = NULL;
533*fae548d3Szrj
534*fae548d3Szrj return ctf_arc_open_by_name_sections (arc, symsect, strsect, name, errp);
535*fae548d3Szrj }
536*fae548d3Szrj
537*fae548d3Szrj /* Return the ctf_file_t at the given ctfa_ctfs-relative offset, or NULL if
538*fae548d3Szrj none, setting 'err' if non-NULL. */
539*fae548d3Szrj static ctf_file_t *
ctf_arc_open_by_offset(const struct ctf_archive * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,size_t offset,int * errp)540*fae548d3Szrj ctf_arc_open_by_offset (const struct ctf_archive *arc,
541*fae548d3Szrj const ctf_sect_t *symsect,
542*fae548d3Szrj const ctf_sect_t *strsect, size_t offset,
543*fae548d3Szrj int *errp)
544*fae548d3Szrj {
545*fae548d3Szrj ctf_sect_t ctfsect;
546*fae548d3Szrj ctf_file_t *fp;
547*fae548d3Szrj
548*fae548d3Szrj ctf_dprintf ("ctf_arc_open_by_offset(%lu): opening\n", (unsigned long) offset);
549*fae548d3Szrj
550*fae548d3Szrj memset (&ctfsect, 0, sizeof (ctf_sect_t));
551*fae548d3Szrj
552*fae548d3Szrj offset += le64toh (arc->ctfa_ctfs);
553*fae548d3Szrj
554*fae548d3Szrj ctfsect.cts_name = _CTF_SECTION;
555*fae548d3Szrj ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset)));
556*fae548d3Szrj ctfsect.cts_entsize = 1;
557*fae548d3Szrj ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t));
558*fae548d3Szrj fp = ctf_bufopen (&ctfsect, symsect, strsect, errp);
559*fae548d3Szrj if (fp)
560*fae548d3Szrj ctf_setmodel (fp, le64toh (arc->ctfa_model));
561*fae548d3Szrj return fp;
562*fae548d3Szrj }
563*fae548d3Szrj
564*fae548d3Szrj /* Raw iteration over all CTF files in an archive. We pass the raw data for all
565*fae548d3Szrj CTF files in turn to the specified callback function. */
566*fae548d3Szrj static int
ctf_archive_raw_iter_internal(const struct ctf_archive * arc,ctf_archive_raw_member_f * func,void * data)567*fae548d3Szrj ctf_archive_raw_iter_internal (const struct ctf_archive *arc,
568*fae548d3Szrj ctf_archive_raw_member_f *func, void *data)
569*fae548d3Szrj {
570*fae548d3Szrj int rc;
571*fae548d3Szrj size_t i;
572*fae548d3Szrj struct ctf_archive_modent *modent;
573*fae548d3Szrj const char *nametbl;
574*fae548d3Szrj
575*fae548d3Szrj modent = (ctf_archive_modent_t *) ((char *) arc
576*fae548d3Szrj + sizeof (struct ctf_archive));
577*fae548d3Szrj nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
578*fae548d3Szrj
579*fae548d3Szrj for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
580*fae548d3Szrj {
581*fae548d3Szrj const char *name;
582*fae548d3Szrj char *fp;
583*fae548d3Szrj
584*fae548d3Szrj name = &nametbl[le64toh (modent[i].name_offset)];
585*fae548d3Szrj fp = ((char *) arc + le64toh (arc->ctfa_ctfs)
586*fae548d3Szrj + le64toh (modent[i].ctf_offset));
587*fae548d3Szrj
588*fae548d3Szrj if ((rc = func (name, (void *) (fp + sizeof (uint64_t)),
589*fae548d3Szrj le64toh (*((uint64_t *) fp)), data)) != 0)
590*fae548d3Szrj return rc;
591*fae548d3Szrj }
592*fae548d3Szrj return 0;
593*fae548d3Szrj }
594*fae548d3Szrj
595*fae548d3Szrj /* Raw iteration over all CTF files in an archive: public entry point.
596*fae548d3Szrj
597*fae548d3Szrj Returns -EINVAL if not supported for this sort of archive. */
598*fae548d3Szrj int
ctf_archive_raw_iter(const ctf_archive_t * arc,ctf_archive_raw_member_f * func,void * data)599*fae548d3Szrj ctf_archive_raw_iter (const ctf_archive_t *arc,
600*fae548d3Szrj ctf_archive_raw_member_f * func, void *data)
601*fae548d3Szrj {
602*fae548d3Szrj if (arc->ctfi_is_archive)
603*fae548d3Szrj return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data);
604*fae548d3Szrj
605*fae548d3Szrj return -EINVAL; /* Not supported. */
606*fae548d3Szrj }
607*fae548d3Szrj
608*fae548d3Szrj /* Iterate over all CTF files in an archive. We pass all CTF files in turn to
609*fae548d3Szrj the specified callback function. */
610*fae548d3Szrj static int
ctf_archive_iter_internal(const ctf_archive_t * wrapper,const struct ctf_archive * arc,const ctf_sect_t * symsect,const ctf_sect_t * strsect,ctf_archive_member_f * func,void * data)611*fae548d3Szrj ctf_archive_iter_internal (const ctf_archive_t *wrapper,
612*fae548d3Szrj const struct ctf_archive *arc,
613*fae548d3Szrj const ctf_sect_t *symsect,
614*fae548d3Szrj const ctf_sect_t *strsect,
615*fae548d3Szrj ctf_archive_member_f *func, void *data)
616*fae548d3Szrj {
617*fae548d3Szrj int rc;
618*fae548d3Szrj size_t i;
619*fae548d3Szrj ctf_file_t *f;
620*fae548d3Szrj struct ctf_archive_modent *modent;
621*fae548d3Szrj const char *nametbl;
622*fae548d3Szrj
623*fae548d3Szrj modent = (ctf_archive_modent_t *) ((char *) arc
624*fae548d3Szrj + sizeof (struct ctf_archive));
625*fae548d3Szrj nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
626*fae548d3Szrj
627*fae548d3Szrj for (i = 0; i < le64toh (arc->ctfa_nfiles); i++)
628*fae548d3Szrj {
629*fae548d3Szrj const char *name;
630*fae548d3Szrj
631*fae548d3Szrj name = &nametbl[le64toh (modent[i].name_offset)];
632*fae548d3Szrj if ((f = ctf_arc_open_by_name_internal (arc, symsect, strsect,
633*fae548d3Szrj name, &rc)) == NULL)
634*fae548d3Szrj return rc;
635*fae548d3Szrj
636*fae548d3Szrj f->ctf_archive = (ctf_archive_t *) wrapper;
637*fae548d3Szrj if ((rc = func (f, name, data)) != 0)
638*fae548d3Szrj {
639*fae548d3Szrj ctf_file_close (f);
640*fae548d3Szrj return rc;
641*fae548d3Szrj }
642*fae548d3Szrj
643*fae548d3Szrj ctf_file_close (f);
644*fae548d3Szrj }
645*fae548d3Szrj return 0;
646*fae548d3Szrj }
647*fae548d3Szrj
648*fae548d3Szrj /* Iterate over all CTF files in an archive: public entry point. We pass all
649*fae548d3Szrj CTF files in turn to the specified callback function. */
650*fae548d3Szrj int
ctf_archive_iter(const ctf_archive_t * arc,ctf_archive_member_f * func,void * data)651*fae548d3Szrj ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
652*fae548d3Szrj void *data)
653*fae548d3Szrj {
654*fae548d3Szrj const ctf_sect_t *symsect = &arc->ctfi_symsect;
655*fae548d3Szrj const ctf_sect_t *strsect = &arc->ctfi_strsect;
656*fae548d3Szrj
657*fae548d3Szrj if (symsect->cts_name == NULL)
658*fae548d3Szrj symsect = NULL;
659*fae548d3Szrj if (strsect->cts_name == NULL)
660*fae548d3Szrj strsect = NULL;
661*fae548d3Szrj
662*fae548d3Szrj if (arc->ctfi_is_archive)
663*fae548d3Szrj return ctf_archive_iter_internal (arc, arc->ctfi_archive, symsect, strsect,
664*fae548d3Szrj func, data);
665*fae548d3Szrj
666*fae548d3Szrj return func (arc->ctfi_file, _CTF_SECTION, data);
667*fae548d3Szrj }
668*fae548d3Szrj
669*fae548d3Szrj #ifdef HAVE_MMAP
670*fae548d3Szrj /* Map the header in. Only used on new, empty files. */
arc_mmap_header(int fd,size_t headersz)671*fae548d3Szrj static void *arc_mmap_header (int fd, size_t headersz)
672*fae548d3Szrj {
673*fae548d3Szrj void *hdr;
674*fae548d3Szrj if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
675*fae548d3Szrj 0)) == MAP_FAILED)
676*fae548d3Szrj return NULL;
677*fae548d3Szrj return hdr;
678*fae548d3Szrj }
679*fae548d3Szrj
680*fae548d3Szrj /* mmap() the whole file, for reading only. (Map it writably, but privately: we
681*fae548d3Szrj need to modify the region, but don't need anyone else to see the
682*fae548d3Szrj modifications.) */
arc_mmap_file(int fd,size_t size)683*fae548d3Szrj static void *arc_mmap_file (int fd, size_t size)
684*fae548d3Szrj {
685*fae548d3Szrj void *arc;
686*fae548d3Szrj if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
687*fae548d3Szrj fd, 0)) == MAP_FAILED)
688*fae548d3Szrj return NULL;
689*fae548d3Szrj return arc;
690*fae548d3Szrj }
691*fae548d3Szrj
692*fae548d3Szrj /* Persist the header to disk. */
arc_mmap_writeout(int fd _libctf_unused_,void * header,size_t headersz,const char ** errmsg)693*fae548d3Szrj static int arc_mmap_writeout (int fd _libctf_unused_, void *header,
694*fae548d3Szrj size_t headersz, const char **errmsg)
695*fae548d3Szrj {
696*fae548d3Szrj if (msync (header, headersz, MS_ASYNC) < 0)
697*fae548d3Szrj {
698*fae548d3Szrj if (errmsg)
699*fae548d3Szrj *errmsg = "arc_mmap_writeout(): Cannot sync after writing to %s: %s\n";
700*fae548d3Szrj return -1;
701*fae548d3Szrj }
702*fae548d3Szrj return 0;
703*fae548d3Szrj }
704*fae548d3Szrj
705*fae548d3Szrj /* Unmap the region. */
arc_mmap_unmap(void * header,size_t headersz,const char ** errmsg)706*fae548d3Szrj static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg)
707*fae548d3Szrj {
708*fae548d3Szrj if (munmap (header, headersz) < 0)
709*fae548d3Szrj {
710*fae548d3Szrj if (errmsg)
711*fae548d3Szrj *errmsg = "arc_mmap_munmap(): Cannot unmap after writing to %s: %s\n";
712*fae548d3Szrj return -1;
713*fae548d3Szrj }
714*fae548d3Szrj return 0;
715*fae548d3Szrj }
716*fae548d3Szrj #else
717*fae548d3Szrj /* Map the header in. Only used on new, empty files. */
arc_mmap_header(int fd _libctf_unused_,size_t headersz)718*fae548d3Szrj static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz)
719*fae548d3Szrj {
720*fae548d3Szrj void *hdr;
721*fae548d3Szrj if ((hdr = malloc (headersz)) == NULL)
722*fae548d3Szrj return NULL;
723*fae548d3Szrj return hdr;
724*fae548d3Szrj }
725*fae548d3Szrj
726*fae548d3Szrj /* Pull in the whole file, for reading only. We assume the current file
727*fae548d3Szrj position is at the start of the file. */
arc_mmap_file(int fd,size_t size)728*fae548d3Szrj static void *arc_mmap_file (int fd, size_t size)
729*fae548d3Szrj {
730*fae548d3Szrj char *data;
731*fae548d3Szrj
732*fae548d3Szrj if ((data = malloc (size)) == NULL)
733*fae548d3Szrj return NULL;
734*fae548d3Szrj
735*fae548d3Szrj if (ctf_pread (fd, data, size, 0) < 0)
736*fae548d3Szrj {
737*fae548d3Szrj free (data);
738*fae548d3Szrj return NULL;
739*fae548d3Szrj }
740*fae548d3Szrj return data;
741*fae548d3Szrj }
742*fae548d3Szrj
743*fae548d3Szrj /* Persist the header to disk. */
arc_mmap_writeout(int fd,void * header,size_t headersz,const char ** errmsg)744*fae548d3Szrj static int arc_mmap_writeout (int fd, void *header, size_t headersz,
745*fae548d3Szrj const char **errmsg)
746*fae548d3Szrj {
747*fae548d3Szrj ssize_t len;
748*fae548d3Szrj size_t acc = 0;
749*fae548d3Szrj char *data = (char *) header;
750*fae548d3Szrj ssize_t count = headersz;
751*fae548d3Szrj
752*fae548d3Szrj if ((lseek (fd, 0, SEEK_SET)) < 0)
753*fae548d3Szrj {
754*fae548d3Szrj if (errmsg)
755*fae548d3Szrj *errmsg = "arc_mmap_writeout(): Cannot seek while writing header to "
756*fae548d3Szrj "%s: %s\n";
757*fae548d3Szrj return -1;
758*fae548d3Szrj }
759*fae548d3Szrj
760*fae548d3Szrj while (headersz > 0)
761*fae548d3Szrj {
762*fae548d3Szrj if ((len = write (fd, data, count)) < 0)
763*fae548d3Szrj {
764*fae548d3Szrj if (errmsg)
765*fae548d3Szrj *errmsg = "arc_mmap_writeout(): Cannot write header to %s: %s\n";
766*fae548d3Szrj return len;
767*fae548d3Szrj }
768*fae548d3Szrj if (len == EINTR)
769*fae548d3Szrj continue;
770*fae548d3Szrj
771*fae548d3Szrj acc += len;
772*fae548d3Szrj if (len == 0) /* EOF. */
773*fae548d3Szrj break;
774*fae548d3Szrj
775*fae548d3Szrj count -= len;
776*fae548d3Szrj data += len;
777*fae548d3Szrj }
778*fae548d3Szrj return 0;
779*fae548d3Szrj }
780*fae548d3Szrj
781*fae548d3Szrj /* Unmap the region. */
arc_mmap_unmap(void * header,size_t headersz _libctf_unused_,const char ** errmsg _libctf_unused_)782*fae548d3Szrj static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_,
783*fae548d3Szrj const char **errmsg _libctf_unused_)
784*fae548d3Szrj {
785*fae548d3Szrj free (header);
786*fae548d3Szrj return 0;
787*fae548d3Szrj }
788*fae548d3Szrj #endif
789