/src/binutils-gdb/libctf/ctf-archive.c
Line | Count | Source |
1 | | /* CTF archive files. |
2 | | Copyright (C) 2019-2026 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. Returns NULL if this cannot be a CTF archive or dict at all. */ |
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 | && ctfsect->cts_size < (sizeof (ctf_archive_t) + sizeof (uint64_t)))) |
401 | 0 | return NULL; |
402 | | |
403 | 0 | if (ctfsect->cts_size >= (sizeof (struct ctf_archive) + sizeof (uint64_t)) |
404 | 0 | && le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC) |
405 | 0 | { |
406 | 0 | struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data; |
407 | 0 | return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs) |
408 | 0 | + sizeof (uint64_t)); |
409 | 0 | } |
410 | 0 | else |
411 | 0 | return (const ctf_preamble_t *) ctfsect->cts_data; |
412 | 0 | } |
413 | | |
414 | | /* Open a CTF archive or dictionary from data in a buffer (which the caller must |
415 | | preserve until ctf_arc_close() time). Returns the archive, or NULL and an |
416 | | error in *err (if not NULL). */ |
417 | | ctf_archive_t * |
418 | | ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, |
419 | | const ctf_sect_t *strsect, int *errp) |
420 | 0 | { |
421 | 0 | struct ctf_archive *arc = NULL; |
422 | 0 | int is_archive; |
423 | 0 | ctf_dict_t *fp = NULL; |
424 | |
|
425 | 0 | if (ctfsect->cts_data != NULL |
426 | 0 | && ctfsect->cts_size >= sizeof (struct ctf_archive) |
427 | 0 | && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC)) |
428 | 0 | { |
429 | | /* The archive is mmappable, so this operation is trivial. |
430 | | |
431 | | This buffer is nonmodifiable, so the trick involving mmapping only part |
432 | | of it and storing the length in the magic number is not applicable: so |
433 | | record this fact in the archive-wrapper header. (We cannot record it |
434 | | in the archive, because the archive may very well be a read-only |
435 | | mapping.) */ |
436 | |
|
437 | 0 | is_archive = 1; |
438 | 0 | arc = (struct ctf_archive *) ctfsect->cts_data; |
439 | 0 | } |
440 | 0 | else |
441 | 0 | { |
442 | 0 | is_archive = 0; |
443 | 0 | if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL) |
444 | 0 | { |
445 | 0 | ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF")); |
446 | 0 | return NULL; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect, |
450 | 0 | errp); |
451 | 0 | } |
452 | | |
453 | | /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if |
454 | | not NULL). */ |
455 | | struct ctf_archive * |
456 | | ctf_arc_open_internal (const char *filename, int *errp) |
457 | 0 | { |
458 | 0 | const char *errmsg; |
459 | 0 | int fd; |
460 | 0 | struct stat s; |
461 | 0 | struct ctf_archive *arc; /* (Actually the whole file.) */ |
462 | |
|
463 | 0 | libctf_init_debug(); |
464 | 0 | if ((fd = open (filename, O_RDONLY)) < 0) |
465 | 0 | { |
466 | 0 | errmsg = N_("ctf_arc_open(): cannot open %s"); |
467 | 0 | goto err; |
468 | 0 | } |
469 | 0 | if (fstat (fd, &s) < 0) |
470 | 0 | { |
471 | 0 | errmsg = N_("ctf_arc_open(): cannot stat %s"); |
472 | 0 | goto err_close; |
473 | 0 | } |
474 | | |
475 | 0 | if ((arc = arc_mmap_file (fd, s.st_size)) == NULL) |
476 | 0 | { |
477 | 0 | errmsg = N_("ctf_arc_open(): cannot read in %s"); |
478 | 0 | goto err_close; |
479 | 0 | } |
480 | | |
481 | 0 | if (le64toh (arc->ctfa_magic) != CTFA_MAGIC) |
482 | 0 | { |
483 | 0 | errmsg = N_("ctf_arc_open(): %s: invalid magic number"); |
484 | 0 | errno = ECTF_FMT; |
485 | 0 | goto err_unmap; |
486 | 0 | } |
487 | | |
488 | | /* This horrible hack lets us know how much to unmap when the file is |
489 | | closed. (We no longer need the magic number, and the mapping |
490 | | is private.) */ |
491 | 0 | arc->ctfa_magic = s.st_size; |
492 | 0 | close (fd); |
493 | |
|
494 | 0 | if (errp) |
495 | 0 | *errp = 0; |
496 | |
|
497 | 0 | return arc; |
498 | | |
499 | 0 | err_unmap: |
500 | 0 | arc_mmap_unmap (arc, s.st_size, NULL); |
501 | 0 | err_close: |
502 | 0 | close (fd); |
503 | 0 | err: |
504 | 0 | if (errp) |
505 | 0 | *errp = errno; |
506 | 0 | ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename); |
507 | 0 | return NULL; |
508 | 0 | } |
509 | | |
510 | | /* Close an archive. */ |
511 | | void |
512 | | ctf_arc_close_internal (struct ctf_archive *arc) |
513 | 0 | { |
514 | 0 | if (arc == NULL) |
515 | 0 | return; |
516 | | |
517 | | /* See the comment in ctf_arc_open(). */ |
518 | 0 | arc_mmap_unmap (arc, arc->ctfa_magic, NULL); |
519 | 0 | } |
520 | | |
521 | | /* Public entry point: close an archive, or CTF file. */ |
522 | | void |
523 | | ctf_arc_close (ctf_archive_t *arc) |
524 | 0 | { |
525 | 0 | if (arc == NULL) |
526 | 0 | return; |
527 | | |
528 | 0 | if (arc->ctfi_is_archive) |
529 | 0 | { |
530 | 0 | if (arc->ctfi_unmap_on_close) |
531 | 0 | ctf_arc_close_internal (arc->ctfi_archive); |
532 | 0 | } |
533 | 0 | else |
534 | 0 | ctf_dict_close (arc->ctfi_dict); |
535 | 0 | free (arc->ctfi_symdicts); |
536 | 0 | free (arc->ctfi_symnamedicts); |
537 | 0 | ctf_dynhash_destroy (arc->ctfi_dicts); |
538 | 0 | if (arc->ctfi_free_symsect) |
539 | 0 | free ((void *) arc->ctfi_symsect.cts_data); |
540 | 0 | if (arc->ctfi_free_strsect) |
541 | 0 | free ((void *) arc->ctfi_strsect.cts_data); |
542 | 0 | free (arc->ctfi_data); |
543 | 0 | if (arc->ctfi_bfd_close) |
544 | 0 | arc->ctfi_bfd_close (arc); |
545 | 0 | free (arc); |
546 | 0 | } |
547 | | |
548 | | /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if |
549 | | non-NULL. A name of NULL means to open the default file. */ |
550 | | static ctf_dict_t * |
551 | | ctf_dict_open_internal (const struct ctf_archive *arc, |
552 | | const ctf_sect_t *symsect, |
553 | | const ctf_sect_t *strsect, |
554 | | const char *name, int little_endian, |
555 | | int *errp) |
556 | 0 | { |
557 | 0 | struct ctf_archive_modent *modent; |
558 | 0 | const char *search_nametbl; |
559 | |
|
560 | 0 | if (name == NULL) |
561 | 0 | name = _CTF_SECTION; /* The default name. */ |
562 | |
|
563 | 0 | ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name); |
564 | |
|
565 | 0 | modent = (ctf_archive_modent_t *) ((char *) arc |
566 | 0 | + sizeof (struct ctf_archive)); |
567 | |
|
568 | 0 | search_nametbl = (const char *) arc + le64toh (arc->ctfa_names); |
569 | 0 | modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts), |
570 | 0 | sizeof (struct ctf_archive_modent), |
571 | 0 | search_modent_by_name, (void *) search_nametbl); |
572 | | |
573 | | /* This is actually a common case and normal operation: no error |
574 | | debug output. */ |
575 | 0 | if (modent == NULL) |
576 | 0 | { |
577 | 0 | if (errp) |
578 | 0 | *errp = ECTF_ARNNAME; |
579 | 0 | return NULL; |
580 | 0 | } |
581 | | |
582 | 0 | return ctf_dict_open_by_offset (arc, symsect, strsect, |
583 | 0 | le64toh (modent->ctf_offset), |
584 | 0 | little_endian, errp); |
585 | 0 | } |
586 | | |
587 | | /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if |
588 | | non-NULL. A name of NULL means to open the default file. |
589 | | |
590 | | Use the specified string and symbol table sections. |
591 | | |
592 | | Public entry point. */ |
593 | | ctf_dict_t * |
594 | | ctf_dict_open_sections (const ctf_archive_t *arc, |
595 | | const ctf_sect_t *symsect, |
596 | | const ctf_sect_t *strsect, |
597 | | const char *name, |
598 | | int *errp) |
599 | 0 | { |
600 | 0 | if (errp) |
601 | 0 | *errp = 0; |
602 | |
|
603 | 0 | if (arc->ctfi_is_archive) |
604 | 0 | { |
605 | 0 | ctf_dict_t *ret; |
606 | 0 | ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect, |
607 | 0 | name, arc->ctfi_symsect_little_endian, |
608 | 0 | errp); |
609 | 0 | if (ret) |
610 | 0 | { |
611 | 0 | ret->ctf_archive = (ctf_archive_t *) arc; |
612 | 0 | if (ctf_arc_import_parent (arc, ret, errp) < 0) |
613 | 0 | { |
614 | 0 | ctf_dict_close (ret); |
615 | 0 | return NULL; |
616 | 0 | } |
617 | 0 | } |
618 | 0 | return ret; |
619 | 0 | } |
620 | | |
621 | 0 | if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0)) |
622 | 0 | { |
623 | 0 | if (errp) |
624 | 0 | *errp = ECTF_ARNNAME; |
625 | 0 | return NULL; |
626 | 0 | } |
627 | 0 | arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc; |
628 | | |
629 | | /* Bump the refcount so that the user can ctf_dict_close() it. */ |
630 | 0 | arc->ctfi_dict->ctf_refcnt++; |
631 | 0 | return arc->ctfi_dict; |
632 | 0 | } |
633 | | |
634 | | /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if |
635 | | non-NULL. A name of NULL means to open the default file. |
636 | | |
637 | | Public entry point. */ |
638 | | ctf_dict_t * |
639 | | ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp) |
640 | 0 | { |
641 | 0 | const ctf_sect_t *symsect = &arc->ctfi_symsect; |
642 | 0 | const ctf_sect_t *strsect = &arc->ctfi_strsect; |
643 | |
|
644 | 0 | if (symsect->cts_name == NULL) |
645 | 0 | symsect = NULL; |
646 | 0 | if (strsect->cts_name == NULL) |
647 | 0 | strsect = NULL; |
648 | |
|
649 | 0 | return ctf_dict_open_sections (arc, symsect, strsect, name, errp); |
650 | 0 | } |
651 | | |
652 | | static void |
653 | | ctf_cached_dict_close (void *fp) |
654 | 0 | { |
655 | 0 | ctf_dict_close ((ctf_dict_t *) fp); |
656 | 0 | } |
657 | | |
658 | | /* Return the ctf_dict_t with the given name and cache it in the archive's |
659 | | ctfi_dicts. If this is the first cached dict, designate it the |
660 | | crossdict_cache. */ |
661 | | static ctf_dict_t * |
662 | | ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp) |
663 | 0 | { |
664 | 0 | ctf_dict_t *fp; |
665 | 0 | char *dupname; |
666 | | |
667 | | /* Just return from the cache if possible. */ |
668 | 0 | if (arc->ctfi_dicts |
669 | 0 | && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL)) |
670 | 0 | { |
671 | 0 | fp->ctf_refcnt++; |
672 | 0 | return fp; |
673 | 0 | } |
674 | | |
675 | | /* Not yet cached: open it. */ |
676 | 0 | fp = ctf_dict_open (arc, name, errp); |
677 | 0 | dupname = strdup (name); |
678 | |
|
679 | 0 | if (!fp || !dupname) |
680 | 0 | goto oom; |
681 | | |
682 | 0 | if (arc->ctfi_dicts == NULL) |
683 | 0 | if ((arc->ctfi_dicts |
684 | 0 | = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, |
685 | 0 | free, ctf_cached_dict_close)) == NULL) |
686 | 0 | goto oom; |
687 | | |
688 | 0 | if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0) |
689 | 0 | goto oom; |
690 | 0 | fp->ctf_refcnt++; |
691 | |
|
692 | 0 | if (arc->ctfi_crossdict_cache == NULL) |
693 | 0 | arc->ctfi_crossdict_cache = fp; |
694 | |
|
695 | 0 | return fp; |
696 | | |
697 | 0 | oom: |
698 | 0 | ctf_dict_close (fp); |
699 | 0 | free (dupname); |
700 | 0 | if (errp) |
701 | 0 | *errp = ENOMEM; |
702 | 0 | return NULL; |
703 | 0 | } |
704 | | |
705 | | /* Flush any caches the CTF archive may have open. */ |
706 | | void |
707 | | ctf_arc_flush_caches (ctf_archive_t *wrapper) |
708 | 0 | { |
709 | 0 | free (wrapper->ctfi_symdicts); |
710 | 0 | ctf_dynhash_destroy (wrapper->ctfi_symnamedicts); |
711 | 0 | ctf_dynhash_destroy (wrapper->ctfi_dicts); |
712 | 0 | wrapper->ctfi_symdicts = NULL; |
713 | 0 | wrapper->ctfi_symnamedicts = NULL; |
714 | 0 | wrapper->ctfi_dicts = NULL; |
715 | 0 | wrapper->ctfi_crossdict_cache = NULL; |
716 | 0 | } |
717 | | |
718 | | /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if |
719 | | none, setting 'err' if non-NULL. */ |
720 | | static ctf_dict_t * |
721 | | ctf_dict_open_by_offset (const struct ctf_archive *arc, |
722 | | const ctf_sect_t *symsect, |
723 | | const ctf_sect_t *strsect, size_t offset, |
724 | | int little_endian, int *errp) |
725 | 0 | { |
726 | 0 | ctf_sect_t ctfsect; |
727 | 0 | ctf_dict_t *fp; |
728 | |
|
729 | 0 | ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset); |
730 | |
|
731 | 0 | memset (&ctfsect, 0, sizeof (ctf_sect_t)); |
732 | |
|
733 | 0 | offset += le64toh (arc->ctfa_ctfs); |
734 | |
|
735 | 0 | ctfsect.cts_name = _CTF_SECTION; |
736 | 0 | ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset))); |
737 | 0 | ctfsect.cts_entsize = 1; |
738 | 0 | ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t)); |
739 | 0 | fp = ctf_bufopen (&ctfsect, symsect, strsect, errp); |
740 | 0 | if (fp) |
741 | 0 | { |
742 | 0 | ctf_setmodel (fp, le64toh (arc->ctfa_model)); |
743 | 0 | if (little_endian >= 0) |
744 | 0 | ctf_symsect_endianness (fp, little_endian); |
745 | 0 | } |
746 | 0 | return fp; |
747 | 0 | } |
748 | | |
749 | | /* Backward compatibility. */ |
750 | | ctf_dict_t * |
751 | | ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name, |
752 | | int *errp) |
753 | 0 | { |
754 | 0 | return ctf_dict_open (arc, name, errp); |
755 | 0 | } |
756 | | |
757 | | ctf_dict_t * |
758 | | ctf_arc_open_by_name_sections (const ctf_archive_t *arc, |
759 | | const ctf_sect_t *symsect, |
760 | | const ctf_sect_t *strsect, |
761 | | const char *name, |
762 | | int *errp) |
763 | 0 | { |
764 | 0 | return ctf_dict_open_sections (arc, symsect, strsect, name, errp); |
765 | 0 | } |
766 | | |
767 | | /* Import the parent into a ctf archive, if this is a child, the parent is not |
768 | | already set, and a suitable archive member exists. No error is raised if |
769 | | this is not possible: this is just a best-effort helper operation to give |
770 | | people useful dicts to start with. */ |
771 | | static int |
772 | | ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp) |
773 | 0 | { |
774 | 0 | if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent) |
775 | 0 | { |
776 | 0 | int err = 0; |
777 | 0 | ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc, |
778 | 0 | fp->ctf_parname, &err); |
779 | 0 | if (errp) |
780 | 0 | *errp = err; |
781 | |
|
782 | 0 | if (parent) |
783 | 0 | { |
784 | 0 | ctf_import (fp, parent); |
785 | 0 | ctf_dict_close (parent); |
786 | 0 | } |
787 | 0 | else if (err != ECTF_ARNNAME) |
788 | 0 | return -1; /* errno is set for us. */ |
789 | 0 | } |
790 | 0 | return 0; |
791 | 0 | } |
792 | | |
793 | | /* Return the number of members in an archive. */ |
794 | | size_t |
795 | | ctf_archive_count (const ctf_archive_t *wrapper) |
796 | 0 | { |
797 | 0 | if (!wrapper->ctfi_is_archive) |
798 | 0 | return 1; |
799 | | |
800 | 0 | return le64toh (wrapper->ctfi_archive->ctfa_ndicts); |
801 | 0 | } |
802 | | |
803 | | /* Look up a symbol in an archive by name or index (if the name is set, a lookup |
804 | | by name is done). Return the dict in the archive that the symbol is found |
805 | | in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't |
806 | | have to look it up yourself). The dict is cached, so repeated lookups are |
807 | | nearly free. |
808 | | |
809 | | As usual, you should ctf_dict_close() the returned dict once you are done |
810 | | with it. |
811 | | |
812 | | Returns NULL on error, and an error in errp (if set). */ |
813 | | |
814 | | static ctf_dict_t * |
815 | | ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx, |
816 | | const char *symname, ctf_id_t *typep, int *errp) |
817 | 0 | { |
818 | 0 | ctf_dict_t *fp; |
819 | 0 | void *fpkey; |
820 | 0 | ctf_id_t type; |
821 | | |
822 | | /* The usual non-archive-transparent-wrapper special case. */ |
823 | 0 | if (!wrapper->ctfi_is_archive) |
824 | 0 | { |
825 | 0 | if (!symname) |
826 | 0 | { |
827 | 0 | if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR) |
828 | 0 | { |
829 | 0 | if (errp) |
830 | 0 | *errp = ctf_errno (wrapper->ctfi_dict); |
831 | 0 | return NULL; |
832 | 0 | } |
833 | 0 | } |
834 | 0 | else |
835 | 0 | { |
836 | 0 | if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict, |
837 | 0 | symname)) == CTF_ERR) |
838 | 0 | { |
839 | 0 | if (errp) |
840 | 0 | *errp = ctf_errno (wrapper->ctfi_dict); |
841 | 0 | return NULL; |
842 | 0 | } |
843 | 0 | } |
844 | 0 | if (typep) |
845 | 0 | *typep = type; |
846 | 0 | wrapper->ctfi_dict->ctf_refcnt++; |
847 | 0 | return wrapper->ctfi_dict; |
848 | 0 | } |
849 | | |
850 | 0 | if (wrapper->ctfi_symsect.cts_name == NULL |
851 | 0 | || wrapper->ctfi_symsect.cts_data == NULL |
852 | 0 | || wrapper->ctfi_symsect.cts_size == 0 |
853 | 0 | || wrapper->ctfi_symsect.cts_entsize == 0) |
854 | 0 | { |
855 | 0 | if (errp) |
856 | 0 | *errp = ECTF_NOSYMTAB; |
857 | 0 | return NULL; |
858 | 0 | } |
859 | | |
860 | | /* Make enough space for all possible symbol indexes, if not already done. We |
861 | | cache the originating dictionary of all symbols. The dict links are weak, |
862 | | to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped. |
863 | | We also cache similar mappings for symbol names: these are ordinary |
864 | | dynhashes, with weak links to dicts. */ |
865 | | |
866 | 0 | if (!wrapper->ctfi_symdicts) |
867 | 0 | { |
868 | 0 | if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size |
869 | 0 | / wrapper->ctfi_symsect.cts_entsize, |
870 | 0 | sizeof (ctf_dict_t *))) == NULL) |
871 | 0 | { |
872 | 0 | if (errp) |
873 | 0 | *errp = ENOMEM; |
874 | 0 | return NULL; |
875 | 0 | } |
876 | 0 | } |
877 | 0 | if (!wrapper->ctfi_symnamedicts) |
878 | 0 | { |
879 | 0 | if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string, |
880 | 0 | ctf_hash_eq_string, |
881 | 0 | free, NULL)) == NULL) |
882 | 0 | { |
883 | 0 | if (errp) |
884 | 0 | *errp = ENOMEM; |
885 | 0 | return NULL; |
886 | 0 | } |
887 | 0 | } |
888 | | |
889 | | /* Perhaps the dict in which we found a previous lookup is cached. If it's |
890 | | supposed to be cached but we don't find it, pretend it was always not |
891 | | found: this should never happen, but shouldn't be allowed to cause trouble |
892 | | if it does. */ |
893 | | |
894 | 0 | if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts, |
895 | 0 | symname, NULL, &fpkey)) |
896 | 0 | || (!symname && wrapper->ctfi_symdicts[symidx] != NULL)) |
897 | 0 | { |
898 | 0 | if (symname) |
899 | 0 | fp = (ctf_dict_t *) fpkey; |
900 | 0 | else |
901 | 0 | fp = wrapper->ctfi_symdicts[symidx]; |
902 | |
|
903 | 0 | if (fp == &enosym) |
904 | 0 | goto no_sym; |
905 | | |
906 | 0 | if (symname) |
907 | 0 | { |
908 | 0 | if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR) |
909 | 0 | goto cache_no_sym; |
910 | 0 | } |
911 | 0 | else |
912 | 0 | { |
913 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
914 | 0 | goto cache_no_sym; |
915 | 0 | } |
916 | | |
917 | 0 | if (typep) |
918 | 0 | *typep = type; |
919 | 0 | fp->ctf_refcnt++; |
920 | 0 | return fp; |
921 | 0 | } |
922 | | |
923 | | /* Not cached: find it and cache it. We must track open errors ourselves even |
924 | | if our caller doesn't, to be able to distinguish no-error end-of-iteration |
925 | | from open errors. */ |
926 | | |
927 | 0 | int local_err; |
928 | 0 | int *local_errp; |
929 | 0 | ctf_next_t *i = NULL; |
930 | 0 | const char *name; |
931 | |
|
932 | 0 | if (errp) |
933 | 0 | local_errp = errp; |
934 | 0 | else |
935 | 0 | local_errp = &local_err; |
936 | |
|
937 | 0 | while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL) |
938 | 0 | { |
939 | 0 | if (!symname) |
940 | 0 | { |
941 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR) |
942 | 0 | wrapper->ctfi_symdicts[symidx] = fp; |
943 | 0 | } |
944 | 0 | else |
945 | 0 | { |
946 | 0 | if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR) |
947 | 0 | { |
948 | 0 | char *tmp; |
949 | | /* No error checking, as above. */ |
950 | 0 | if ((tmp = strdup (symname)) != NULL) |
951 | 0 | ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp); |
952 | 0 | } |
953 | 0 | } |
954 | |
|
955 | 0 | if (type != CTF_ERR) |
956 | 0 | { |
957 | 0 | if (typep) |
958 | 0 | *typep = type; |
959 | 0 | ctf_next_destroy (i); |
960 | 0 | return fp; |
961 | 0 | } |
962 | 0 | if (ctf_errno (fp) != ECTF_NOTYPEDAT) |
963 | 0 | { |
964 | 0 | if (errp) |
965 | 0 | *errp = ctf_errno (fp); |
966 | 0 | ctf_dict_close (fp); |
967 | 0 | ctf_next_destroy (i); |
968 | 0 | return NULL; /* errno is set for us. */ |
969 | 0 | } |
970 | 0 | ctf_dict_close (fp); |
971 | 0 | } |
972 | 0 | if (*local_errp != ECTF_NEXT_END) |
973 | 0 | { |
974 | 0 | ctf_next_destroy (i); |
975 | 0 | return NULL; |
976 | 0 | } |
977 | | |
978 | | /* Don't leak end-of-iteration to the caller. */ |
979 | 0 | *local_errp = 0; |
980 | |
|
981 | 0 | cache_no_sym: |
982 | 0 | if (!symname) |
983 | 0 | wrapper->ctfi_symdicts[symidx] = &enosym; |
984 | 0 | else |
985 | 0 | { |
986 | 0 | char *tmp; |
987 | | |
988 | | /* No error checking: if caching fails, there is only a slight performance |
989 | | impact. */ |
990 | 0 | if ((tmp = strdup (symname)) != NULL) |
991 | 0 | if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0) |
992 | 0 | free (tmp); |
993 | 0 | } |
994 | |
|
995 | 0 | no_sym: |
996 | 0 | if (errp) |
997 | 0 | *errp = ECTF_NOTYPEDAT; |
998 | 0 | if (typep) |
999 | 0 | *typep = CTF_ERR; |
1000 | 0 | return NULL; |
1001 | 0 | } |
1002 | | |
1003 | | /* The public API for looking up a symbol by index. */ |
1004 | | ctf_dict_t * |
1005 | | ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx, |
1006 | | ctf_id_t *typep, int *errp) |
1007 | 0 | { |
1008 | 0 | return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp); |
1009 | 0 | } |
1010 | | |
1011 | | /* The public API for looking up a symbol by name. */ |
1012 | | |
1013 | | ctf_dict_t * |
1014 | | ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname, |
1015 | | ctf_id_t *typep, int *errp) |
1016 | 0 | { |
1017 | 0 | return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp); |
1018 | 0 | } |
1019 | | |
1020 | | /* Return all enumeration constants with a given NAME across all dicts in an |
1021 | | archive, similar to ctf_lookup_enumerator_next. The DICT is cached, so |
1022 | | opening costs are paid only once, but (unlike ctf_arc_lookup_symbol* |
1023 | | above) the results of the iterations are not cached. dict and errp are |
1024 | | not optional. */ |
1025 | | |
1026 | | ctf_id_t |
1027 | | ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name, |
1028 | | ctf_next_t **it, int64_t *enum_value, |
1029 | | ctf_dict_t **dict, int *errp) |
1030 | 0 | { |
1031 | 0 | ctf_next_t *i = *it; |
1032 | 0 | ctf_id_t type; |
1033 | 0 | int opened_this_time = 0; |
1034 | 0 | int err; |
1035 | | |
1036 | | /* We have two nested iterators in here: ctn_next tracks archives, while |
1037 | | within it ctn_next_inner tracks enumerators within an archive. We |
1038 | | keep track of the dict by simply reusing the passed-in arg: if it's |
1039 | | changed by the caller, the caller will get an ECTF_WRONGFP error, |
1040 | | so this is quite safe and means we don't have to track the arc and fp |
1041 | | simultaneously in the ctf_next_t. */ |
1042 | |
|
1043 | 0 | if (!i) |
1044 | 0 | { |
1045 | 0 | if ((i = ctf_next_create ()) == NULL) |
1046 | 0 | { |
1047 | 0 | err = ENOMEM; |
1048 | 0 | goto err; |
1049 | 0 | } |
1050 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_arc_lookup_enumerator_next; |
1051 | 0 | i->cu.ctn_arc = arc; |
1052 | 0 | *it = i; |
1053 | 0 | } |
1054 | | |
1055 | 0 | if ((void (*) (void)) ctf_arc_lookup_enumerator_next != i->ctn_iter_fun) |
1056 | 0 | { |
1057 | 0 | err = ECTF_NEXT_WRONGFUN; |
1058 | 0 | goto err; |
1059 | 0 | } |
1060 | | |
1061 | 0 | if (arc != i->cu.ctn_arc) |
1062 | 0 | { |
1063 | 0 | err = ECTF_NEXT_WRONGFP; |
1064 | 0 | goto err; |
1065 | 0 | } |
1066 | | |
1067 | | /* Prevent any earlier end-of-iteration on this dict from confusing the |
1068 | | test below. */ |
1069 | 0 | if (i->ctn_next != NULL) |
1070 | 0 | ctf_set_errno (*dict, 0); |
1071 | |
|
1072 | 0 | do |
1073 | 0 | { |
1074 | | /* At end of one dict, or not started any iterations yet? |
1075 | | Traverse to next dict. If we never returned this dict to the |
1076 | | caller, close it ourselves: the caller will never see it and cannot |
1077 | | do so. */ |
1078 | |
|
1079 | 0 | if (i->ctn_next == NULL || ctf_errno (*dict) == ECTF_NEXT_END) |
1080 | 0 | { |
1081 | 0 | if (opened_this_time) |
1082 | 0 | { |
1083 | 0 | ctf_dict_close (*dict); |
1084 | 0 | *dict = NULL; |
1085 | 0 | opened_this_time = 0; |
1086 | 0 | } |
1087 | |
|
1088 | 0 | *dict = ctf_archive_next (arc, &i->ctn_next, NULL, 0, &err); |
1089 | 0 | if (!*dict) |
1090 | 0 | goto err; |
1091 | 0 | opened_this_time = 1; |
1092 | 0 | } |
1093 | | |
1094 | 0 | type = ctf_lookup_enumerator_next (*dict, name, &i->ctn_next_inner, |
1095 | 0 | enum_value); |
1096 | 0 | } |
1097 | 0 | while (type == CTF_ERR && ctf_errno (*dict) == ECTF_NEXT_END); |
1098 | | |
1099 | 0 | if (type == CTF_ERR) |
1100 | 0 | { |
1101 | 0 | err = ctf_errno (*dict); |
1102 | 0 | goto err; |
1103 | 0 | } |
1104 | | |
1105 | | /* If this dict is being reused from the previous iteration, bump its |
1106 | | refcnt: the caller is going to close it and has no idea that we didn't |
1107 | | open it this time round. */ |
1108 | 0 | if (!opened_this_time) |
1109 | 0 | ctf_ref (*dict); |
1110 | |
|
1111 | 0 | return type; |
1112 | | |
1113 | 0 | err: /* Also ECTF_NEXT_END. */ |
1114 | 0 | if (opened_this_time) |
1115 | 0 | { |
1116 | 0 | ctf_dict_close (*dict); |
1117 | 0 | *dict = NULL; |
1118 | 0 | } |
1119 | |
|
1120 | 0 | ctf_next_destroy (i); |
1121 | 0 | *it = NULL; |
1122 | 0 | if (errp) |
1123 | 0 | *errp = err; |
1124 | 0 | return CTF_ERR; |
1125 | 0 | } |
1126 | | |
1127 | | /* Raw iteration over all CTF files in an archive. We pass the raw data for all |
1128 | | CTF files in turn to the specified callback function. */ |
1129 | | static int |
1130 | | ctf_archive_raw_iter_internal (const struct ctf_archive *arc, |
1131 | | ctf_archive_raw_member_f *func, void *data) |
1132 | 0 | { |
1133 | 0 | int rc; |
1134 | 0 | size_t i; |
1135 | 0 | struct ctf_archive_modent *modent; |
1136 | 0 | const char *nametbl; |
1137 | |
|
1138 | 0 | modent = (ctf_archive_modent_t *) ((char *) arc |
1139 | 0 | + sizeof (struct ctf_archive)); |
1140 | 0 | nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); |
1141 | |
|
1142 | 0 | for (i = 0; i < le64toh (arc->ctfa_ndicts); i++) |
1143 | 0 | { |
1144 | 0 | const char *name; |
1145 | 0 | char *fp; |
1146 | |
|
1147 | 0 | name = &nametbl[le64toh (modent[i].name_offset)]; |
1148 | 0 | fp = ((char *) arc + le64toh (arc->ctfa_ctfs) |
1149 | 0 | + le64toh (modent[i].ctf_offset)); |
1150 | |
|
1151 | 0 | if ((rc = func (name, (void *) (fp + sizeof (uint64_t)), |
1152 | 0 | le64toh (*((uint64_t *) fp)), data)) != 0) |
1153 | 0 | return rc; |
1154 | 0 | } |
1155 | 0 | return 0; |
1156 | 0 | } |
1157 | | |
1158 | | /* Raw iteration over all CTF files in an archive: public entry point. |
1159 | | |
1160 | | Returns -EINVAL if not supported for this sort of archive. */ |
1161 | | int |
1162 | | ctf_archive_raw_iter (const ctf_archive_t *arc, |
1163 | | ctf_archive_raw_member_f * func, void *data) |
1164 | 0 | { |
1165 | 0 | if (arc->ctfi_is_archive) |
1166 | 0 | return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data); |
1167 | | |
1168 | 0 | return -EINVAL; /* Not supported. */ |
1169 | 0 | } |
1170 | | |
1171 | | /* Iterate over all CTF files in an archive: public entry point. We pass all |
1172 | | CTF files in turn to the specified callback function. */ |
1173 | | int |
1174 | | ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func, |
1175 | | void *data) |
1176 | 0 | { |
1177 | 0 | ctf_next_t *i = NULL; |
1178 | 0 | ctf_dict_t *fp; |
1179 | 0 | const char *name; |
1180 | 0 | int err = 0; |
1181 | |
|
1182 | 0 | while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL) |
1183 | 0 | { |
1184 | 0 | int rc; |
1185 | |
|
1186 | 0 | if ((rc = func (fp, name, data)) != 0) |
1187 | 0 | { |
1188 | 0 | ctf_dict_close (fp); |
1189 | 0 | ctf_next_destroy (i); |
1190 | 0 | return rc; |
1191 | 0 | } |
1192 | 0 | ctf_dict_close (fp); |
1193 | 0 | } |
1194 | 0 | if (err != ECTF_NEXT_END && err != 0) |
1195 | 0 | { |
1196 | 0 | ctf_next_destroy (i); |
1197 | 0 | return -1; |
1198 | 0 | } |
1199 | 0 | return 0; |
1200 | 0 | } |
1201 | | |
1202 | | /* Iterate over all CTF files in an archive, returning each dict in turn as a |
1203 | | ctf_dict_t, and NULL on error or end of iteration. It is the caller's |
1204 | | responsibility to close it. Parent dicts may be skipped. |
1205 | | |
1206 | | The archive member is cached for rapid return on future calls. |
1207 | | |
1208 | | We identify parents by name rather than by flag value: for now, with the |
1209 | | linker only emitting parents named _CTF_SECTION, this works well enough. */ |
1210 | | |
1211 | | ctf_dict_t * |
1212 | | ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name, |
1213 | | int skip_parent, int *errp) |
1214 | 0 | { |
1215 | 0 | ctf_dict_t *f; |
1216 | 0 | ctf_next_t *i = *it; |
1217 | 0 | struct ctf_archive *arc; |
1218 | 0 | struct ctf_archive_modent *modent; |
1219 | 0 | const char *nametbl; |
1220 | 0 | const char *name_; |
1221 | |
|
1222 | 0 | if (!i) |
1223 | 0 | { |
1224 | 0 | if ((i = ctf_next_create()) == NULL) |
1225 | 0 | { |
1226 | 0 | if (errp) |
1227 | 0 | *errp = ENOMEM; |
1228 | 0 | return NULL; |
1229 | 0 | } |
1230 | 0 | i->cu.ctn_arc = wrapper; |
1231 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_archive_next; |
1232 | 0 | *it = i; |
1233 | 0 | } |
1234 | | |
1235 | 0 | if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun) |
1236 | 0 | { |
1237 | 0 | if (errp) |
1238 | 0 | *errp = ECTF_NEXT_WRONGFUN; |
1239 | 0 | return NULL; |
1240 | 0 | } |
1241 | | |
1242 | 0 | if (wrapper != i->cu.ctn_arc) |
1243 | 0 | { |
1244 | 0 | if (errp) |
1245 | 0 | *errp = ECTF_NEXT_WRONGFP; |
1246 | 0 | return NULL; |
1247 | 0 | } |
1248 | | |
1249 | | /* Iteration is made a bit more complex by the need to handle ctf_dict_t's |
1250 | | transparently wrapped in a single-member archive. These are parents: if |
1251 | | skip_parent is on, they are skipped and the iterator terminates |
1252 | | immediately. */ |
1253 | | |
1254 | 0 | if (!wrapper->ctfi_is_archive && i->ctn_n == 0) |
1255 | 0 | { |
1256 | 0 | i->ctn_n++; |
1257 | 0 | if (!skip_parent) |
1258 | 0 | { |
1259 | 0 | wrapper->ctfi_dict->ctf_refcnt++; |
1260 | 0 | if (name) |
1261 | 0 | *name = _CTF_SECTION; |
1262 | 0 | return wrapper->ctfi_dict; |
1263 | 0 | } |
1264 | 0 | } |
1265 | | |
1266 | 0 | arc = wrapper->ctfi_archive; |
1267 | | |
1268 | | /* The loop keeps going when skip_parent is on as long as the member we find |
1269 | | is the parent (i.e. at most two iterations, but possibly an early return if |
1270 | | *all* we have is a parent). */ |
1271 | |
|
1272 | 0 | do |
1273 | 0 | { |
1274 | 0 | if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts))) |
1275 | 0 | { |
1276 | 0 | ctf_next_destroy (i); |
1277 | 0 | *it = NULL; |
1278 | 0 | if (errp) |
1279 | 0 | *errp = ECTF_NEXT_END; |
1280 | 0 | return NULL; |
1281 | 0 | } |
1282 | | |
1283 | 0 | modent = (ctf_archive_modent_t *) ((char *) arc |
1284 | 0 | + sizeof (struct ctf_archive)); |
1285 | 0 | nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); |
1286 | |
|
1287 | 0 | name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)]; |
1288 | 0 | i->ctn_n++; |
1289 | 0 | } |
1290 | 0 | while (skip_parent && strcmp (name_, _CTF_SECTION) == 0); |
1291 | | |
1292 | 0 | if (name) |
1293 | 0 | *name = name_; |
1294 | |
|
1295 | 0 | f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp); |
1296 | 0 | return f; |
1297 | 0 | } |
1298 | | |
1299 | | #ifdef HAVE_MMAP |
1300 | | /* Map the header in. Only used on new, empty files. */ |
1301 | | static void *arc_mmap_header (int fd, size_t headersz) |
1302 | 0 | { |
1303 | 0 | void *hdr; |
1304 | 0 | if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, |
1305 | 0 | 0)) == MAP_FAILED) |
1306 | 0 | return NULL; |
1307 | 0 | return hdr; |
1308 | 0 | } |
1309 | | |
1310 | | /* mmap() the whole file, for reading only. (Map it writably, but privately: we |
1311 | | need to modify the region, but don't need anyone else to see the |
1312 | | modifications.) */ |
1313 | | static void *arc_mmap_file (int fd, size_t size) |
1314 | 0 | { |
1315 | 0 | void *arc; |
1316 | 0 | if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, |
1317 | 0 | fd, 0)) == MAP_FAILED) |
1318 | 0 | return NULL; |
1319 | 0 | return arc; |
1320 | 0 | } |
1321 | | |
1322 | | /* Persist the header to disk. */ |
1323 | | static int arc_mmap_writeout (int fd _libctf_unused_, void *header, |
1324 | | size_t headersz, const char **errmsg) |
1325 | 0 | { |
1326 | 0 | if (msync (header, headersz, MS_ASYNC) < 0) |
1327 | 0 | { |
1328 | 0 | if (errmsg) |
1329 | 0 | *errmsg = N_("arc_mmap_writeout(): cannot sync after writing " |
1330 | 0 | "to %s: %s"); |
1331 | 0 | return -1; |
1332 | 0 | } |
1333 | 0 | return 0; |
1334 | 0 | } |
1335 | | |
1336 | | /* Unmap the region. */ |
1337 | | static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg) |
1338 | 0 | { |
1339 | 0 | if (munmap (header, headersz) < 0) |
1340 | 0 | { |
1341 | 0 | if (errmsg) |
1342 | 0 | *errmsg = N_("arc_mmap_munmap(): cannot unmap after writing " |
1343 | 0 | "to %s: %s"); |
1344 | 0 | return -1; |
1345 | 0 | } |
1346 | 0 | return 0; |
1347 | 0 | } |
1348 | | #else |
1349 | | /* Map the header in. Only used on new, empty files. */ |
1350 | | static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz) |
1351 | | { |
1352 | | void *hdr; |
1353 | | if ((hdr = malloc (headersz)) == NULL) |
1354 | | return NULL; |
1355 | | return hdr; |
1356 | | } |
1357 | | |
1358 | | /* Pull in the whole file, for reading only. We assume the current file |
1359 | | position is at the start of the file. */ |
1360 | | static void *arc_mmap_file (int fd, size_t size) |
1361 | | { |
1362 | | char *data; |
1363 | | |
1364 | | if ((data = malloc (size)) == NULL) |
1365 | | return NULL; |
1366 | | |
1367 | | if (ctf_pread (fd, data, size, 0) < 0) |
1368 | | { |
1369 | | free (data); |
1370 | | return NULL; |
1371 | | } |
1372 | | return data; |
1373 | | } |
1374 | | |
1375 | | /* Persist the header to disk. */ |
1376 | | static int arc_mmap_writeout (int fd, void *header, size_t headersz, |
1377 | | const char **errmsg) |
1378 | | { |
1379 | | ssize_t len; |
1380 | | char *data = (char *) header; |
1381 | | ssize_t count = headersz; |
1382 | | |
1383 | | if ((lseek (fd, 0, SEEK_SET)) < 0) |
1384 | | { |
1385 | | if (errmsg) |
1386 | | *errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to " |
1387 | | "%s: %s"); |
1388 | | return -1; |
1389 | | } |
1390 | | |
1391 | | while (headersz > 0) |
1392 | | { |
1393 | | if ((len = write (fd, data, count)) < 0) |
1394 | | { |
1395 | | if (errmsg) |
1396 | | *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s"); |
1397 | | return len; |
1398 | | } |
1399 | | if (len == EINTR) |
1400 | | continue; |
1401 | | |
1402 | | if (len == 0) /* EOF. */ |
1403 | | break; |
1404 | | |
1405 | | count -= len; |
1406 | | data += len; |
1407 | | } |
1408 | | return 0; |
1409 | | } |
1410 | | |
1411 | | /* Unmap the region. */ |
1412 | | static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_, |
1413 | | const char **errmsg _libctf_unused_) |
1414 | | { |
1415 | | free (header); |
1416 | | return 0; |
1417 | | } |
1418 | | #endif |