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