18dffb485Schristos /* CTF archive files. 2*12989c96Schristos Copyright (C) 2019-2024 Free Software Foundation, Inc. 38dffb485Schristos 48dffb485Schristos This file is part of libctf. 58dffb485Schristos 68dffb485Schristos libctf is free software; you can redistribute it and/or modify it under 78dffb485Schristos the terms of the GNU General Public License as published by the Free 88dffb485Schristos Software Foundation; either version 3, or (at your option) any later 98dffb485Schristos version. 108dffb485Schristos 118dffb485Schristos This program is distributed in the hope that it will be useful, but 128dffb485Schristos WITHOUT ANY WARRANTY; without even the implied warranty of 138dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 148dffb485Schristos See the GNU General Public License for more details. 158dffb485Schristos 168dffb485Schristos You should have received a copy of the GNU General Public License 178dffb485Schristos along with this program; see the file COPYING. If not see 188dffb485Schristos <http://www.gnu.org/licenses/>. */ 198dffb485Schristos 208dffb485Schristos #include <ctf-impl.h> 218dffb485Schristos #include <sys/types.h> 228dffb485Schristos #include <sys/stat.h> 238dffb485Schristos #include <elf.h> 248dffb485Schristos #include "ctf-endian.h" 258dffb485Schristos #include <errno.h> 268dffb485Schristos #include <fcntl.h> 278dffb485Schristos #include <stdio.h> 288dffb485Schristos #include <string.h> 298dffb485Schristos #include <unistd.h> 308dffb485Schristos 318dffb485Schristos #ifdef HAVE_MMAP 328dffb485Schristos #include <sys/mman.h> 338dffb485Schristos #endif 348dffb485Schristos 354b169a6bSchristos static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold); 364b169a6bSchristos static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc, 378dffb485Schristos const ctf_sect_t *symsect, 388dffb485Schristos const ctf_sect_t *strsect, 394b169a6bSchristos size_t offset, int little_endian, 404b169a6bSchristos int *errp); 418dffb485Schristos static int sort_modent_by_name (const void *one, const void *two, void *n); 428dffb485Schristos static void *arc_mmap_header (int fd, size_t headersz); 438dffb485Schristos static void *arc_mmap_file (int fd, size_t size); 448dffb485Schristos static int arc_mmap_writeout (int fd, void *header, size_t headersz, 458dffb485Schristos const char **errmsg); 468dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg); 47*12989c96Schristos static int ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, 48*12989c96Schristos int *errp); 494b169a6bSchristos 504b169a6bSchristos /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts 514b169a6bSchristos and ctfi_symnamedicts. Never initialized. */ 524b169a6bSchristos static ctf_dict_t enosym; 538dffb485Schristos 548dffb485Schristos /* Write out a CTF archive to the start of the file referenced by the passed-in 554b169a6bSchristos fd. The entries in CTF_DICTS are referenced by name: the names are passed in 564b169a6bSchristos the names array, which must have CTF_DICTS entries. 578dffb485Schristos 588dffb485Schristos Returns 0 on success, or an errno, or an ECTF_* value. */ 598dffb485Schristos int 604b169a6bSchristos ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt, 618dffb485Schristos const char **names, size_t threshold) 628dffb485Schristos { 638dffb485Schristos const char *errmsg; 648dffb485Schristos struct ctf_archive *archdr; 658dffb485Schristos size_t i; 668dffb485Schristos char dummy = 0; 678dffb485Schristos size_t headersz; 688dffb485Schristos ssize_t namesz; 698dffb485Schristos size_t ctf_startoffs; /* Start of the section we are working over. */ 708dffb485Schristos char *nametbl = NULL; /* The name table. */ 718dffb485Schristos char *np; 728dffb485Schristos off_t nameoffs; 738dffb485Schristos struct ctf_archive_modent *modent; 748dffb485Schristos 758dffb485Schristos ctf_dprintf ("Writing CTF archive with %lu files\n", 764b169a6bSchristos (unsigned long) ctf_dict_cnt); 778dffb485Schristos 788dffb485Schristos /* Figure out the size of the mmap()ed header, including the 798dffb485Schristos ctf_archive_modent array. We assume that all of this needs no 808dffb485Schristos padding: a likely assumption, given that it's all made up of 818dffb485Schristos uint64_t's. */ 828dffb485Schristos headersz = sizeof (struct ctf_archive) 834b169a6bSchristos + (ctf_dict_cnt * sizeof (uint64_t) * 2); 848dffb485Schristos ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz); 858dffb485Schristos 868dffb485Schristos /* From now on we work in two pieces: an mmap()ed region from zero up to the 878dffb485Schristos headersz, and a region updated via write() starting after that, containing 888dffb485Schristos all the tables. Platforms that do not support mmap() just use write(). */ 898dffb485Schristos ctf_startoffs = headersz; 908dffb485Schristos if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0) 918dffb485Schristos { 928dffb485Schristos errmsg = N_("ctf_arc_write(): cannot extend file while writing"); 938dffb485Schristos goto err; 948dffb485Schristos } 958dffb485Schristos 968dffb485Schristos if (write (fd, &dummy, 1) < 0) 978dffb485Schristos { 988dffb485Schristos errmsg = N_("ctf_arc_write(): cannot extend file while writing"); 998dffb485Schristos goto err; 1008dffb485Schristos } 1018dffb485Schristos 1028dffb485Schristos if ((archdr = arc_mmap_header (fd, headersz)) == NULL) 1038dffb485Schristos { 1048dffb485Schristos errmsg = N_("ctf_arc_write(): cannot mmap"); 1058dffb485Schristos goto err; 1068dffb485Schristos } 1078dffb485Schristos 1088dffb485Schristos /* Fill in everything we can, which is everything other than the name 1098dffb485Schristos table offset. */ 1108dffb485Schristos archdr->ctfa_magic = htole64 (CTFA_MAGIC); 1114b169a6bSchristos archdr->ctfa_ndicts = htole64 (ctf_dict_cnt); 1128dffb485Schristos archdr->ctfa_ctfs = htole64 (ctf_startoffs); 1138dffb485Schristos 1148dffb485Schristos /* We could validate that all CTF files have the same data model, but 1158dffb485Schristos since any reasonable construction process will be building things of 1168dffb485Schristos only one bitness anyway, this is pretty pointless, so just use the 1178dffb485Schristos model of the first CTF file for all of them. (It *is* valid to 1188dffb485Schristos create an empty archive: the value of ctfa_model is irrelevant in 1198dffb485Schristos this case, but we must be sure not to dereference uninitialized 1208dffb485Schristos memory.) */ 1218dffb485Schristos 1224b169a6bSchristos if (ctf_dict_cnt > 0) 1234b169a6bSchristos archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0])); 1248dffb485Schristos 1258dffb485Schristos /* Now write out the CTFs: ctf_archive_modent array via the mapping, 1268dffb485Schristos ctfs via write(). The names themselves have not been written yet: we 1278dffb485Schristos track them in a local strtab until the time is right, and sort the 1288dffb485Schristos modents array after construction. 1298dffb485Schristos 1308dffb485Schristos The name table is not sorted. */ 1318dffb485Schristos 1324b169a6bSchristos for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++) 1338dffb485Schristos namesz += strlen (names[i]) + 1; 1348dffb485Schristos 1358dffb485Schristos nametbl = malloc (namesz); 1368dffb485Schristos if (nametbl == NULL) 1378dffb485Schristos { 1388dffb485Schristos errmsg = N_("ctf_arc_write(): error writing named CTF to archive"); 1398dffb485Schristos goto err_unmap; 1408dffb485Schristos } 1418dffb485Schristos 1428dffb485Schristos for (i = 0, namesz = 0, 1438dffb485Schristos modent = (ctf_archive_modent_t *) ((char *) archdr 1448dffb485Schristos + sizeof (struct ctf_archive)); 1454b169a6bSchristos i < le64toh (archdr->ctfa_ndicts); i++) 1468dffb485Schristos { 1478dffb485Schristos off_t off; 1488dffb485Schristos 1498dffb485Schristos strcpy (&nametbl[namesz], names[i]); 1508dffb485Schristos 1514b169a6bSchristos off = arc_write_one_ctf (ctf_dicts[i], fd, threshold); 1528dffb485Schristos if ((off < 0) && (off > -ECTF_BASE)) 1538dffb485Schristos { 1548dffb485Schristos errmsg = N_("ctf_arc_write(): cannot determine file " 1558dffb485Schristos "position while writing to archive"); 1568dffb485Schristos goto err_free; 1578dffb485Schristos } 1588dffb485Schristos if (off < 0) 1598dffb485Schristos { 1608dffb485Schristos errmsg = N_("ctf_arc_write(): cannot write CTF file to archive"); 1618dffb485Schristos errno = off * -1; 1628dffb485Schristos goto err_free; 1638dffb485Schristos } 1648dffb485Schristos 1658dffb485Schristos modent->name_offset = htole64 (namesz); 1668dffb485Schristos modent->ctf_offset = htole64 (off - ctf_startoffs); 1678dffb485Schristos namesz += strlen (names[i]) + 1; 1688dffb485Schristos modent++; 1698dffb485Schristos } 1708dffb485Schristos 1718dffb485Schristos ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr 1728dffb485Schristos + sizeof (struct ctf_archive)), 1734b169a6bSchristos le64toh (archdr->ctfa_ndicts), 1748dffb485Schristos sizeof (struct ctf_archive_modent), sort_modent_by_name, 1758dffb485Schristos nametbl); 1768dffb485Schristos 1778dffb485Schristos /* Now the name table. */ 1788dffb485Schristos 1798dffb485Schristos if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0) 1808dffb485Schristos { 1818dffb485Schristos errmsg = N_("ctf_arc_write(): cannot get current file position " 1828dffb485Schristos "in archive"); 1838dffb485Schristos goto err_free; 1848dffb485Schristos } 1858dffb485Schristos archdr->ctfa_names = htole64 (nameoffs); 1868dffb485Schristos np = nametbl; 1878dffb485Schristos while (namesz > 0) 1888dffb485Schristos { 1898dffb485Schristos ssize_t len; 1908dffb485Schristos if ((len = write (fd, np, namesz)) < 0) 1918dffb485Schristos { 1928dffb485Schristos errmsg = N_("ctf_arc_write(): cannot write name table to archive"); 1938dffb485Schristos goto err_free; 1948dffb485Schristos } 1958dffb485Schristos namesz -= len; 1968dffb485Schristos np += len; 1978dffb485Schristos } 1988dffb485Schristos free (nametbl); 1998dffb485Schristos 2008dffb485Schristos if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0) 2018dffb485Schristos goto err_unmap; 2028dffb485Schristos if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0) 2038dffb485Schristos goto err; 2048dffb485Schristos return 0; 2058dffb485Schristos 2068dffb485Schristos err_free: 2078dffb485Schristos free (nametbl); 2088dffb485Schristos err_unmap: 2098dffb485Schristos arc_mmap_unmap (archdr, headersz, NULL); 2108dffb485Schristos err: 2118dffb485Schristos /* We report errors into the first file in the archive, if any: if this is a 2128dffb485Schristos zero-file archive, put it in the open-errors stream for lack of anywhere 2138dffb485Schristos else for it to go. */ 2144b169a6bSchristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, "%s", 2158dffb485Schristos gettext (errmsg)); 2168dffb485Schristos return errno; 2178dffb485Schristos } 2188dffb485Schristos 2194b169a6bSchristos /* Write out a CTF archive. The entries in CTF_DICTS are referenced by name: 2204b169a6bSchristos the names are passed in the names array, which must have CTF_DICTS entries. 2218dffb485Schristos 2228dffb485Schristos If the filename is NULL, create a temporary file and return a pointer to it. 2238dffb485Schristos 2248dffb485Schristos Returns 0 on success, or an errno, or an ECTF_* value. */ 2258dffb485Schristos int 2264b169a6bSchristos ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt, 2278dffb485Schristos const char **names, size_t threshold) 2288dffb485Schristos { 2298dffb485Schristos int err; 2308dffb485Schristos int fd; 2318dffb485Schristos 2328dffb485Schristos if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0) 2338dffb485Schristos { 2344b169a6bSchristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, 2358dffb485Schristos _("ctf_arc_write(): cannot create %s"), file); 2368dffb485Schristos return errno; 2378dffb485Schristos } 2388dffb485Schristos 2394b169a6bSchristos err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, names, threshold); 2408dffb485Schristos if (err) 2418dffb485Schristos goto err_close; 2428dffb485Schristos 2438dffb485Schristos if ((err = close (fd)) < 0) 2444b169a6bSchristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, 2458dffb485Schristos _("ctf_arc_write(): cannot close after writing to archive")); 2468dffb485Schristos goto err; 2478dffb485Schristos 2488dffb485Schristos err_close: 2498dffb485Schristos (void) close (fd); 2508dffb485Schristos err: 2518dffb485Schristos if (err < 0) 2528dffb485Schristos unlink (file); 2538dffb485Schristos 2548dffb485Schristos return err; 2558dffb485Schristos } 2568dffb485Schristos 257*12989c96Schristos /* Write one CTF dict out. Return the file position of the written file (or 2588dffb485Schristos rather, of the file-size uint64_t that precedes it): negative return is a 2598dffb485Schristos negative errno or ctf_errno value. On error, the file position may no longer 2608dffb485Schristos be at the end of the file. */ 2618dffb485Schristos static off_t 2624b169a6bSchristos arc_write_one_ctf (ctf_dict_t *f, int fd, size_t threshold) 2638dffb485Schristos { 2648dffb485Schristos off_t off, end_off; 2658dffb485Schristos uint64_t ctfsz = 0; 2668dffb485Schristos char *ctfszp; 2678dffb485Schristos size_t ctfsz_len; 2684b169a6bSchristos int (*writefn) (ctf_dict_t * fp, int fd); 2698dffb485Schristos 2708dffb485Schristos if ((off = lseek (fd, 0, SEEK_CUR)) < 0) 2718dffb485Schristos return errno * -1; 2728dffb485Schristos 2738dffb485Schristos if (f->ctf_size > threshold) 2748dffb485Schristos writefn = ctf_compress_write; 2758dffb485Schristos else 2768dffb485Schristos writefn = ctf_write; 2778dffb485Schristos 2788dffb485Schristos /* This zero-write turns into the size in a moment. */ 2798dffb485Schristos ctfsz_len = sizeof (ctfsz); 2808dffb485Schristos ctfszp = (char *) &ctfsz; 2818dffb485Schristos while (ctfsz_len > 0) 2828dffb485Schristos { 2838dffb485Schristos ssize_t writelen = write (fd, ctfszp, ctfsz_len); 2848dffb485Schristos if (writelen < 0) 2858dffb485Schristos return errno * -1; 2868dffb485Schristos ctfsz_len -= writelen; 2878dffb485Schristos ctfszp += writelen; 2888dffb485Schristos } 2898dffb485Schristos 2908dffb485Schristos if (writefn (f, fd) != 0) 2918dffb485Schristos return f->ctf_errno * -1; 2928dffb485Schristos 2938dffb485Schristos if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0) 2948dffb485Schristos return errno * -1; 2958dffb485Schristos ctfsz = htole64 (end_off - off); 2968dffb485Schristos 2978dffb485Schristos if ((lseek (fd, off, SEEK_SET)) < 0) 2988dffb485Schristos return errno * -1; 2998dffb485Schristos 3008dffb485Schristos /* ... here. */ 3018dffb485Schristos ctfsz_len = sizeof (ctfsz); 3028dffb485Schristos ctfszp = (char *) &ctfsz; 3038dffb485Schristos while (ctfsz_len > 0) 3048dffb485Schristos { 3058dffb485Schristos ssize_t writelen = write (fd, ctfszp, ctfsz_len); 3068dffb485Schristos if (writelen < 0) 3078dffb485Schristos return errno * -1; 3088dffb485Schristos ctfsz_len -= writelen; 3098dffb485Schristos ctfszp += writelen; 3108dffb485Schristos } 3118dffb485Schristos 3128dffb485Schristos end_off = LCTF_ALIGN_OFFS (end_off, 8); 3138dffb485Schristos if ((lseek (fd, end_off, SEEK_SET)) < 0) 3148dffb485Schristos return errno * -1; 3158dffb485Schristos 3168dffb485Schristos return off; 3178dffb485Schristos } 3188dffb485Schristos 3198dffb485Schristos /* qsort() function to sort the array of struct ctf_archive_modents into 3208dffb485Schristos ascending name order. */ 3218dffb485Schristos static int 3228dffb485Schristos sort_modent_by_name (const void *one, const void *two, void *n) 3238dffb485Schristos { 3248dffb485Schristos const struct ctf_archive_modent *a = one; 3258dffb485Schristos const struct ctf_archive_modent *b = two; 3268dffb485Schristos char *nametbl = n; 3278dffb485Schristos 3288dffb485Schristos return strcmp (&nametbl[le64toh (a->name_offset)], 3298dffb485Schristos &nametbl[le64toh (b->name_offset)]); 3308dffb485Schristos } 3318dffb485Schristos 3328dffb485Schristos /* bsearch_r() function to search for a given name in the sorted array of struct 3338dffb485Schristos ctf_archive_modents. */ 3348dffb485Schristos static int 3358dffb485Schristos search_modent_by_name (const void *key, const void *ent, void *arg) 3368dffb485Schristos { 3378dffb485Schristos const char *k = key; 3388dffb485Schristos const struct ctf_archive_modent *v = ent; 3398dffb485Schristos const char *search_nametbl = arg; 3408dffb485Schristos 3418dffb485Schristos return strcmp (k, &search_nametbl[le64toh (v->name_offset)]); 3428dffb485Schristos } 3438dffb485Schristos 3448dffb485Schristos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a 3454b169a6bSchristos ctf_dict. Closes ARC and/or FP on error. Arrange to free the SYMSECT or 3468dffb485Schristos STRSECT, as needed, on close. Possibly do not unmap on close. */ 3478dffb485Schristos 3488dffb485Schristos struct ctf_archive_internal * 3498dffb485Schristos ctf_new_archive_internal (int is_archive, int unmap_on_close, 3508dffb485Schristos struct ctf_archive *arc, 3514b169a6bSchristos ctf_dict_t *fp, const ctf_sect_t *symsect, 3528dffb485Schristos const ctf_sect_t *strsect, 3538dffb485Schristos int *errp) 3548dffb485Schristos { 3558dffb485Schristos struct ctf_archive_internal *arci; 3568dffb485Schristos 3578dffb485Schristos if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL) 3588dffb485Schristos { 3598dffb485Schristos if (is_archive) 3608dffb485Schristos { 3618dffb485Schristos if (unmap_on_close) 3628dffb485Schristos ctf_arc_close_internal (arc); 3638dffb485Schristos } 3648dffb485Schristos else 3654b169a6bSchristos ctf_dict_close (fp); 3668dffb485Schristos return (ctf_set_open_errno (errp, errno)); 3678dffb485Schristos } 3688dffb485Schristos arci->ctfi_is_archive = is_archive; 3698dffb485Schristos if (is_archive) 3708dffb485Schristos arci->ctfi_archive = arc; 3718dffb485Schristos else 3724b169a6bSchristos arci->ctfi_dict = fp; 3738dffb485Schristos if (symsect) 3748dffb485Schristos memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect)); 3758dffb485Schristos if (strsect) 3768dffb485Schristos memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect)); 3778dffb485Schristos arci->ctfi_free_symsect = 0; 3788dffb485Schristos arci->ctfi_free_strsect = 0; 3798dffb485Schristos arci->ctfi_unmap_on_close = unmap_on_close; 3804b169a6bSchristos arci->ctfi_symsect_little_endian = -1; 3818dffb485Schristos 3828dffb485Schristos return arci; 3838dffb485Schristos } 3848dffb485Schristos 3854b169a6bSchristos /* Set the symbol-table endianness of an archive (defaulting the symtab 3864b169a6bSchristos endianness of all ctf_file_t's opened from that archive). */ 3874b169a6bSchristos void 3884b169a6bSchristos ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian) 3894b169a6bSchristos { 3904b169a6bSchristos arc->ctfi_symsect_little_endian = !!little_endian; 3914b169a6bSchristos if (!arc->ctfi_is_archive) 3924b169a6bSchristos ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian); 3934b169a6bSchristos } 3944b169a6bSchristos 3954b169a6bSchristos /* Get the CTF preamble from data in a buffer, which may be either an archive or 3964b169a6bSchristos a CTF dict. If multiple dicts are present in an archive, the preamble comes 3974b169a6bSchristos from an arbitrary dict. The preamble is a pointer into the ctfsect passed 3984b169a6bSchristos in. */ 3994b169a6bSchristos 4004b169a6bSchristos const ctf_preamble_t * 4014b169a6bSchristos ctf_arc_bufpreamble (const ctf_sect_t *ctfsect) 4024b169a6bSchristos { 403*12989c96Schristos if (ctfsect->cts_data != NULL 404*12989c96Schristos && ctfsect->cts_size > sizeof (uint64_t) 405*12989c96Schristos && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC)) 4064b169a6bSchristos { 4074b169a6bSchristos struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data; 4084b169a6bSchristos return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs) 4094b169a6bSchristos + sizeof (uint64_t)); 4104b169a6bSchristos } 4114b169a6bSchristos else 4124b169a6bSchristos return (const ctf_preamble_t *) ctfsect->cts_data; 4134b169a6bSchristos } 4144b169a6bSchristos 4158dffb485Schristos /* Open a CTF archive or dictionary from data in a buffer (which the caller must 4168dffb485Schristos preserve until ctf_arc_close() time). Returns the archive, or NULL and an 4178dffb485Schristos error in *err (if not NULL). */ 4188dffb485Schristos ctf_archive_t * 4198dffb485Schristos ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, 4208dffb485Schristos const ctf_sect_t *strsect, int *errp) 4218dffb485Schristos { 4228dffb485Schristos struct ctf_archive *arc = NULL; 4238dffb485Schristos int is_archive; 4244b169a6bSchristos ctf_dict_t *fp = NULL; 4258dffb485Schristos 426*12989c96Schristos if (ctfsect->cts_data != NULL 427*12989c96Schristos && ctfsect->cts_size > sizeof (uint64_t) 428*12989c96Schristos && (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC)) 4298dffb485Schristos { 4308dffb485Schristos /* The archive is mmappable, so this operation is trivial. 4318dffb485Schristos 4328dffb485Schristos This buffer is nonmodifiable, so the trick involving mmapping only part 4338dffb485Schristos of it and storing the length in the magic number is not applicable: so 4348dffb485Schristos record this fact in the archive-wrapper header. (We cannot record it 4358dffb485Schristos in the archive, because the archive may very well be a read-only 4368dffb485Schristos mapping.) */ 4378dffb485Schristos 4388dffb485Schristos is_archive = 1; 4398dffb485Schristos arc = (struct ctf_archive *) ctfsect->cts_data; 4408dffb485Schristos } 4418dffb485Schristos else 4428dffb485Schristos { 4438dffb485Schristos is_archive = 0; 4448dffb485Schristos if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL) 4458dffb485Schristos { 4468dffb485Schristos ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF")); 4478dffb485Schristos return NULL; 4488dffb485Schristos } 4498dffb485Schristos } 4508dffb485Schristos return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect, 4518dffb485Schristos errp); 4528dffb485Schristos } 4538dffb485Schristos 4548dffb485Schristos /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if 4558dffb485Schristos not NULL). */ 4568dffb485Schristos struct ctf_archive * 4578dffb485Schristos ctf_arc_open_internal (const char *filename, int *errp) 4588dffb485Schristos { 4598dffb485Schristos const char *errmsg; 4608dffb485Schristos int fd; 4618dffb485Schristos struct stat s; 4628dffb485Schristos struct ctf_archive *arc; /* (Actually the whole file.) */ 4638dffb485Schristos 4648dffb485Schristos libctf_init_debug(); 4658dffb485Schristos if ((fd = open (filename, O_RDONLY)) < 0) 4668dffb485Schristos { 4678dffb485Schristos errmsg = N_("ctf_arc_open(): cannot open %s"); 4688dffb485Schristos goto err; 4698dffb485Schristos } 4708dffb485Schristos if (fstat (fd, &s) < 0) 4718dffb485Schristos { 4728dffb485Schristos errmsg = N_("ctf_arc_open(): cannot stat %s"); 4738dffb485Schristos goto err_close; 4748dffb485Schristos } 4758dffb485Schristos 4768dffb485Schristos if ((arc = arc_mmap_file (fd, s.st_size)) == NULL) 4778dffb485Schristos { 4788dffb485Schristos errmsg = N_("ctf_arc_open(): cannot read in %s"); 4798dffb485Schristos goto err_close; 4808dffb485Schristos } 4818dffb485Schristos 4828dffb485Schristos if (le64toh (arc->ctfa_magic) != CTFA_MAGIC) 4838dffb485Schristos { 4848dffb485Schristos errmsg = N_("ctf_arc_open(): %s: invalid magic number"); 4858dffb485Schristos errno = ECTF_FMT; 4868dffb485Schristos goto err_unmap; 4878dffb485Schristos } 4888dffb485Schristos 4898dffb485Schristos /* This horrible hack lets us know how much to unmap when the file is 4908dffb485Schristos closed. (We no longer need the magic number, and the mapping 4918dffb485Schristos is private.) */ 4928dffb485Schristos arc->ctfa_magic = s.st_size; 4938dffb485Schristos close (fd); 4948dffb485Schristos return arc; 4958dffb485Schristos 4968dffb485Schristos err_unmap: 4978dffb485Schristos arc_mmap_unmap (arc, s.st_size, NULL); 4988dffb485Schristos err_close: 4998dffb485Schristos close (fd); 5008dffb485Schristos err: 5018dffb485Schristos if (errp) 5028dffb485Schristos *errp = errno; 5038dffb485Schristos ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename); 5048dffb485Schristos return NULL; 5058dffb485Schristos } 5068dffb485Schristos 5078dffb485Schristos /* Close an archive. */ 5088dffb485Schristos void 5098dffb485Schristos ctf_arc_close_internal (struct ctf_archive *arc) 5108dffb485Schristos { 5118dffb485Schristos if (arc == NULL) 5128dffb485Schristos return; 5138dffb485Schristos 5148dffb485Schristos /* See the comment in ctf_arc_open(). */ 5158dffb485Schristos arc_mmap_unmap (arc, arc->ctfa_magic, NULL); 5168dffb485Schristos } 5178dffb485Schristos 5188dffb485Schristos /* Public entry point: close an archive, or CTF file. */ 5198dffb485Schristos void 5208dffb485Schristos ctf_arc_close (ctf_archive_t *arc) 5218dffb485Schristos { 5228dffb485Schristos if (arc == NULL) 5238dffb485Schristos return; 5248dffb485Schristos 5258dffb485Schristos if (arc->ctfi_is_archive) 5268dffb485Schristos { 5278dffb485Schristos if (arc->ctfi_unmap_on_close) 5288dffb485Schristos ctf_arc_close_internal (arc->ctfi_archive); 5298dffb485Schristos } 5308dffb485Schristos else 5314b169a6bSchristos ctf_dict_close (arc->ctfi_dict); 5324b169a6bSchristos free (arc->ctfi_symdicts); 5334b169a6bSchristos free (arc->ctfi_symnamedicts); 5344b169a6bSchristos ctf_dynhash_destroy (arc->ctfi_dicts); 5358dffb485Schristos if (arc->ctfi_free_symsect) 5368dffb485Schristos free ((void *) arc->ctfi_symsect.cts_data); 5378dffb485Schristos if (arc->ctfi_free_strsect) 5388dffb485Schristos free ((void *) arc->ctfi_strsect.cts_data); 5398dffb485Schristos free (arc->ctfi_data); 5408dffb485Schristos if (arc->ctfi_bfd_close) 5418dffb485Schristos arc->ctfi_bfd_close (arc); 5428dffb485Schristos free (arc); 5438dffb485Schristos } 5448dffb485Schristos 5454b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 5468dffb485Schristos non-NULL. A name of NULL means to open the default file. */ 5474b169a6bSchristos static ctf_dict_t * 5484b169a6bSchristos ctf_dict_open_internal (const struct ctf_archive *arc, 5498dffb485Schristos const ctf_sect_t *symsect, 5508dffb485Schristos const ctf_sect_t *strsect, 5514b169a6bSchristos const char *name, int little_endian, 5524b169a6bSchristos int *errp) 5538dffb485Schristos { 5548dffb485Schristos struct ctf_archive_modent *modent; 5558dffb485Schristos const char *search_nametbl; 5568dffb485Schristos 5578dffb485Schristos if (name == NULL) 5588dffb485Schristos name = _CTF_SECTION; /* The default name. */ 5598dffb485Schristos 5604b169a6bSchristos ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name); 5618dffb485Schristos 5628dffb485Schristos modent = (ctf_archive_modent_t *) ((char *) arc 5638dffb485Schristos + sizeof (struct ctf_archive)); 5648dffb485Schristos 5658dffb485Schristos search_nametbl = (const char *) arc + le64toh (arc->ctfa_names); 5664b169a6bSchristos modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts), 5678dffb485Schristos sizeof (struct ctf_archive_modent), 5688dffb485Schristos search_modent_by_name, (void *) search_nametbl); 5698dffb485Schristos 5708dffb485Schristos /* This is actually a common case and normal operation: no error 5718dffb485Schristos debug output. */ 5728dffb485Schristos if (modent == NULL) 5738dffb485Schristos { 5748dffb485Schristos if (errp) 5758dffb485Schristos *errp = ECTF_ARNNAME; 5768dffb485Schristos return NULL; 5778dffb485Schristos } 5788dffb485Schristos 5794b169a6bSchristos return ctf_dict_open_by_offset (arc, symsect, strsect, 5804b169a6bSchristos le64toh (modent->ctf_offset), 5814b169a6bSchristos little_endian, errp); 5828dffb485Schristos } 5838dffb485Schristos 5844b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 5858dffb485Schristos non-NULL. A name of NULL means to open the default file. 5868dffb485Schristos 5878dffb485Schristos Use the specified string and symbol table sections. 5888dffb485Schristos 5898dffb485Schristos Public entry point. */ 5904b169a6bSchristos ctf_dict_t * 5914b169a6bSchristos ctf_dict_open_sections (const ctf_archive_t *arc, 5928dffb485Schristos const ctf_sect_t *symsect, 5938dffb485Schristos const ctf_sect_t *strsect, 5948dffb485Schristos const char *name, 5958dffb485Schristos int *errp) 5968dffb485Schristos { 5978dffb485Schristos if (arc->ctfi_is_archive) 5988dffb485Schristos { 5994b169a6bSchristos ctf_dict_t *ret; 6004b169a6bSchristos ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect, 6014b169a6bSchristos name, arc->ctfi_symsect_little_endian, 6024b169a6bSchristos errp); 6038dffb485Schristos if (ret) 6044b169a6bSchristos { 6058dffb485Schristos ret->ctf_archive = (ctf_archive_t *) arc; 606*12989c96Schristos if (ctf_arc_import_parent (arc, ret, errp) < 0) 607*12989c96Schristos { 608*12989c96Schristos ctf_dict_close (ret); 609*12989c96Schristos return NULL; 610*12989c96Schristos } 6114b169a6bSchristos } 6128dffb485Schristos return ret; 6138dffb485Schristos } 6148dffb485Schristos 6158dffb485Schristos if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0)) 6168dffb485Schristos { 6178dffb485Schristos if (errp) 6188dffb485Schristos *errp = ECTF_ARNNAME; 6198dffb485Schristos return NULL; 6208dffb485Schristos } 6214b169a6bSchristos arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc; 6228dffb485Schristos 6234b169a6bSchristos /* Bump the refcount so that the user can ctf_dict_close() it. */ 6244b169a6bSchristos arc->ctfi_dict->ctf_refcnt++; 6254b169a6bSchristos return arc->ctfi_dict; 6268dffb485Schristos } 6278dffb485Schristos 6284b169a6bSchristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 6298dffb485Schristos non-NULL. A name of NULL means to open the default file. 6308dffb485Schristos 6318dffb485Schristos Public entry point. */ 6324b169a6bSchristos ctf_dict_t * 6334b169a6bSchristos ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp) 6348dffb485Schristos { 6358dffb485Schristos const ctf_sect_t *symsect = &arc->ctfi_symsect; 6368dffb485Schristos const ctf_sect_t *strsect = &arc->ctfi_strsect; 6378dffb485Schristos 6388dffb485Schristos if (symsect->cts_name == NULL) 6398dffb485Schristos symsect = NULL; 6408dffb485Schristos if (strsect->cts_name == NULL) 6418dffb485Schristos strsect = NULL; 6428dffb485Schristos 6434b169a6bSchristos return ctf_dict_open_sections (arc, symsect, strsect, name, errp); 6448dffb485Schristos } 6458dffb485Schristos 6464b169a6bSchristos static void 6474b169a6bSchristos ctf_cached_dict_close (void *fp) 6484b169a6bSchristos { 6494b169a6bSchristos ctf_dict_close ((ctf_dict_t *) fp); 6504b169a6bSchristos } 6514b169a6bSchristos 6524b169a6bSchristos /* Return the ctf_dict_t with the given name and cache it in the archive's 6534b169a6bSchristos ctfi_dicts. If this is the first cached dict, designate it the 6544b169a6bSchristos crossdict_cache. */ 6554b169a6bSchristos static ctf_dict_t * 6564b169a6bSchristos ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp) 6574b169a6bSchristos { 6584b169a6bSchristos ctf_dict_t *fp; 6594b169a6bSchristos char *dupname; 6604b169a6bSchristos 6614b169a6bSchristos /* Just return from the cache if possible. */ 6624b169a6bSchristos if (arc->ctfi_dicts 6634b169a6bSchristos && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL)) 6644b169a6bSchristos { 6654b169a6bSchristos fp->ctf_refcnt++; 6664b169a6bSchristos return fp; 6674b169a6bSchristos } 6684b169a6bSchristos 6694b169a6bSchristos /* Not yet cached: open it. */ 6704b169a6bSchristos fp = ctf_dict_open (arc, name, errp); 6714b169a6bSchristos dupname = strdup (name); 6724b169a6bSchristos 6734b169a6bSchristos if (!fp || !dupname) 6744b169a6bSchristos goto oom; 6754b169a6bSchristos 6764b169a6bSchristos if (arc->ctfi_dicts == NULL) 6774b169a6bSchristos if ((arc->ctfi_dicts 6784b169a6bSchristos = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, 6794b169a6bSchristos free, ctf_cached_dict_close)) == NULL) 6804b169a6bSchristos goto oom; 6814b169a6bSchristos 6824b169a6bSchristos if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0) 6834b169a6bSchristos goto oom; 6844b169a6bSchristos fp->ctf_refcnt++; 6854b169a6bSchristos 6864b169a6bSchristos if (arc->ctfi_crossdict_cache == NULL) 6874b169a6bSchristos arc->ctfi_crossdict_cache = fp; 6884b169a6bSchristos 6894b169a6bSchristos return fp; 6904b169a6bSchristos 6914b169a6bSchristos oom: 6924b169a6bSchristos ctf_dict_close (fp); 6934b169a6bSchristos free (dupname); 6944b169a6bSchristos if (errp) 6954b169a6bSchristos *errp = ENOMEM; 6964b169a6bSchristos return NULL; 6974b169a6bSchristos } 6984b169a6bSchristos 6994b169a6bSchristos /* Flush any caches the CTF archive may have open. */ 7004b169a6bSchristos void 7014b169a6bSchristos ctf_arc_flush_caches (ctf_archive_t *wrapper) 7024b169a6bSchristos { 7034b169a6bSchristos free (wrapper->ctfi_symdicts); 704*12989c96Schristos ctf_dynhash_destroy (wrapper->ctfi_symnamedicts); 7054b169a6bSchristos ctf_dynhash_destroy (wrapper->ctfi_dicts); 7064b169a6bSchristos wrapper->ctfi_symdicts = NULL; 7074b169a6bSchristos wrapper->ctfi_symnamedicts = NULL; 7084b169a6bSchristos wrapper->ctfi_dicts = NULL; 7094b169a6bSchristos wrapper->ctfi_crossdict_cache = NULL; 7104b169a6bSchristos } 7114b169a6bSchristos 7124b169a6bSchristos /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if 7138dffb485Schristos none, setting 'err' if non-NULL. */ 7144b169a6bSchristos static ctf_dict_t * 7154b169a6bSchristos ctf_dict_open_by_offset (const struct ctf_archive *arc, 7168dffb485Schristos const ctf_sect_t *symsect, 7178dffb485Schristos const ctf_sect_t *strsect, size_t offset, 7184b169a6bSchristos int little_endian, int *errp) 7198dffb485Schristos { 7208dffb485Schristos ctf_sect_t ctfsect; 7214b169a6bSchristos ctf_dict_t *fp; 7228dffb485Schristos 7234b169a6bSchristos ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset); 7248dffb485Schristos 7258dffb485Schristos memset (&ctfsect, 0, sizeof (ctf_sect_t)); 7268dffb485Schristos 7278dffb485Schristos offset += le64toh (arc->ctfa_ctfs); 7288dffb485Schristos 7298dffb485Schristos ctfsect.cts_name = _CTF_SECTION; 7308dffb485Schristos ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset))); 7318dffb485Schristos ctfsect.cts_entsize = 1; 7328dffb485Schristos ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t)); 7338dffb485Schristos fp = ctf_bufopen (&ctfsect, symsect, strsect, errp); 7348dffb485Schristos if (fp) 7354b169a6bSchristos { 7368dffb485Schristos ctf_setmodel (fp, le64toh (arc->ctfa_model)); 7374b169a6bSchristos if (little_endian >= 0) 7384b169a6bSchristos ctf_symsect_endianness (fp, little_endian); 7394b169a6bSchristos } 7408dffb485Schristos return fp; 7418dffb485Schristos } 7428dffb485Schristos 7434b169a6bSchristos /* Backward compatibility. */ 7444b169a6bSchristos ctf_dict_t * 7454b169a6bSchristos ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name, 7464b169a6bSchristos int *errp) 7474b169a6bSchristos { 7484b169a6bSchristos return ctf_dict_open (arc, name, errp); 7494b169a6bSchristos } 7504b169a6bSchristos 7514b169a6bSchristos ctf_dict_t * 7524b169a6bSchristos ctf_arc_open_by_name_sections (const ctf_archive_t *arc, 7534b169a6bSchristos const ctf_sect_t *symsect, 7544b169a6bSchristos const ctf_sect_t *strsect, 7554b169a6bSchristos const char *name, 7564b169a6bSchristos int *errp) 7574b169a6bSchristos { 7584b169a6bSchristos return ctf_dict_open_sections (arc, symsect, strsect, name, errp); 7594b169a6bSchristos } 7604b169a6bSchristos 7614b169a6bSchristos /* Import the parent into a ctf archive, if this is a child, the parent is not 7624b169a6bSchristos already set, and a suitable archive member exists. No error is raised if 7634b169a6bSchristos this is not possible: this is just a best-effort helper operation to give 7644b169a6bSchristos people useful dicts to start with. */ 765*12989c96Schristos static int 766*12989c96Schristos ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp, int *errp) 7674b169a6bSchristos { 7684b169a6bSchristos if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent) 7694b169a6bSchristos { 770*12989c96Schristos int err; 7714b169a6bSchristos ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc, 772*12989c96Schristos fp->ctf_parname, &err); 773*12989c96Schristos if (errp) 774*12989c96Schristos *errp = err; 775*12989c96Schristos 7764b169a6bSchristos if (parent) 7774b169a6bSchristos { 7784b169a6bSchristos ctf_import (fp, parent); 7794b169a6bSchristos ctf_dict_close (parent); 7804b169a6bSchristos } 781*12989c96Schristos else if (err != ECTF_ARNNAME) 782*12989c96Schristos return -1; /* errno is set for us. */ 7834b169a6bSchristos } 784*12989c96Schristos return 0; 7854b169a6bSchristos } 7864b169a6bSchristos 7878dffb485Schristos /* Return the number of members in an archive. */ 7888dffb485Schristos size_t 7898dffb485Schristos ctf_archive_count (const ctf_archive_t *wrapper) 7908dffb485Schristos { 7918dffb485Schristos if (!wrapper->ctfi_is_archive) 7928dffb485Schristos return 1; 7938dffb485Schristos 7944b169a6bSchristos return wrapper->ctfi_archive->ctfa_ndicts; 7954b169a6bSchristos } 7964b169a6bSchristos 7974b169a6bSchristos /* Look up a symbol in an archive by name or index (if the name is set, a lookup 7984b169a6bSchristos by name is done). Return the dict in the archive that the symbol is found 7994b169a6bSchristos in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't 8004b169a6bSchristos have to look it up yourself). The dict is cached, so repeated lookups are 8014b169a6bSchristos nearly free. 8024b169a6bSchristos 8034b169a6bSchristos As usual, you should ctf_dict_close() the returned dict once you are done 8044b169a6bSchristos with it. 8054b169a6bSchristos 8064b169a6bSchristos Returns NULL on error, and an error in errp (if set). */ 8074b169a6bSchristos 8084b169a6bSchristos static ctf_dict_t * 8094b169a6bSchristos ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx, 8104b169a6bSchristos const char *symname, ctf_id_t *typep, int *errp) 8114b169a6bSchristos { 8124b169a6bSchristos ctf_dict_t *fp; 8134b169a6bSchristos void *fpkey; 8144b169a6bSchristos ctf_id_t type; 8154b169a6bSchristos 8164b169a6bSchristos /* The usual non-archive-transparent-wrapper special case. */ 8174b169a6bSchristos if (!wrapper->ctfi_is_archive) 8184b169a6bSchristos { 8194b169a6bSchristos if (!symname) 8204b169a6bSchristos { 8214b169a6bSchristos if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR) 8224b169a6bSchristos { 8234b169a6bSchristos if (errp) 8244b169a6bSchristos *errp = ctf_errno (wrapper->ctfi_dict); 8254b169a6bSchristos return NULL; 8264b169a6bSchristos } 8274b169a6bSchristos } 8284b169a6bSchristos else 8294b169a6bSchristos { 8304b169a6bSchristos if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict, 8314b169a6bSchristos symname)) == CTF_ERR) 8324b169a6bSchristos { 8334b169a6bSchristos if (errp) 8344b169a6bSchristos *errp = ctf_errno (wrapper->ctfi_dict); 8354b169a6bSchristos return NULL; 8364b169a6bSchristos } 8374b169a6bSchristos } 8384b169a6bSchristos if (typep) 8394b169a6bSchristos *typep = type; 8404b169a6bSchristos wrapper->ctfi_dict->ctf_refcnt++; 8414b169a6bSchristos return wrapper->ctfi_dict; 8424b169a6bSchristos } 8434b169a6bSchristos 8444b169a6bSchristos if (wrapper->ctfi_symsect.cts_name == NULL 8454b169a6bSchristos || wrapper->ctfi_symsect.cts_data == NULL 8464b169a6bSchristos || wrapper->ctfi_symsect.cts_size == 0 8474b169a6bSchristos || wrapper->ctfi_symsect.cts_entsize == 0) 8484b169a6bSchristos { 8494b169a6bSchristos if (errp) 8504b169a6bSchristos *errp = ECTF_NOSYMTAB; 8514b169a6bSchristos return NULL; 8524b169a6bSchristos } 8534b169a6bSchristos 8544b169a6bSchristos /* Make enough space for all possible symbol indexes, if not already done. We 8554b169a6bSchristos cache the originating dictionary of all symbols. The dict links are weak, 8564b169a6bSchristos to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped. 8574b169a6bSchristos We also cache similar mappings for symbol names: these are ordinary 8584b169a6bSchristos dynhashes, with weak links to dicts. */ 8594b169a6bSchristos 8604b169a6bSchristos if (!wrapper->ctfi_symdicts) 8614b169a6bSchristos { 8624b169a6bSchristos if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size 8634b169a6bSchristos / wrapper->ctfi_symsect.cts_entsize, 8644b169a6bSchristos sizeof (ctf_dict_t *))) == NULL) 8654b169a6bSchristos { 8664b169a6bSchristos if (errp) 8674b169a6bSchristos *errp = ENOMEM; 8684b169a6bSchristos return NULL; 8694b169a6bSchristos } 8704b169a6bSchristos } 8714b169a6bSchristos if (!wrapper->ctfi_symnamedicts) 8724b169a6bSchristos { 8734b169a6bSchristos if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string, 8744b169a6bSchristos ctf_hash_eq_string, 8754b169a6bSchristos free, NULL)) == NULL) 8764b169a6bSchristos { 8774b169a6bSchristos if (errp) 8784b169a6bSchristos *errp = ENOMEM; 8794b169a6bSchristos return NULL; 8804b169a6bSchristos } 8814b169a6bSchristos } 8824b169a6bSchristos 8834b169a6bSchristos /* Perhaps the dict in which we found a previous lookup is cached. If it's 8844b169a6bSchristos supposed to be cached but we don't find it, pretend it was always not 8854b169a6bSchristos found: this should never happen, but shouldn't be allowed to cause trouble 8864b169a6bSchristos if it does. */ 8874b169a6bSchristos 8884b169a6bSchristos if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts, 8894b169a6bSchristos symname, NULL, &fpkey)) 8904b169a6bSchristos || (!symname && wrapper->ctfi_symdicts[symidx] != NULL)) 8914b169a6bSchristos { 8924b169a6bSchristos if (symname) 8934b169a6bSchristos fp = (ctf_dict_t *) fpkey; 8944b169a6bSchristos else 8954b169a6bSchristos fp = wrapper->ctfi_symdicts[symidx]; 8964b169a6bSchristos 8974b169a6bSchristos if (fp == &enosym) 8984b169a6bSchristos goto no_sym; 8994b169a6bSchristos 9004b169a6bSchristos if (symname) 9014b169a6bSchristos { 9024b169a6bSchristos if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR) 9034b169a6bSchristos goto cache_no_sym; 9044b169a6bSchristos } 9054b169a6bSchristos else 9064b169a6bSchristos { 9074b169a6bSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) 9084b169a6bSchristos goto cache_no_sym; 9094b169a6bSchristos } 9104b169a6bSchristos 9114b169a6bSchristos if (typep) 9124b169a6bSchristos *typep = type; 9134b169a6bSchristos fp->ctf_refcnt++; 9144b169a6bSchristos return fp; 9154b169a6bSchristos } 9164b169a6bSchristos 9174b169a6bSchristos /* Not cached: find it and cache it. We must track open errors ourselves even 9184b169a6bSchristos if our caller doesn't, to be able to distinguish no-error end-of-iteration 9194b169a6bSchristos from open errors. */ 9204b169a6bSchristos 9214b169a6bSchristos int local_err; 9224b169a6bSchristos int *local_errp; 9234b169a6bSchristos ctf_next_t *i = NULL; 9244b169a6bSchristos const char *name; 9254b169a6bSchristos 9264b169a6bSchristos if (errp) 9274b169a6bSchristos local_errp = errp; 9284b169a6bSchristos else 9294b169a6bSchristos local_errp = &local_err; 9304b169a6bSchristos 9314b169a6bSchristos while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL) 9324b169a6bSchristos { 9334b169a6bSchristos if (!symname) 9344b169a6bSchristos { 9354b169a6bSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR) 9364b169a6bSchristos wrapper->ctfi_symdicts[symidx] = fp; 9374b169a6bSchristos } 9384b169a6bSchristos else 9394b169a6bSchristos { 9404b169a6bSchristos if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR) 9414b169a6bSchristos { 9424b169a6bSchristos char *tmp; 9434b169a6bSchristos /* No error checking, as above. */ 9444b169a6bSchristos if ((tmp = strdup (symname)) != NULL) 9454b169a6bSchristos ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp); 9464b169a6bSchristos } 9474b169a6bSchristos } 9484b169a6bSchristos 9494b169a6bSchristos if (type != CTF_ERR) 9504b169a6bSchristos { 9514b169a6bSchristos if (typep) 9524b169a6bSchristos *typep = type; 9534b169a6bSchristos ctf_next_destroy (i); 9544b169a6bSchristos return fp; 9554b169a6bSchristos } 9564b169a6bSchristos if (ctf_errno (fp) != ECTF_NOTYPEDAT) 9574b169a6bSchristos { 9584b169a6bSchristos if (errp) 9594b169a6bSchristos *errp = ctf_errno (fp); 9604b169a6bSchristos ctf_next_destroy (i); 9614b169a6bSchristos return NULL; /* errno is set for us. */ 9624b169a6bSchristos } 9634b169a6bSchristos ctf_dict_close (fp); 9644b169a6bSchristos } 9654b169a6bSchristos if (*local_errp != ECTF_NEXT_END) 9664b169a6bSchristos { 9674b169a6bSchristos ctf_next_destroy (i); 9684b169a6bSchristos return NULL; 9694b169a6bSchristos } 9704b169a6bSchristos 9714b169a6bSchristos /* Don't leak end-of-iteration to the caller. */ 9724b169a6bSchristos *local_errp = 0; 9734b169a6bSchristos 9744b169a6bSchristos cache_no_sym: 9754b169a6bSchristos if (!symname) 9764b169a6bSchristos wrapper->ctfi_symdicts[symidx] = &enosym; 9774b169a6bSchristos else 9784b169a6bSchristos { 9794b169a6bSchristos char *tmp; 9804b169a6bSchristos 9814b169a6bSchristos /* No error checking: if caching fails, there is only a slight performance 9824b169a6bSchristos impact. */ 9834b169a6bSchristos if ((tmp = strdup (symname)) != NULL) 9844b169a6bSchristos if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0) 9854b169a6bSchristos free (tmp); 9864b169a6bSchristos } 9874b169a6bSchristos 9884b169a6bSchristos no_sym: 9894b169a6bSchristos if (errp) 9904b169a6bSchristos *errp = ECTF_NOTYPEDAT; 9914b169a6bSchristos if (typep) 9924b169a6bSchristos *typep = CTF_ERR; 9934b169a6bSchristos return NULL; 9944b169a6bSchristos } 9954b169a6bSchristos 9964b169a6bSchristos /* The public API for looking up a symbol by index. */ 9974b169a6bSchristos ctf_dict_t * 9984b169a6bSchristos ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx, 9994b169a6bSchristos ctf_id_t *typep, int *errp) 10004b169a6bSchristos { 10014b169a6bSchristos return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp); 10024b169a6bSchristos } 10034b169a6bSchristos 10044b169a6bSchristos /* The public API for looking up a symbol by name. */ 10054b169a6bSchristos 10064b169a6bSchristos ctf_dict_t * 10074b169a6bSchristos ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname, 10084b169a6bSchristos ctf_id_t *typep, int *errp) 10094b169a6bSchristos { 10104b169a6bSchristos return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp); 10118dffb485Schristos } 10128dffb485Schristos 10138dffb485Schristos /* Raw iteration over all CTF files in an archive. We pass the raw data for all 10148dffb485Schristos CTF files in turn to the specified callback function. */ 10158dffb485Schristos static int 10168dffb485Schristos ctf_archive_raw_iter_internal (const struct ctf_archive *arc, 10178dffb485Schristos ctf_archive_raw_member_f *func, void *data) 10188dffb485Schristos { 10198dffb485Schristos int rc; 10208dffb485Schristos size_t i; 10218dffb485Schristos struct ctf_archive_modent *modent; 10228dffb485Schristos const char *nametbl; 10238dffb485Schristos 10248dffb485Schristos modent = (ctf_archive_modent_t *) ((char *) arc 10258dffb485Schristos + sizeof (struct ctf_archive)); 10268dffb485Schristos nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); 10278dffb485Schristos 10284b169a6bSchristos for (i = 0; i < le64toh (arc->ctfa_ndicts); i++) 10298dffb485Schristos { 10308dffb485Schristos const char *name; 10318dffb485Schristos char *fp; 10328dffb485Schristos 10338dffb485Schristos name = &nametbl[le64toh (modent[i].name_offset)]; 10348dffb485Schristos fp = ((char *) arc + le64toh (arc->ctfa_ctfs) 10358dffb485Schristos + le64toh (modent[i].ctf_offset)); 10368dffb485Schristos 10378dffb485Schristos if ((rc = func (name, (void *) (fp + sizeof (uint64_t)), 10388dffb485Schristos le64toh (*((uint64_t *) fp)), data)) != 0) 10398dffb485Schristos return rc; 10408dffb485Schristos } 10418dffb485Schristos return 0; 10428dffb485Schristos } 10438dffb485Schristos 10448dffb485Schristos /* Raw iteration over all CTF files in an archive: public entry point. 10458dffb485Schristos 10468dffb485Schristos Returns -EINVAL if not supported for this sort of archive. */ 10478dffb485Schristos int 10488dffb485Schristos ctf_archive_raw_iter (const ctf_archive_t *arc, 10498dffb485Schristos ctf_archive_raw_member_f * func, void *data) 10508dffb485Schristos { 10518dffb485Schristos if (arc->ctfi_is_archive) 10528dffb485Schristos return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data); 10538dffb485Schristos 10548dffb485Schristos return -EINVAL; /* Not supported. */ 10558dffb485Schristos } 10568dffb485Schristos 10578dffb485Schristos /* Iterate over all CTF files in an archive: public entry point. We pass all 10588dffb485Schristos CTF files in turn to the specified callback function. */ 10598dffb485Schristos int 10608dffb485Schristos ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func, 10618dffb485Schristos void *data) 10628dffb485Schristos { 10634b169a6bSchristos ctf_next_t *i = NULL; 10644b169a6bSchristos ctf_dict_t *fp; 10654b169a6bSchristos const char *name; 1066*12989c96Schristos int err = 0; 10678dffb485Schristos 10684b169a6bSchristos while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL) 10694b169a6bSchristos { 10704b169a6bSchristos int rc; 10718dffb485Schristos 10724b169a6bSchristos if ((rc = func (fp, name, data)) != 0) 10734b169a6bSchristos { 10744b169a6bSchristos ctf_dict_close (fp); 10754b169a6bSchristos ctf_next_destroy (i); 10764b169a6bSchristos return rc; 10774b169a6bSchristos } 10784b169a6bSchristos ctf_dict_close (fp); 10794b169a6bSchristos } 1080*12989c96Schristos if (err != ECTF_NEXT_END && err != 0) 1081*12989c96Schristos { 1082*12989c96Schristos ctf_next_destroy (i); 1083*12989c96Schristos return -1; 1084*12989c96Schristos } 10854b169a6bSchristos return 0; 10868dffb485Schristos } 10878dffb485Schristos 10888dffb485Schristos /* Iterate over all CTF files in an archive, returning each dict in turn as a 10894b169a6bSchristos ctf_dict_t, and NULL on error or end of iteration. It is the caller's 10904b169a6bSchristos responsibility to close it. Parent dicts may be skipped. 10914b169a6bSchristos 10924b169a6bSchristos The archive member is cached for rapid return on future calls. 10938dffb485Schristos 10948dffb485Schristos We identify parents by name rather than by flag value: for now, with the 10958dffb485Schristos linker only emitting parents named _CTF_SECTION, this works well enough. */ 10968dffb485Schristos 10974b169a6bSchristos ctf_dict_t * 10988dffb485Schristos ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name, 10998dffb485Schristos int skip_parent, int *errp) 11008dffb485Schristos { 11014b169a6bSchristos ctf_dict_t *f; 11028dffb485Schristos ctf_next_t *i = *it; 11038dffb485Schristos struct ctf_archive *arc; 11048dffb485Schristos struct ctf_archive_modent *modent; 11058dffb485Schristos const char *nametbl; 11068dffb485Schristos const char *name_; 11078dffb485Schristos 11088dffb485Schristos if (!i) 11098dffb485Schristos { 11108dffb485Schristos if ((i = ctf_next_create()) == NULL) 11118dffb485Schristos { 11128dffb485Schristos if (errp) 11138dffb485Schristos *errp = ENOMEM; 11148dffb485Schristos return NULL; 11158dffb485Schristos } 11168dffb485Schristos i->cu.ctn_arc = wrapper; 11178dffb485Schristos i->ctn_iter_fun = (void (*) (void)) ctf_archive_next; 11188dffb485Schristos *it = i; 11198dffb485Schristos } 11208dffb485Schristos 11218dffb485Schristos if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun) 11228dffb485Schristos { 11238dffb485Schristos if (errp) 11248dffb485Schristos *errp = ECTF_NEXT_WRONGFUN; 11258dffb485Schristos return NULL; 11268dffb485Schristos } 11278dffb485Schristos 11288dffb485Schristos if (wrapper != i->cu.ctn_arc) 11298dffb485Schristos { 11308dffb485Schristos if (errp) 11318dffb485Schristos *errp = ECTF_NEXT_WRONGFP; 11328dffb485Schristos return NULL; 11338dffb485Schristos } 11348dffb485Schristos 11354b169a6bSchristos /* Iteration is made a bit more complex by the need to handle ctf_dict_t's 11368dffb485Schristos transparently wrapped in a single-member archive. These are parents: if 11378dffb485Schristos skip_parent is on, they are skipped and the iterator terminates 11388dffb485Schristos immediately. */ 11398dffb485Schristos 11408dffb485Schristos if (!wrapper->ctfi_is_archive && i->ctn_n == 0) 11418dffb485Schristos { 11428dffb485Schristos i->ctn_n++; 11438dffb485Schristos if (!skip_parent) 11448dffb485Schristos { 11454b169a6bSchristos wrapper->ctfi_dict->ctf_refcnt++; 11464b169a6bSchristos if (name) 11474b169a6bSchristos *name = _CTF_SECTION; 11484b169a6bSchristos return wrapper->ctfi_dict; 11498dffb485Schristos } 11508dffb485Schristos } 11518dffb485Schristos 11528dffb485Schristos arc = wrapper->ctfi_archive; 11538dffb485Schristos 11548dffb485Schristos /* The loop keeps going when skip_parent is on as long as the member we find 11558dffb485Schristos is the parent (i.e. at most two iterations, but possibly an early return if 11568dffb485Schristos *all* we have is a parent). */ 11578dffb485Schristos 11588dffb485Schristos do 11598dffb485Schristos { 11604b169a6bSchristos if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts))) 11618dffb485Schristos { 11628dffb485Schristos ctf_next_destroy (i); 11638dffb485Schristos *it = NULL; 11648dffb485Schristos if (errp) 11658dffb485Schristos *errp = ECTF_NEXT_END; 11668dffb485Schristos return NULL; 11678dffb485Schristos } 11688dffb485Schristos 11698dffb485Schristos modent = (ctf_archive_modent_t *) ((char *) arc 11708dffb485Schristos + sizeof (struct ctf_archive)); 11718dffb485Schristos nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); 11728dffb485Schristos 11738dffb485Schristos name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)]; 11748dffb485Schristos i->ctn_n++; 11754b169a6bSchristos } 11764b169a6bSchristos while (skip_parent && strcmp (name_, _CTF_SECTION) == 0); 11778dffb485Schristos 11788dffb485Schristos if (name) 11798dffb485Schristos *name = name_; 11808dffb485Schristos 11814b169a6bSchristos f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp); 11828dffb485Schristos return f; 11838dffb485Schristos } 11848dffb485Schristos 11858dffb485Schristos #ifdef HAVE_MMAP 11868dffb485Schristos /* Map the header in. Only used on new, empty files. */ 11878dffb485Schristos static void *arc_mmap_header (int fd, size_t headersz) 11888dffb485Schristos { 11898dffb485Schristos void *hdr; 11908dffb485Schristos if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 11918dffb485Schristos 0)) == MAP_FAILED) 11928dffb485Schristos return NULL; 11938dffb485Schristos return hdr; 11948dffb485Schristos } 11958dffb485Schristos 11968dffb485Schristos /* mmap() the whole file, for reading only. (Map it writably, but privately: we 11978dffb485Schristos need to modify the region, but don't need anyone else to see the 11988dffb485Schristos modifications.) */ 11998dffb485Schristos static void *arc_mmap_file (int fd, size_t size) 12008dffb485Schristos { 12018dffb485Schristos void *arc; 12028dffb485Schristos if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 12038dffb485Schristos fd, 0)) == MAP_FAILED) 12048dffb485Schristos return NULL; 12058dffb485Schristos return arc; 12068dffb485Schristos } 12078dffb485Schristos 12088dffb485Schristos /* Persist the header to disk. */ 12098dffb485Schristos static int arc_mmap_writeout (int fd _libctf_unused_, void *header, 12108dffb485Schristos size_t headersz, const char **errmsg) 12118dffb485Schristos { 12128dffb485Schristos if (msync (header, headersz, MS_ASYNC) < 0) 12138dffb485Schristos { 12148dffb485Schristos if (errmsg) 12158dffb485Schristos *errmsg = N_("arc_mmap_writeout(): cannot sync after writing " 12168dffb485Schristos "to %s: %s"); 12178dffb485Schristos return -1; 12188dffb485Schristos } 12198dffb485Schristos return 0; 12208dffb485Schristos } 12218dffb485Schristos 12228dffb485Schristos /* Unmap the region. */ 12238dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg) 12248dffb485Schristos { 12258dffb485Schristos if (munmap (header, headersz) < 0) 12268dffb485Schristos { 12278dffb485Schristos if (errmsg) 12288dffb485Schristos *errmsg = N_("arc_mmap_munmap(): cannot unmap after writing " 12298dffb485Schristos "to %s: %s"); 12308dffb485Schristos return -1; 12318dffb485Schristos } 12328dffb485Schristos return 0; 12338dffb485Schristos } 12348dffb485Schristos #else 12358dffb485Schristos /* Map the header in. Only used on new, empty files. */ 12368dffb485Schristos static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz) 12378dffb485Schristos { 12388dffb485Schristos void *hdr; 12398dffb485Schristos if ((hdr = malloc (headersz)) == NULL) 12408dffb485Schristos return NULL; 12418dffb485Schristos return hdr; 12428dffb485Schristos } 12438dffb485Schristos 12448dffb485Schristos /* Pull in the whole file, for reading only. We assume the current file 12458dffb485Schristos position is at the start of the file. */ 12468dffb485Schristos static void *arc_mmap_file (int fd, size_t size) 12478dffb485Schristos { 12488dffb485Schristos char *data; 12498dffb485Schristos 12508dffb485Schristos if ((data = malloc (size)) == NULL) 12518dffb485Schristos return NULL; 12528dffb485Schristos 12538dffb485Schristos if (ctf_pread (fd, data, size, 0) < 0) 12548dffb485Schristos { 12558dffb485Schristos free (data); 12568dffb485Schristos return NULL; 12578dffb485Schristos } 12588dffb485Schristos return data; 12598dffb485Schristos } 12608dffb485Schristos 12618dffb485Schristos /* Persist the header to disk. */ 12628dffb485Schristos static int arc_mmap_writeout (int fd, void *header, size_t headersz, 12638dffb485Schristos const char **errmsg) 12648dffb485Schristos { 12658dffb485Schristos ssize_t len; 12668dffb485Schristos char *data = (char *) header; 12678dffb485Schristos ssize_t count = headersz; 12688dffb485Schristos 12698dffb485Schristos if ((lseek (fd, 0, SEEK_SET)) < 0) 12708dffb485Schristos { 12718dffb485Schristos if (errmsg) 12728dffb485Schristos *errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to " 12738dffb485Schristos "%s: %s"); 12748dffb485Schristos return -1; 12758dffb485Schristos } 12768dffb485Schristos 12778dffb485Schristos while (headersz > 0) 12788dffb485Schristos { 12798dffb485Schristos if ((len = write (fd, data, count)) < 0) 12808dffb485Schristos { 12818dffb485Schristos if (errmsg) 12828dffb485Schristos *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s"); 12838dffb485Schristos return len; 12848dffb485Schristos } 12858dffb485Schristos if (len == EINTR) 12868dffb485Schristos continue; 12878dffb485Schristos 12888dffb485Schristos if (len == 0) /* EOF. */ 12898dffb485Schristos break; 12908dffb485Schristos 12918dffb485Schristos count -= len; 12928dffb485Schristos data += len; 12938dffb485Schristos } 12948dffb485Schristos return 0; 12958dffb485Schristos } 12968dffb485Schristos 12978dffb485Schristos /* Unmap the region. */ 12988dffb485Schristos static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_, 12998dffb485Schristos const char **errmsg _libctf_unused_) 13008dffb485Schristos { 13018dffb485Schristos free (header); 13028dffb485Schristos return 0; 13038dffb485Schristos } 13048dffb485Schristos #endif 1305