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