xref: /dflybsd-src/contrib/binutils-2.34/libctf/ctf-archive.c (revision b52ef7118d1621abed722c5bbbd542210290ecef)
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