17d62b00eSchristos /* CTF archive files. 2*6881a400Schristos Copyright (C) 2019-2022 Free Software Foundation, Inc. 37d62b00eSchristos 47d62b00eSchristos This file is part of libctf. 57d62b00eSchristos 67d62b00eSchristos libctf is free software; you can redistribute it and/or modify it under 77d62b00eSchristos the terms of the GNU General Public License as published by the Free 87d62b00eSchristos Software Foundation; either version 3, or (at your option) any later 97d62b00eSchristos version. 107d62b00eSchristos 117d62b00eSchristos This program is distributed in the hope that it will be useful, but 127d62b00eSchristos WITHOUT ANY WARRANTY; without even the implied warranty of 137d62b00eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 147d62b00eSchristos See the GNU General Public License for more details. 157d62b00eSchristos 167d62b00eSchristos You should have received a copy of the GNU General Public License 177d62b00eSchristos along with this program; see the file COPYING. If not see 187d62b00eSchristos <http://www.gnu.org/licenses/>. */ 197d62b00eSchristos 207d62b00eSchristos #include <ctf-impl.h> 217d62b00eSchristos #include <sys/types.h> 227d62b00eSchristos #include <sys/stat.h> 237d62b00eSchristos #include <elf.h> 247d62b00eSchristos #include "ctf-endian.h" 257d62b00eSchristos #include <errno.h> 267d62b00eSchristos #include <fcntl.h> 277d62b00eSchristos #include <stdio.h> 287d62b00eSchristos #include <string.h> 297d62b00eSchristos #include <unistd.h> 307d62b00eSchristos 317d62b00eSchristos #ifdef HAVE_MMAP 327d62b00eSchristos #include <sys/mman.h> 337d62b00eSchristos #endif 347d62b00eSchristos 35*6881a400Schristos static off_t arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold); 36*6881a400Schristos static ctf_dict_t *ctf_dict_open_by_offset (const struct ctf_archive *arc, 377d62b00eSchristos const ctf_sect_t *symsect, 387d62b00eSchristos const ctf_sect_t *strsect, 39*6881a400Schristos size_t offset, int little_endian, 40*6881a400Schristos int *errp); 417d62b00eSchristos static int sort_modent_by_name (const void *one, const void *two, void *n); 427d62b00eSchristos static void *arc_mmap_header (int fd, size_t headersz); 437d62b00eSchristos static void *arc_mmap_file (int fd, size_t size); 447d62b00eSchristos static int arc_mmap_writeout (int fd, void *header, size_t headersz, 457d62b00eSchristos const char **errmsg); 467d62b00eSchristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg); 47*6881a400Schristos static void ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp); 48*6881a400Schristos 49*6881a400Schristos /* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts 50*6881a400Schristos and ctfi_symnamedicts. Never initialized. */ 51*6881a400Schristos static ctf_dict_t enosym; 527d62b00eSchristos 537d62b00eSchristos /* Write out a CTF archive to the start of the file referenced by the passed-in 54*6881a400Schristos fd. The entries in CTF_DICTS are referenced by name: the names are passed in 55*6881a400Schristos the names array, which must have CTF_DICTS entries. 567d62b00eSchristos 577d62b00eSchristos Returns 0 on success, or an errno, or an ECTF_* value. */ 587d62b00eSchristos int 59*6881a400Schristos ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt, 607d62b00eSchristos const char **names, size_t threshold) 617d62b00eSchristos { 627d62b00eSchristos const char *errmsg; 637d62b00eSchristos struct ctf_archive *archdr; 647d62b00eSchristos size_t i; 657d62b00eSchristos char dummy = 0; 667d62b00eSchristos size_t headersz; 677d62b00eSchristos ssize_t namesz; 687d62b00eSchristos size_t ctf_startoffs; /* Start of the section we are working over. */ 697d62b00eSchristos char *nametbl = NULL; /* The name table. */ 707d62b00eSchristos char *np; 717d62b00eSchristos off_t nameoffs; 727d62b00eSchristos struct ctf_archive_modent *modent; 737d62b00eSchristos 747d62b00eSchristos ctf_dprintf ("Writing CTF archive with %lu files\n", 75*6881a400Schristos (unsigned long) ctf_dict_cnt); 767d62b00eSchristos 777d62b00eSchristos /* Figure out the size of the mmap()ed header, including the 787d62b00eSchristos ctf_archive_modent array. We assume that all of this needs no 797d62b00eSchristos padding: a likely assumption, given that it's all made up of 807d62b00eSchristos uint64_t's. */ 817d62b00eSchristos headersz = sizeof (struct ctf_archive) 82*6881a400Schristos + (ctf_dict_cnt * sizeof (uint64_t) * 2); 837d62b00eSchristos ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz); 847d62b00eSchristos 857d62b00eSchristos /* From now on we work in two pieces: an mmap()ed region from zero up to the 867d62b00eSchristos headersz, and a region updated via write() starting after that, containing 877d62b00eSchristos all the tables. Platforms that do not support mmap() just use write(). */ 887d62b00eSchristos ctf_startoffs = headersz; 897d62b00eSchristos if (lseek (fd, ctf_startoffs - 1, SEEK_SET) < 0) 907d62b00eSchristos { 917d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot extend file while writing"); 927d62b00eSchristos goto err; 937d62b00eSchristos } 947d62b00eSchristos 957d62b00eSchristos if (write (fd, &dummy, 1) < 0) 967d62b00eSchristos { 977d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot extend file while writing"); 987d62b00eSchristos goto err; 997d62b00eSchristos } 1007d62b00eSchristos 1017d62b00eSchristos if ((archdr = arc_mmap_header (fd, headersz)) == NULL) 1027d62b00eSchristos { 1037d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot mmap"); 1047d62b00eSchristos goto err; 1057d62b00eSchristos } 1067d62b00eSchristos 1077d62b00eSchristos /* Fill in everything we can, which is everything other than the name 1087d62b00eSchristos table offset. */ 1097d62b00eSchristos archdr->ctfa_magic = htole64 (CTFA_MAGIC); 110*6881a400Schristos archdr->ctfa_ndicts = htole64 (ctf_dict_cnt); 1117d62b00eSchristos archdr->ctfa_ctfs = htole64 (ctf_startoffs); 1127d62b00eSchristos 1137d62b00eSchristos /* We could validate that all CTF files have the same data model, but 1147d62b00eSchristos since any reasonable construction process will be building things of 1157d62b00eSchristos only one bitness anyway, this is pretty pointless, so just use the 1167d62b00eSchristos model of the first CTF file for all of them. (It *is* valid to 1177d62b00eSchristos create an empty archive: the value of ctfa_model is irrelevant in 1187d62b00eSchristos this case, but we must be sure not to dereference uninitialized 1197d62b00eSchristos memory.) */ 1207d62b00eSchristos 121*6881a400Schristos if (ctf_dict_cnt > 0) 122*6881a400Schristos archdr->ctfa_model = htole64 (ctf_getmodel (ctf_dicts[0])); 1237d62b00eSchristos 1247d62b00eSchristos /* Now write out the CTFs: ctf_archive_modent array via the mapping, 1257d62b00eSchristos ctfs via write(). The names themselves have not been written yet: we 1267d62b00eSchristos track them in a local strtab until the time is right, and sort the 1277d62b00eSchristos modents array after construction. 1287d62b00eSchristos 1297d62b00eSchristos The name table is not sorted. */ 1307d62b00eSchristos 131*6881a400Schristos for (i = 0, namesz = 0; i < le64toh (archdr->ctfa_ndicts); i++) 1327d62b00eSchristos namesz += strlen (names[i]) + 1; 1337d62b00eSchristos 1347d62b00eSchristos nametbl = malloc (namesz); 1357d62b00eSchristos if (nametbl == NULL) 1367d62b00eSchristos { 1377d62b00eSchristos errmsg = N_("ctf_arc_write(): error writing named CTF to archive"); 1387d62b00eSchristos goto err_unmap; 1397d62b00eSchristos } 1407d62b00eSchristos 1417d62b00eSchristos for (i = 0, namesz = 0, 1427d62b00eSchristos modent = (ctf_archive_modent_t *) ((char *) archdr 1437d62b00eSchristos + sizeof (struct ctf_archive)); 144*6881a400Schristos i < le64toh (archdr->ctfa_ndicts); i++) 1457d62b00eSchristos { 1467d62b00eSchristos off_t off; 1477d62b00eSchristos 1487d62b00eSchristos strcpy (&nametbl[namesz], names[i]); 1497d62b00eSchristos 150*6881a400Schristos off = arc_write_one_ctf (ctf_dicts[i], fd, threshold); 1517d62b00eSchristos if ((off < 0) && (off > -ECTF_BASE)) 1527d62b00eSchristos { 1537d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot determine file " 1547d62b00eSchristos "position while writing to archive"); 1557d62b00eSchristos goto err_free; 1567d62b00eSchristos } 1577d62b00eSchristos if (off < 0) 1587d62b00eSchristos { 1597d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot write CTF file to archive"); 1607d62b00eSchristos errno = off * -1; 1617d62b00eSchristos goto err_free; 1627d62b00eSchristos } 1637d62b00eSchristos 1647d62b00eSchristos modent->name_offset = htole64 (namesz); 1657d62b00eSchristos modent->ctf_offset = htole64 (off - ctf_startoffs); 1667d62b00eSchristos namesz += strlen (names[i]) + 1; 1677d62b00eSchristos modent++; 1687d62b00eSchristos } 1697d62b00eSchristos 1707d62b00eSchristos ctf_qsort_r ((ctf_archive_modent_t *) ((char *) archdr 1717d62b00eSchristos + sizeof (struct ctf_archive)), 172*6881a400Schristos le64toh (archdr->ctfa_ndicts), 1737d62b00eSchristos sizeof (struct ctf_archive_modent), sort_modent_by_name, 1747d62b00eSchristos nametbl); 1757d62b00eSchristos 1767d62b00eSchristos /* Now the name table. */ 1777d62b00eSchristos 1787d62b00eSchristos if ((nameoffs = lseek (fd, 0, SEEK_CUR)) < 0) 1797d62b00eSchristos { 1807d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot get current file position " 1817d62b00eSchristos "in archive"); 1827d62b00eSchristos goto err_free; 1837d62b00eSchristos } 1847d62b00eSchristos archdr->ctfa_names = htole64 (nameoffs); 1857d62b00eSchristos np = nametbl; 1867d62b00eSchristos while (namesz > 0) 1877d62b00eSchristos { 1887d62b00eSchristos ssize_t len; 1897d62b00eSchristos if ((len = write (fd, np, namesz)) < 0) 1907d62b00eSchristos { 1917d62b00eSchristos errmsg = N_("ctf_arc_write(): cannot write name table to archive"); 1927d62b00eSchristos goto err_free; 1937d62b00eSchristos } 1947d62b00eSchristos namesz -= len; 1957d62b00eSchristos np += len; 1967d62b00eSchristos } 1977d62b00eSchristos free (nametbl); 1987d62b00eSchristos 1997d62b00eSchristos if (arc_mmap_writeout (fd, archdr, headersz, &errmsg) < 0) 2007d62b00eSchristos goto err_unmap; 2017d62b00eSchristos if (arc_mmap_unmap (archdr, headersz, &errmsg) < 0) 2027d62b00eSchristos goto err; 2037d62b00eSchristos return 0; 2047d62b00eSchristos 2057d62b00eSchristos err_free: 2067d62b00eSchristos free (nametbl); 2077d62b00eSchristos err_unmap: 2087d62b00eSchristos arc_mmap_unmap (archdr, headersz, NULL); 2097d62b00eSchristos err: 2107d62b00eSchristos /* We report errors into the first file in the archive, if any: if this is a 2117d62b00eSchristos zero-file archive, put it in the open-errors stream for lack of anywhere 2127d62b00eSchristos else for it to go. */ 213*6881a400Schristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, "%s", 2147d62b00eSchristos gettext (errmsg)); 2157d62b00eSchristos return errno; 2167d62b00eSchristos } 2177d62b00eSchristos 218*6881a400Schristos /* Write out a CTF archive. The entries in CTF_DICTS are referenced by name: 219*6881a400Schristos the names are passed in the names array, which must have CTF_DICTS entries. 2207d62b00eSchristos 2217d62b00eSchristos If the filename is NULL, create a temporary file and return a pointer to it. 2227d62b00eSchristos 2237d62b00eSchristos Returns 0 on success, or an errno, or an ECTF_* value. */ 2247d62b00eSchristos int 225*6881a400Schristos ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt, 2267d62b00eSchristos const char **names, size_t threshold) 2277d62b00eSchristos { 2287d62b00eSchristos int err; 2297d62b00eSchristos int fd; 2307d62b00eSchristos 2317d62b00eSchristos if ((fd = open (file, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) < 0) 2327d62b00eSchristos { 233*6881a400Schristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, 2347d62b00eSchristos _("ctf_arc_write(): cannot create %s"), file); 2357d62b00eSchristos return errno; 2367d62b00eSchristos } 2377d62b00eSchristos 238*6881a400Schristos err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, names, threshold); 2397d62b00eSchristos if (err) 2407d62b00eSchristos goto err_close; 2417d62b00eSchristos 2427d62b00eSchristos if ((err = close (fd)) < 0) 243*6881a400Schristos ctf_err_warn (ctf_dict_cnt > 0 ? ctf_dicts[0] : NULL, 0, errno, 2447d62b00eSchristos _("ctf_arc_write(): cannot close after writing to archive")); 2457d62b00eSchristos goto err; 2467d62b00eSchristos 2477d62b00eSchristos err_close: 2487d62b00eSchristos (void) close (fd); 2497d62b00eSchristos err: 2507d62b00eSchristos if (err < 0) 2517d62b00eSchristos unlink (file); 2527d62b00eSchristos 2537d62b00eSchristos return err; 2547d62b00eSchristos } 2557d62b00eSchristos 2567d62b00eSchristos /* Write one CTF file out. Return the file position of the written file (or 2577d62b00eSchristos rather, of the file-size uint64_t that precedes it): negative return is a 2587d62b00eSchristos negative errno or ctf_errno value. On error, the file position may no longer 2597d62b00eSchristos be at the end of the file. */ 2607d62b00eSchristos static off_t 261*6881a400Schristos arc_write_one_ctf (ctf_dict_t * f, int fd, size_t threshold) 2627d62b00eSchristos { 2637d62b00eSchristos off_t off, end_off; 2647d62b00eSchristos uint64_t ctfsz = 0; 2657d62b00eSchristos char *ctfszp; 2667d62b00eSchristos size_t ctfsz_len; 267*6881a400Schristos int (*writefn) (ctf_dict_t * fp, int fd); 2687d62b00eSchristos 2697d62b00eSchristos if (ctf_serialize (f) < 0) 2707d62b00eSchristos return f->ctf_errno * -1; 2717d62b00eSchristos 2727d62b00eSchristos if ((off = lseek (fd, 0, SEEK_CUR)) < 0) 2737d62b00eSchristos return errno * -1; 2747d62b00eSchristos 2757d62b00eSchristos if (f->ctf_size > threshold) 2767d62b00eSchristos writefn = ctf_compress_write; 2777d62b00eSchristos else 2787d62b00eSchristos writefn = ctf_write; 2797d62b00eSchristos 2807d62b00eSchristos /* This zero-write turns into the size in a moment. */ 2817d62b00eSchristos ctfsz_len = sizeof (ctfsz); 2827d62b00eSchristos ctfszp = (char *) &ctfsz; 2837d62b00eSchristos while (ctfsz_len > 0) 2847d62b00eSchristos { 2857d62b00eSchristos ssize_t writelen = write (fd, ctfszp, ctfsz_len); 2867d62b00eSchristos if (writelen < 0) 2877d62b00eSchristos return errno * -1; 2887d62b00eSchristos ctfsz_len -= writelen; 2897d62b00eSchristos ctfszp += writelen; 2907d62b00eSchristos } 2917d62b00eSchristos 2927d62b00eSchristos if (writefn (f, fd) != 0) 2937d62b00eSchristos return f->ctf_errno * -1; 2947d62b00eSchristos 2957d62b00eSchristos if ((end_off = lseek (fd, 0, SEEK_CUR)) < 0) 2967d62b00eSchristos return errno * -1; 2977d62b00eSchristos ctfsz = htole64 (end_off - off); 2987d62b00eSchristos 2997d62b00eSchristos if ((lseek (fd, off, SEEK_SET)) < 0) 3007d62b00eSchristos return errno * -1; 3017d62b00eSchristos 3027d62b00eSchristos /* ... here. */ 3037d62b00eSchristos ctfsz_len = sizeof (ctfsz); 3047d62b00eSchristos ctfszp = (char *) &ctfsz; 3057d62b00eSchristos while (ctfsz_len > 0) 3067d62b00eSchristos { 3077d62b00eSchristos ssize_t writelen = write (fd, ctfszp, ctfsz_len); 3087d62b00eSchristos if (writelen < 0) 3097d62b00eSchristos return errno * -1; 3107d62b00eSchristos ctfsz_len -= writelen; 3117d62b00eSchristos ctfszp += writelen; 3127d62b00eSchristos } 3137d62b00eSchristos 3147d62b00eSchristos end_off = LCTF_ALIGN_OFFS (end_off, 8); 3157d62b00eSchristos if ((lseek (fd, end_off, SEEK_SET)) < 0) 3167d62b00eSchristos return errno * -1; 3177d62b00eSchristos 3187d62b00eSchristos return off; 3197d62b00eSchristos } 3207d62b00eSchristos 3217d62b00eSchristos /* qsort() function to sort the array of struct ctf_archive_modents into 3227d62b00eSchristos ascending name order. */ 3237d62b00eSchristos static int 3247d62b00eSchristos sort_modent_by_name (const void *one, const void *two, void *n) 3257d62b00eSchristos { 3267d62b00eSchristos const struct ctf_archive_modent *a = one; 3277d62b00eSchristos const struct ctf_archive_modent *b = two; 3287d62b00eSchristos char *nametbl = n; 3297d62b00eSchristos 3307d62b00eSchristos return strcmp (&nametbl[le64toh (a->name_offset)], 3317d62b00eSchristos &nametbl[le64toh (b->name_offset)]); 3327d62b00eSchristos } 3337d62b00eSchristos 3347d62b00eSchristos /* bsearch_r() function to search for a given name in the sorted array of struct 3357d62b00eSchristos ctf_archive_modents. */ 3367d62b00eSchristos static int 3377d62b00eSchristos search_modent_by_name (const void *key, const void *ent, void *arg) 3387d62b00eSchristos { 3397d62b00eSchristos const char *k = key; 3407d62b00eSchristos const struct ctf_archive_modent *v = ent; 3417d62b00eSchristos const char *search_nametbl = arg; 3427d62b00eSchristos 3437d62b00eSchristos return strcmp (k, &search_nametbl[le64toh (v->name_offset)]); 3447d62b00eSchristos } 3457d62b00eSchristos 3467d62b00eSchristos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a 347*6881a400Schristos ctf_dict. Closes ARC and/or FP on error. Arrange to free the SYMSECT or 3487d62b00eSchristos STRSECT, as needed, on close. Possibly do not unmap on close. */ 3497d62b00eSchristos 3507d62b00eSchristos struct ctf_archive_internal * 3517d62b00eSchristos ctf_new_archive_internal (int is_archive, int unmap_on_close, 3527d62b00eSchristos struct ctf_archive *arc, 353*6881a400Schristos ctf_dict_t *fp, const ctf_sect_t *symsect, 3547d62b00eSchristos const ctf_sect_t *strsect, 3557d62b00eSchristos int *errp) 3567d62b00eSchristos { 3577d62b00eSchristos struct ctf_archive_internal *arci; 3587d62b00eSchristos 3597d62b00eSchristos if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL) 3607d62b00eSchristos { 3617d62b00eSchristos if (is_archive) 3627d62b00eSchristos { 3637d62b00eSchristos if (unmap_on_close) 3647d62b00eSchristos ctf_arc_close_internal (arc); 3657d62b00eSchristos } 3667d62b00eSchristos else 367*6881a400Schristos ctf_dict_close (fp); 3687d62b00eSchristos return (ctf_set_open_errno (errp, errno)); 3697d62b00eSchristos } 3707d62b00eSchristos arci->ctfi_is_archive = is_archive; 3717d62b00eSchristos if (is_archive) 3727d62b00eSchristos arci->ctfi_archive = arc; 3737d62b00eSchristos else 374*6881a400Schristos arci->ctfi_dict = fp; 3757d62b00eSchristos if (symsect) 3767d62b00eSchristos memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect)); 3777d62b00eSchristos if (strsect) 3787d62b00eSchristos memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect)); 3797d62b00eSchristos arci->ctfi_free_symsect = 0; 3807d62b00eSchristos arci->ctfi_free_strsect = 0; 3817d62b00eSchristos arci->ctfi_unmap_on_close = unmap_on_close; 382*6881a400Schristos arci->ctfi_symsect_little_endian = -1; 3837d62b00eSchristos 3847d62b00eSchristos return arci; 3857d62b00eSchristos } 3867d62b00eSchristos 387*6881a400Schristos /* Set the symbol-table endianness of an archive (defaulting the symtab 388*6881a400Schristos endianness of all ctf_file_t's opened from that archive). */ 389*6881a400Schristos void 390*6881a400Schristos ctf_arc_symsect_endianness (ctf_archive_t *arc, int little_endian) 391*6881a400Schristos { 392*6881a400Schristos arc->ctfi_symsect_little_endian = !!little_endian; 393*6881a400Schristos if (!arc->ctfi_is_archive) 394*6881a400Schristos ctf_symsect_endianness (arc->ctfi_dict, arc->ctfi_symsect_little_endian); 395*6881a400Schristos } 396*6881a400Schristos 397*6881a400Schristos /* Get the CTF preamble from data in a buffer, which may be either an archive or 398*6881a400Schristos a CTF dict. If multiple dicts are present in an archive, the preamble comes 399*6881a400Schristos from an arbitrary dict. The preamble is a pointer into the ctfsect passed 400*6881a400Schristos in. */ 401*6881a400Schristos 402*6881a400Schristos const ctf_preamble_t * 403*6881a400Schristos ctf_arc_bufpreamble (const ctf_sect_t *ctfsect) 404*6881a400Schristos { 405*6881a400Schristos if (ctfsect->cts_size > sizeof (uint64_t) && 406*6881a400Schristos (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC)) 407*6881a400Schristos { 408*6881a400Schristos struct ctf_archive *arc = (struct ctf_archive *) ctfsect->cts_data; 409*6881a400Schristos return (const ctf_preamble_t *) ((char *) arc + le64toh (arc->ctfa_ctfs) 410*6881a400Schristos + sizeof (uint64_t)); 411*6881a400Schristos } 412*6881a400Schristos else 413*6881a400Schristos return (const ctf_preamble_t *) ctfsect->cts_data; 414*6881a400Schristos } 415*6881a400Schristos 4167d62b00eSchristos /* Open a CTF archive or dictionary from data in a buffer (which the caller must 4177d62b00eSchristos preserve until ctf_arc_close() time). Returns the archive, or NULL and an 4187d62b00eSchristos error in *err (if not NULL). */ 4197d62b00eSchristos ctf_archive_t * 4207d62b00eSchristos ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, 4217d62b00eSchristos const ctf_sect_t *strsect, int *errp) 4227d62b00eSchristos { 4237d62b00eSchristos struct ctf_archive *arc = NULL; 4247d62b00eSchristos int is_archive; 425*6881a400Schristos ctf_dict_t *fp = NULL; 4267d62b00eSchristos 4277d62b00eSchristos if (ctfsect->cts_size > sizeof (uint64_t) && 4287d62b00eSchristos (le64toh ((*(uint64_t *) ctfsect->cts_data)) == CTFA_MAGIC)) 4297d62b00eSchristos { 4307d62b00eSchristos /* The archive is mmappable, so this operation is trivial. 4317d62b00eSchristos 4327d62b00eSchristos This buffer is nonmodifiable, so the trick involving mmapping only part 4337d62b00eSchristos of it and storing the length in the magic number is not applicable: so 4347d62b00eSchristos record this fact in the archive-wrapper header. (We cannot record it 4357d62b00eSchristos in the archive, because the archive may very well be a read-only 4367d62b00eSchristos mapping.) */ 4377d62b00eSchristos 4387d62b00eSchristos is_archive = 1; 4397d62b00eSchristos arc = (struct ctf_archive *) ctfsect->cts_data; 4407d62b00eSchristos } 4417d62b00eSchristos else 4427d62b00eSchristos { 4437d62b00eSchristos is_archive = 0; 4447d62b00eSchristos if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL) 4457d62b00eSchristos { 4467d62b00eSchristos ctf_err_warn (NULL, 0, *errp, _("ctf_arc_bufopen(): cannot open CTF")); 4477d62b00eSchristos return NULL; 4487d62b00eSchristos } 4497d62b00eSchristos } 4507d62b00eSchristos return ctf_new_archive_internal (is_archive, 0, arc, fp, symsect, strsect, 4517d62b00eSchristos errp); 4527d62b00eSchristos } 4537d62b00eSchristos 4547d62b00eSchristos /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if 4557d62b00eSchristos not NULL). */ 4567d62b00eSchristos struct ctf_archive * 4577d62b00eSchristos ctf_arc_open_internal (const char *filename, int *errp) 4587d62b00eSchristos { 4597d62b00eSchristos const char *errmsg; 4607d62b00eSchristos int fd; 4617d62b00eSchristos struct stat s; 4627d62b00eSchristos struct ctf_archive *arc; /* (Actually the whole file.) */ 4637d62b00eSchristos 4647d62b00eSchristos libctf_init_debug(); 4657d62b00eSchristos if ((fd = open (filename, O_RDONLY)) < 0) 4667d62b00eSchristos { 4677d62b00eSchristos errmsg = N_("ctf_arc_open(): cannot open %s"); 4687d62b00eSchristos goto err; 4697d62b00eSchristos } 4707d62b00eSchristos if (fstat (fd, &s) < 0) 4717d62b00eSchristos { 4727d62b00eSchristos errmsg = N_("ctf_arc_open(): cannot stat %s"); 4737d62b00eSchristos goto err_close; 4747d62b00eSchristos } 4757d62b00eSchristos 4767d62b00eSchristos if ((arc = arc_mmap_file (fd, s.st_size)) == NULL) 4777d62b00eSchristos { 4787d62b00eSchristos errmsg = N_("ctf_arc_open(): cannot read in %s"); 4797d62b00eSchristos goto err_close; 4807d62b00eSchristos } 4817d62b00eSchristos 4827d62b00eSchristos if (le64toh (arc->ctfa_magic) != CTFA_MAGIC) 4837d62b00eSchristos { 4847d62b00eSchristos errmsg = N_("ctf_arc_open(): %s: invalid magic number"); 4857d62b00eSchristos errno = ECTF_FMT; 4867d62b00eSchristos goto err_unmap; 4877d62b00eSchristos } 4887d62b00eSchristos 4897d62b00eSchristos /* This horrible hack lets us know how much to unmap when the file is 4907d62b00eSchristos closed. (We no longer need the magic number, and the mapping 4917d62b00eSchristos is private.) */ 4927d62b00eSchristos arc->ctfa_magic = s.st_size; 4937d62b00eSchristos close (fd); 4947d62b00eSchristos return arc; 4957d62b00eSchristos 4967d62b00eSchristos err_unmap: 4977d62b00eSchristos arc_mmap_unmap (arc, s.st_size, NULL); 4987d62b00eSchristos err_close: 4997d62b00eSchristos close (fd); 5007d62b00eSchristos err: 5017d62b00eSchristos if (errp) 5027d62b00eSchristos *errp = errno; 5037d62b00eSchristos ctf_err_warn (NULL, 0, errno, gettext (errmsg), filename); 5047d62b00eSchristos return NULL; 5057d62b00eSchristos } 5067d62b00eSchristos 5077d62b00eSchristos /* Close an archive. */ 5087d62b00eSchristos void 5097d62b00eSchristos ctf_arc_close_internal (struct ctf_archive *arc) 5107d62b00eSchristos { 5117d62b00eSchristos if (arc == NULL) 5127d62b00eSchristos return; 5137d62b00eSchristos 5147d62b00eSchristos /* See the comment in ctf_arc_open(). */ 5157d62b00eSchristos arc_mmap_unmap (arc, arc->ctfa_magic, NULL); 5167d62b00eSchristos } 5177d62b00eSchristos 5187d62b00eSchristos /* Public entry point: close an archive, or CTF file. */ 5197d62b00eSchristos void 5207d62b00eSchristos ctf_arc_close (ctf_archive_t *arc) 5217d62b00eSchristos { 5227d62b00eSchristos if (arc == NULL) 5237d62b00eSchristos return; 5247d62b00eSchristos 5257d62b00eSchristos if (arc->ctfi_is_archive) 5267d62b00eSchristos { 5277d62b00eSchristos if (arc->ctfi_unmap_on_close) 5287d62b00eSchristos ctf_arc_close_internal (arc->ctfi_archive); 5297d62b00eSchristos } 5307d62b00eSchristos else 531*6881a400Schristos ctf_dict_close (arc->ctfi_dict); 532*6881a400Schristos free (arc->ctfi_symdicts); 533*6881a400Schristos free (arc->ctfi_symnamedicts); 534*6881a400Schristos ctf_dynhash_destroy (arc->ctfi_dicts); 5357d62b00eSchristos if (arc->ctfi_free_symsect) 5367d62b00eSchristos free ((void *) arc->ctfi_symsect.cts_data); 5377d62b00eSchristos if (arc->ctfi_free_strsect) 5387d62b00eSchristos free ((void *) arc->ctfi_strsect.cts_data); 5397d62b00eSchristos free (arc->ctfi_data); 5407d62b00eSchristos if (arc->ctfi_bfd_close) 5417d62b00eSchristos arc->ctfi_bfd_close (arc); 5427d62b00eSchristos free (arc); 5437d62b00eSchristos } 5447d62b00eSchristos 545*6881a400Schristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 5467d62b00eSchristos non-NULL. A name of NULL means to open the default file. */ 547*6881a400Schristos static ctf_dict_t * 548*6881a400Schristos ctf_dict_open_internal (const struct ctf_archive *arc, 5497d62b00eSchristos const ctf_sect_t *symsect, 5507d62b00eSchristos const ctf_sect_t *strsect, 551*6881a400Schristos const char *name, int little_endian, 552*6881a400Schristos int *errp) 5537d62b00eSchristos { 5547d62b00eSchristos struct ctf_archive_modent *modent; 5557d62b00eSchristos const char *search_nametbl; 5567d62b00eSchristos 5577d62b00eSchristos if (name == NULL) 5587d62b00eSchristos name = _CTF_SECTION; /* The default name. */ 5597d62b00eSchristos 560*6881a400Schristos ctf_dprintf ("ctf_dict_open_internal(%s): opening\n", name); 5617d62b00eSchristos 5627d62b00eSchristos modent = (ctf_archive_modent_t *) ((char *) arc 5637d62b00eSchristos + sizeof (struct ctf_archive)); 5647d62b00eSchristos 5657d62b00eSchristos search_nametbl = (const char *) arc + le64toh (arc->ctfa_names); 566*6881a400Schristos modent = bsearch_r (name, modent, le64toh (arc->ctfa_ndicts), 5677d62b00eSchristos sizeof (struct ctf_archive_modent), 5687d62b00eSchristos search_modent_by_name, (void *) search_nametbl); 5697d62b00eSchristos 5707d62b00eSchristos /* This is actually a common case and normal operation: no error 5717d62b00eSchristos debug output. */ 5727d62b00eSchristos if (modent == NULL) 5737d62b00eSchristos { 5747d62b00eSchristos if (errp) 5757d62b00eSchristos *errp = ECTF_ARNNAME; 5767d62b00eSchristos return NULL; 5777d62b00eSchristos } 5787d62b00eSchristos 579*6881a400Schristos return ctf_dict_open_by_offset (arc, symsect, strsect, 580*6881a400Schristos le64toh (modent->ctf_offset), 581*6881a400Schristos little_endian, errp); 5827d62b00eSchristos } 5837d62b00eSchristos 584*6881a400Schristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 5857d62b00eSchristos non-NULL. A name of NULL means to open the default file. 5867d62b00eSchristos 5877d62b00eSchristos Use the specified string and symbol table sections. 5887d62b00eSchristos 5897d62b00eSchristos Public entry point. */ 590*6881a400Schristos ctf_dict_t * 591*6881a400Schristos ctf_dict_open_sections (const ctf_archive_t *arc, 5927d62b00eSchristos const ctf_sect_t *symsect, 5937d62b00eSchristos const ctf_sect_t *strsect, 5947d62b00eSchristos const char *name, 5957d62b00eSchristos int *errp) 5967d62b00eSchristos { 5977d62b00eSchristos if (arc->ctfi_is_archive) 5987d62b00eSchristos { 599*6881a400Schristos ctf_dict_t *ret; 600*6881a400Schristos ret = ctf_dict_open_internal (arc->ctfi_archive, symsect, strsect, 601*6881a400Schristos name, arc->ctfi_symsect_little_endian, 602*6881a400Schristos errp); 6037d62b00eSchristos if (ret) 604*6881a400Schristos { 6057d62b00eSchristos ret->ctf_archive = (ctf_archive_t *) arc; 606*6881a400Schristos ctf_arc_import_parent (arc, ret); 607*6881a400Schristos } 6087d62b00eSchristos return ret; 6097d62b00eSchristos } 6107d62b00eSchristos 6117d62b00eSchristos if ((name != NULL) && (strcmp (name, _CTF_SECTION) != 0)) 6127d62b00eSchristos { 6137d62b00eSchristos if (errp) 6147d62b00eSchristos *errp = ECTF_ARNNAME; 6157d62b00eSchristos return NULL; 6167d62b00eSchristos } 617*6881a400Schristos arc->ctfi_dict->ctf_archive = (ctf_archive_t *) arc; 6187d62b00eSchristos 619*6881a400Schristos /* Bump the refcount so that the user can ctf_dict_close() it. */ 620*6881a400Schristos arc->ctfi_dict->ctf_refcnt++; 621*6881a400Schristos return arc->ctfi_dict; 6227d62b00eSchristos } 6237d62b00eSchristos 624*6881a400Schristos /* Return the ctf_dict_t with the given name, or NULL if none, setting 'err' if 6257d62b00eSchristos non-NULL. A name of NULL means to open the default file. 6267d62b00eSchristos 6277d62b00eSchristos Public entry point. */ 628*6881a400Schristos ctf_dict_t * 629*6881a400Schristos ctf_dict_open (const ctf_archive_t *arc, const char *name, int *errp) 6307d62b00eSchristos { 6317d62b00eSchristos const ctf_sect_t *symsect = &arc->ctfi_symsect; 6327d62b00eSchristos const ctf_sect_t *strsect = &arc->ctfi_strsect; 6337d62b00eSchristos 6347d62b00eSchristos if (symsect->cts_name == NULL) 6357d62b00eSchristos symsect = NULL; 6367d62b00eSchristos if (strsect->cts_name == NULL) 6377d62b00eSchristos strsect = NULL; 6387d62b00eSchristos 639*6881a400Schristos return ctf_dict_open_sections (arc, symsect, strsect, name, errp); 6407d62b00eSchristos } 6417d62b00eSchristos 642*6881a400Schristos static void 643*6881a400Schristos ctf_cached_dict_close (void *fp) 644*6881a400Schristos { 645*6881a400Schristos ctf_dict_close ((ctf_dict_t *) fp); 646*6881a400Schristos } 647*6881a400Schristos 648*6881a400Schristos /* Return the ctf_dict_t with the given name and cache it in the archive's 649*6881a400Schristos ctfi_dicts. If this is the first cached dict, designate it the 650*6881a400Schristos crossdict_cache. */ 651*6881a400Schristos static ctf_dict_t * 652*6881a400Schristos ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp) 653*6881a400Schristos { 654*6881a400Schristos ctf_dict_t *fp; 655*6881a400Schristos char *dupname; 656*6881a400Schristos 657*6881a400Schristos /* Just return from the cache if possible. */ 658*6881a400Schristos if (arc->ctfi_dicts 659*6881a400Schristos && ((fp = ctf_dynhash_lookup (arc->ctfi_dicts, name)) != NULL)) 660*6881a400Schristos { 661*6881a400Schristos fp->ctf_refcnt++; 662*6881a400Schristos return fp; 663*6881a400Schristos } 664*6881a400Schristos 665*6881a400Schristos /* Not yet cached: open it. */ 666*6881a400Schristos fp = ctf_dict_open (arc, name, errp); 667*6881a400Schristos dupname = strdup (name); 668*6881a400Schristos 669*6881a400Schristos if (!fp || !dupname) 670*6881a400Schristos goto oom; 671*6881a400Schristos 672*6881a400Schristos if (arc->ctfi_dicts == NULL) 673*6881a400Schristos if ((arc->ctfi_dicts 674*6881a400Schristos = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, 675*6881a400Schristos free, ctf_cached_dict_close)) == NULL) 676*6881a400Schristos goto oom; 677*6881a400Schristos 678*6881a400Schristos if (ctf_dynhash_insert (arc->ctfi_dicts, dupname, fp) < 0) 679*6881a400Schristos goto oom; 680*6881a400Schristos fp->ctf_refcnt++; 681*6881a400Schristos 682*6881a400Schristos if (arc->ctfi_crossdict_cache == NULL) 683*6881a400Schristos arc->ctfi_crossdict_cache = fp; 684*6881a400Schristos 685*6881a400Schristos return fp; 686*6881a400Schristos 687*6881a400Schristos oom: 688*6881a400Schristos ctf_dict_close (fp); 689*6881a400Schristos free (dupname); 690*6881a400Schristos if (errp) 691*6881a400Schristos *errp = ENOMEM; 692*6881a400Schristos return NULL; 693*6881a400Schristos } 694*6881a400Schristos 695*6881a400Schristos /* Flush any caches the CTF archive may have open. */ 696*6881a400Schristos void 697*6881a400Schristos ctf_arc_flush_caches (ctf_archive_t *wrapper) 698*6881a400Schristos { 699*6881a400Schristos free (wrapper->ctfi_symdicts); 700*6881a400Schristos free (wrapper->ctfi_symnamedicts); 701*6881a400Schristos ctf_dynhash_destroy (wrapper->ctfi_dicts); 702*6881a400Schristos wrapper->ctfi_symdicts = NULL; 703*6881a400Schristos wrapper->ctfi_symnamedicts = NULL; 704*6881a400Schristos wrapper->ctfi_dicts = NULL; 705*6881a400Schristos wrapper->ctfi_crossdict_cache = NULL; 706*6881a400Schristos } 707*6881a400Schristos 708*6881a400Schristos /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if 7097d62b00eSchristos none, setting 'err' if non-NULL. */ 710*6881a400Schristos static ctf_dict_t * 711*6881a400Schristos ctf_dict_open_by_offset (const struct ctf_archive *arc, 7127d62b00eSchristos const ctf_sect_t *symsect, 7137d62b00eSchristos const ctf_sect_t *strsect, size_t offset, 714*6881a400Schristos int little_endian, int *errp) 7157d62b00eSchristos { 7167d62b00eSchristos ctf_sect_t ctfsect; 717*6881a400Schristos ctf_dict_t *fp; 7187d62b00eSchristos 719*6881a400Schristos ctf_dprintf ("ctf_dict_open_by_offset(%lu): opening\n", (unsigned long) offset); 7207d62b00eSchristos 7217d62b00eSchristos memset (&ctfsect, 0, sizeof (ctf_sect_t)); 7227d62b00eSchristos 7237d62b00eSchristos offset += le64toh (arc->ctfa_ctfs); 7247d62b00eSchristos 7257d62b00eSchristos ctfsect.cts_name = _CTF_SECTION; 7267d62b00eSchristos ctfsect.cts_size = le64toh (*((uint64_t *) ((char *) arc + offset))); 7277d62b00eSchristos ctfsect.cts_entsize = 1; 7287d62b00eSchristos ctfsect.cts_data = (void *) ((char *) arc + offset + sizeof (uint64_t)); 7297d62b00eSchristos fp = ctf_bufopen (&ctfsect, symsect, strsect, errp); 7307d62b00eSchristos if (fp) 731*6881a400Schristos { 7327d62b00eSchristos ctf_setmodel (fp, le64toh (arc->ctfa_model)); 733*6881a400Schristos if (little_endian >= 0) 734*6881a400Schristos ctf_symsect_endianness (fp, little_endian); 735*6881a400Schristos } 7367d62b00eSchristos return fp; 7377d62b00eSchristos } 7387d62b00eSchristos 739*6881a400Schristos /* Backward compatibility. */ 740*6881a400Schristos ctf_dict_t * 741*6881a400Schristos ctf_arc_open_by_name (const ctf_archive_t *arc, const char *name, 742*6881a400Schristos int *errp) 743*6881a400Schristos { 744*6881a400Schristos return ctf_dict_open (arc, name, errp); 745*6881a400Schristos } 746*6881a400Schristos 747*6881a400Schristos ctf_dict_t * 748*6881a400Schristos ctf_arc_open_by_name_sections (const ctf_archive_t *arc, 749*6881a400Schristos const ctf_sect_t *symsect, 750*6881a400Schristos const ctf_sect_t *strsect, 751*6881a400Schristos const char *name, 752*6881a400Schristos int *errp) 753*6881a400Schristos { 754*6881a400Schristos return ctf_dict_open_sections (arc, symsect, strsect, name, errp); 755*6881a400Schristos } 756*6881a400Schristos 757*6881a400Schristos /* Import the parent into a ctf archive, if this is a child, the parent is not 758*6881a400Schristos already set, and a suitable archive member exists. No error is raised if 759*6881a400Schristos this is not possible: this is just a best-effort helper operation to give 760*6881a400Schristos people useful dicts to start with. */ 761*6881a400Schristos static void 762*6881a400Schristos ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp) 763*6881a400Schristos { 764*6881a400Schristos if ((fp->ctf_flags & LCTF_CHILD) && fp->ctf_parname && !fp->ctf_parent) 765*6881a400Schristos { 766*6881a400Schristos ctf_dict_t *parent = ctf_dict_open_cached ((ctf_archive_t *) arc, 767*6881a400Schristos fp->ctf_parname, NULL); 768*6881a400Schristos if (parent) 769*6881a400Schristos { 770*6881a400Schristos ctf_import (fp, parent); 771*6881a400Schristos ctf_dict_close (parent); 772*6881a400Schristos } 773*6881a400Schristos } 774*6881a400Schristos } 775*6881a400Schristos 7767d62b00eSchristos /* Return the number of members in an archive. */ 7777d62b00eSchristos size_t 7787d62b00eSchristos ctf_archive_count (const ctf_archive_t *wrapper) 7797d62b00eSchristos { 7807d62b00eSchristos if (!wrapper->ctfi_is_archive) 7817d62b00eSchristos return 1; 7827d62b00eSchristos 783*6881a400Schristos return wrapper->ctfi_archive->ctfa_ndicts; 784*6881a400Schristos } 785*6881a400Schristos 786*6881a400Schristos /* Look up a symbol in an archive by name or index (if the name is set, a lookup 787*6881a400Schristos by name is done). Return the dict in the archive that the symbol is found 788*6881a400Schristos in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't 789*6881a400Schristos have to look it up yourself). The dict is cached, so repeated lookups are 790*6881a400Schristos nearly free. 791*6881a400Schristos 792*6881a400Schristos As usual, you should ctf_dict_close() the returned dict once you are done 793*6881a400Schristos with it. 794*6881a400Schristos 795*6881a400Schristos Returns NULL on error, and an error in errp (if set). */ 796*6881a400Schristos 797*6881a400Schristos static ctf_dict_t * 798*6881a400Schristos ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx, 799*6881a400Schristos const char *symname, ctf_id_t *typep, int *errp) 800*6881a400Schristos { 801*6881a400Schristos ctf_dict_t *fp; 802*6881a400Schristos void *fpkey; 803*6881a400Schristos ctf_id_t type; 804*6881a400Schristos 805*6881a400Schristos /* The usual non-archive-transparent-wrapper special case. */ 806*6881a400Schristos if (!wrapper->ctfi_is_archive) 807*6881a400Schristos { 808*6881a400Schristos if (!symname) 809*6881a400Schristos { 810*6881a400Schristos if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR) 811*6881a400Schristos { 812*6881a400Schristos if (errp) 813*6881a400Schristos *errp = ctf_errno (wrapper->ctfi_dict); 814*6881a400Schristos return NULL; 815*6881a400Schristos } 816*6881a400Schristos } 817*6881a400Schristos else 818*6881a400Schristos { 819*6881a400Schristos if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict, 820*6881a400Schristos symname)) == CTF_ERR) 821*6881a400Schristos { 822*6881a400Schristos if (errp) 823*6881a400Schristos *errp = ctf_errno (wrapper->ctfi_dict); 824*6881a400Schristos return NULL; 825*6881a400Schristos } 826*6881a400Schristos } 827*6881a400Schristos if (typep) 828*6881a400Schristos *typep = type; 829*6881a400Schristos wrapper->ctfi_dict->ctf_refcnt++; 830*6881a400Schristos return wrapper->ctfi_dict; 831*6881a400Schristos } 832*6881a400Schristos 833*6881a400Schristos if (wrapper->ctfi_symsect.cts_name == NULL 834*6881a400Schristos || wrapper->ctfi_symsect.cts_data == NULL 835*6881a400Schristos || wrapper->ctfi_symsect.cts_size == 0 836*6881a400Schristos || wrapper->ctfi_symsect.cts_entsize == 0) 837*6881a400Schristos { 838*6881a400Schristos if (errp) 839*6881a400Schristos *errp = ECTF_NOSYMTAB; 840*6881a400Schristos return NULL; 841*6881a400Schristos } 842*6881a400Schristos 843*6881a400Schristos /* Make enough space for all possible symbol indexes, if not already done. We 844*6881a400Schristos cache the originating dictionary of all symbols. The dict links are weak, 845*6881a400Schristos to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped. 846*6881a400Schristos We also cache similar mappings for symbol names: these are ordinary 847*6881a400Schristos dynhashes, with weak links to dicts. */ 848*6881a400Schristos 849*6881a400Schristos if (!wrapper->ctfi_symdicts) 850*6881a400Schristos { 851*6881a400Schristos if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size 852*6881a400Schristos / wrapper->ctfi_symsect.cts_entsize, 853*6881a400Schristos sizeof (ctf_dict_t *))) == NULL) 854*6881a400Schristos { 855*6881a400Schristos if (errp) 856*6881a400Schristos *errp = ENOMEM; 857*6881a400Schristos return NULL; 858*6881a400Schristos } 859*6881a400Schristos } 860*6881a400Schristos if (!wrapper->ctfi_symnamedicts) 861*6881a400Schristos { 862*6881a400Schristos if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string, 863*6881a400Schristos ctf_hash_eq_string, 864*6881a400Schristos free, NULL)) == NULL) 865*6881a400Schristos { 866*6881a400Schristos if (errp) 867*6881a400Schristos *errp = ENOMEM; 868*6881a400Schristos return NULL; 869*6881a400Schristos } 870*6881a400Schristos } 871*6881a400Schristos 872*6881a400Schristos /* Perhaps the dict in which we found a previous lookup is cached. If it's 873*6881a400Schristos supposed to be cached but we don't find it, pretend it was always not 874*6881a400Schristos found: this should never happen, but shouldn't be allowed to cause trouble 875*6881a400Schristos if it does. */ 876*6881a400Schristos 877*6881a400Schristos if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts, 878*6881a400Schristos symname, NULL, &fpkey)) 879*6881a400Schristos || (!symname && wrapper->ctfi_symdicts[symidx] != NULL)) 880*6881a400Schristos { 881*6881a400Schristos if (symname) 882*6881a400Schristos fp = (ctf_dict_t *) fpkey; 883*6881a400Schristos else 884*6881a400Schristos fp = wrapper->ctfi_symdicts[symidx]; 885*6881a400Schristos 886*6881a400Schristos if (fp == &enosym) 887*6881a400Schristos goto no_sym; 888*6881a400Schristos 889*6881a400Schristos if (symname) 890*6881a400Schristos { 891*6881a400Schristos if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR) 892*6881a400Schristos goto cache_no_sym; 893*6881a400Schristos } 894*6881a400Schristos else 895*6881a400Schristos { 896*6881a400Schristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) 897*6881a400Schristos goto cache_no_sym; 898*6881a400Schristos } 899*6881a400Schristos 900*6881a400Schristos if (typep) 901*6881a400Schristos *typep = type; 902*6881a400Schristos fp->ctf_refcnt++; 903*6881a400Schristos return fp; 904*6881a400Schristos } 905*6881a400Schristos 906*6881a400Schristos /* Not cached: find it and cache it. We must track open errors ourselves even 907*6881a400Schristos if our caller doesn't, to be able to distinguish no-error end-of-iteration 908*6881a400Schristos from open errors. */ 909*6881a400Schristos 910*6881a400Schristos int local_err; 911*6881a400Schristos int *local_errp; 912*6881a400Schristos ctf_next_t *i = NULL; 913*6881a400Schristos const char *name; 914*6881a400Schristos 915*6881a400Schristos if (errp) 916*6881a400Schristos local_errp = errp; 917*6881a400Schristos else 918*6881a400Schristos local_errp = &local_err; 919*6881a400Schristos 920*6881a400Schristos while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL) 921*6881a400Schristos { 922*6881a400Schristos if (!symname) 923*6881a400Schristos { 924*6881a400Schristos if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR) 925*6881a400Schristos wrapper->ctfi_symdicts[symidx] = fp; 926*6881a400Schristos } 927*6881a400Schristos else 928*6881a400Schristos { 929*6881a400Schristos if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR) 930*6881a400Schristos { 931*6881a400Schristos char *tmp; 932*6881a400Schristos /* No error checking, as above. */ 933*6881a400Schristos if ((tmp = strdup (symname)) != NULL) 934*6881a400Schristos ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp); 935*6881a400Schristos } 936*6881a400Schristos } 937*6881a400Schristos 938*6881a400Schristos if (type != CTF_ERR) 939*6881a400Schristos { 940*6881a400Schristos if (typep) 941*6881a400Schristos *typep = type; 942*6881a400Schristos ctf_next_destroy (i); 943*6881a400Schristos return fp; 944*6881a400Schristos } 945*6881a400Schristos if (ctf_errno (fp) != ECTF_NOTYPEDAT) 946*6881a400Schristos { 947*6881a400Schristos if (errp) 948*6881a400Schristos *errp = ctf_errno (fp); 949*6881a400Schristos ctf_next_destroy (i); 950*6881a400Schristos return NULL; /* errno is set for us. */ 951*6881a400Schristos } 952*6881a400Schristos ctf_dict_close (fp); 953*6881a400Schristos } 954*6881a400Schristos if (*local_errp != ECTF_NEXT_END) 955*6881a400Schristos { 956*6881a400Schristos ctf_next_destroy (i); 957*6881a400Schristos return NULL; 958*6881a400Schristos } 959*6881a400Schristos 960*6881a400Schristos /* Don't leak end-of-iteration to the caller. */ 961*6881a400Schristos *local_errp = 0; 962*6881a400Schristos 963*6881a400Schristos cache_no_sym: 964*6881a400Schristos if (!symname) 965*6881a400Schristos wrapper->ctfi_symdicts[symidx] = &enosym; 966*6881a400Schristos else 967*6881a400Schristos { 968*6881a400Schristos char *tmp; 969*6881a400Schristos 970*6881a400Schristos /* No error checking: if caching fails, there is only a slight performance 971*6881a400Schristos impact. */ 972*6881a400Schristos if ((tmp = strdup (symname)) != NULL) 973*6881a400Schristos if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0) 974*6881a400Schristos free (tmp); 975*6881a400Schristos } 976*6881a400Schristos 977*6881a400Schristos no_sym: 978*6881a400Schristos if (errp) 979*6881a400Schristos *errp = ECTF_NOTYPEDAT; 980*6881a400Schristos if (typep) 981*6881a400Schristos *typep = CTF_ERR; 982*6881a400Schristos return NULL; 983*6881a400Schristos } 984*6881a400Schristos 985*6881a400Schristos /* The public API for looking up a symbol by index. */ 986*6881a400Schristos ctf_dict_t * 987*6881a400Schristos ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx, 988*6881a400Schristos ctf_id_t *typep, int *errp) 989*6881a400Schristos { 990*6881a400Schristos return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp); 991*6881a400Schristos } 992*6881a400Schristos 993*6881a400Schristos /* The public API for looking up a symbol by name. */ 994*6881a400Schristos 995*6881a400Schristos ctf_dict_t * 996*6881a400Schristos ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname, 997*6881a400Schristos ctf_id_t *typep, int *errp) 998*6881a400Schristos { 999*6881a400Schristos return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp); 10007d62b00eSchristos } 10017d62b00eSchristos 10027d62b00eSchristos /* Raw iteration over all CTF files in an archive. We pass the raw data for all 10037d62b00eSchristos CTF files in turn to the specified callback function. */ 10047d62b00eSchristos static int 10057d62b00eSchristos ctf_archive_raw_iter_internal (const struct ctf_archive *arc, 10067d62b00eSchristos ctf_archive_raw_member_f *func, void *data) 10077d62b00eSchristos { 10087d62b00eSchristos int rc; 10097d62b00eSchristos size_t i; 10107d62b00eSchristos struct ctf_archive_modent *modent; 10117d62b00eSchristos const char *nametbl; 10127d62b00eSchristos 10137d62b00eSchristos modent = (ctf_archive_modent_t *) ((char *) arc 10147d62b00eSchristos + sizeof (struct ctf_archive)); 10157d62b00eSchristos nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); 10167d62b00eSchristos 1017*6881a400Schristos for (i = 0; i < le64toh (arc->ctfa_ndicts); i++) 10187d62b00eSchristos { 10197d62b00eSchristos const char *name; 10207d62b00eSchristos char *fp; 10217d62b00eSchristos 10227d62b00eSchristos name = &nametbl[le64toh (modent[i].name_offset)]; 10237d62b00eSchristos fp = ((char *) arc + le64toh (arc->ctfa_ctfs) 10247d62b00eSchristos + le64toh (modent[i].ctf_offset)); 10257d62b00eSchristos 10267d62b00eSchristos if ((rc = func (name, (void *) (fp + sizeof (uint64_t)), 10277d62b00eSchristos le64toh (*((uint64_t *) fp)), data)) != 0) 10287d62b00eSchristos return rc; 10297d62b00eSchristos } 10307d62b00eSchristos return 0; 10317d62b00eSchristos } 10327d62b00eSchristos 10337d62b00eSchristos /* Raw iteration over all CTF files in an archive: public entry point. 10347d62b00eSchristos 10357d62b00eSchristos Returns -EINVAL if not supported for this sort of archive. */ 10367d62b00eSchristos int 10377d62b00eSchristos ctf_archive_raw_iter (const ctf_archive_t *arc, 10387d62b00eSchristos ctf_archive_raw_member_f * func, void *data) 10397d62b00eSchristos { 10407d62b00eSchristos if (arc->ctfi_is_archive) 10417d62b00eSchristos return ctf_archive_raw_iter_internal (arc->ctfi_archive, func, data); 10427d62b00eSchristos 10437d62b00eSchristos return -EINVAL; /* Not supported. */ 10447d62b00eSchristos } 10457d62b00eSchristos 10467d62b00eSchristos /* Iterate over all CTF files in an archive: public entry point. We pass all 10477d62b00eSchristos CTF files in turn to the specified callback function. */ 10487d62b00eSchristos int 10497d62b00eSchristos ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func, 10507d62b00eSchristos void *data) 10517d62b00eSchristos { 1052*6881a400Schristos ctf_next_t *i = NULL; 1053*6881a400Schristos ctf_dict_t *fp; 1054*6881a400Schristos const char *name; 1055*6881a400Schristos int err; 10567d62b00eSchristos 1057*6881a400Schristos while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL) 1058*6881a400Schristos { 1059*6881a400Schristos int rc; 10607d62b00eSchristos 1061*6881a400Schristos if ((rc = func (fp, name, data)) != 0) 1062*6881a400Schristos { 1063*6881a400Schristos ctf_dict_close (fp); 1064*6881a400Schristos ctf_next_destroy (i); 1065*6881a400Schristos return rc; 1066*6881a400Schristos } 1067*6881a400Schristos ctf_dict_close (fp); 1068*6881a400Schristos } 1069*6881a400Schristos return 0; 10707d62b00eSchristos } 10717d62b00eSchristos 10727d62b00eSchristos /* Iterate over all CTF files in an archive, returning each dict in turn as a 1073*6881a400Schristos ctf_dict_t, and NULL on error or end of iteration. It is the caller's 1074*6881a400Schristos responsibility to close it. Parent dicts may be skipped. 1075*6881a400Schristos 1076*6881a400Schristos The archive member is cached for rapid return on future calls. 10777d62b00eSchristos 10787d62b00eSchristos We identify parents by name rather than by flag value: for now, with the 10797d62b00eSchristos linker only emitting parents named _CTF_SECTION, this works well enough. */ 10807d62b00eSchristos 1081*6881a400Schristos ctf_dict_t * 10827d62b00eSchristos ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name, 10837d62b00eSchristos int skip_parent, int *errp) 10847d62b00eSchristos { 1085*6881a400Schristos ctf_dict_t *f; 10867d62b00eSchristos ctf_next_t *i = *it; 10877d62b00eSchristos struct ctf_archive *arc; 10887d62b00eSchristos struct ctf_archive_modent *modent; 10897d62b00eSchristos const char *nametbl; 10907d62b00eSchristos const char *name_; 10917d62b00eSchristos 10927d62b00eSchristos if (!i) 10937d62b00eSchristos { 10947d62b00eSchristos if ((i = ctf_next_create()) == NULL) 10957d62b00eSchristos { 10967d62b00eSchristos if (errp) 10977d62b00eSchristos *errp = ENOMEM; 10987d62b00eSchristos return NULL; 10997d62b00eSchristos } 11007d62b00eSchristos i->cu.ctn_arc = wrapper; 11017d62b00eSchristos i->ctn_iter_fun = (void (*) (void)) ctf_archive_next; 11027d62b00eSchristos *it = i; 11037d62b00eSchristos } 11047d62b00eSchristos 11057d62b00eSchristos if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun) 11067d62b00eSchristos { 11077d62b00eSchristos if (errp) 11087d62b00eSchristos *errp = ECTF_NEXT_WRONGFUN; 11097d62b00eSchristos return NULL; 11107d62b00eSchristos } 11117d62b00eSchristos 11127d62b00eSchristos if (wrapper != i->cu.ctn_arc) 11137d62b00eSchristos { 11147d62b00eSchristos if (errp) 11157d62b00eSchristos *errp = ECTF_NEXT_WRONGFP; 11167d62b00eSchristos return NULL; 11177d62b00eSchristos } 11187d62b00eSchristos 1119*6881a400Schristos /* Iteration is made a bit more complex by the need to handle ctf_dict_t's 11207d62b00eSchristos transparently wrapped in a single-member archive. These are parents: if 11217d62b00eSchristos skip_parent is on, they are skipped and the iterator terminates 11227d62b00eSchristos immediately. */ 11237d62b00eSchristos 11247d62b00eSchristos if (!wrapper->ctfi_is_archive && i->ctn_n == 0) 11257d62b00eSchristos { 11267d62b00eSchristos i->ctn_n++; 11277d62b00eSchristos if (!skip_parent) 11287d62b00eSchristos { 1129*6881a400Schristos wrapper->ctfi_dict->ctf_refcnt++; 1130*6881a400Schristos if (name) 1131*6881a400Schristos *name = _CTF_SECTION; 1132*6881a400Schristos return wrapper->ctfi_dict; 11337d62b00eSchristos } 11347d62b00eSchristos } 11357d62b00eSchristos 11367d62b00eSchristos arc = wrapper->ctfi_archive; 11377d62b00eSchristos 11387d62b00eSchristos /* The loop keeps going when skip_parent is on as long as the member we find 11397d62b00eSchristos is the parent (i.e. at most two iterations, but possibly an early return if 11407d62b00eSchristos *all* we have is a parent). */ 11417d62b00eSchristos 11427d62b00eSchristos do 11437d62b00eSchristos { 1144*6881a400Schristos if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_ndicts))) 11457d62b00eSchristos { 11467d62b00eSchristos ctf_next_destroy (i); 11477d62b00eSchristos *it = NULL; 11487d62b00eSchristos if (errp) 11497d62b00eSchristos *errp = ECTF_NEXT_END; 11507d62b00eSchristos return NULL; 11517d62b00eSchristos } 11527d62b00eSchristos 11537d62b00eSchristos modent = (ctf_archive_modent_t *) ((char *) arc 11547d62b00eSchristos + sizeof (struct ctf_archive)); 11557d62b00eSchristos nametbl = (((const char *) arc) + le64toh (arc->ctfa_names)); 11567d62b00eSchristos 11577d62b00eSchristos name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)]; 11587d62b00eSchristos i->ctn_n++; 1159*6881a400Schristos } 1160*6881a400Schristos while (skip_parent && strcmp (name_, _CTF_SECTION) == 0); 11617d62b00eSchristos 11627d62b00eSchristos if (name) 11637d62b00eSchristos *name = name_; 11647d62b00eSchristos 1165*6881a400Schristos f = ctf_dict_open_cached ((ctf_archive_t *) wrapper, name_, errp); 11667d62b00eSchristos return f; 11677d62b00eSchristos } 11687d62b00eSchristos 11697d62b00eSchristos #ifdef HAVE_MMAP 11707d62b00eSchristos /* Map the header in. Only used on new, empty files. */ 11717d62b00eSchristos static void *arc_mmap_header (int fd, size_t headersz) 11727d62b00eSchristos { 11737d62b00eSchristos void *hdr; 11747d62b00eSchristos if ((hdr = mmap (NULL, headersz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 11757d62b00eSchristos 0)) == MAP_FAILED) 11767d62b00eSchristos return NULL; 11777d62b00eSchristos return hdr; 11787d62b00eSchristos } 11797d62b00eSchristos 11807d62b00eSchristos /* mmap() the whole file, for reading only. (Map it writably, but privately: we 11817d62b00eSchristos need to modify the region, but don't need anyone else to see the 11827d62b00eSchristos modifications.) */ 11837d62b00eSchristos static void *arc_mmap_file (int fd, size_t size) 11847d62b00eSchristos { 11857d62b00eSchristos void *arc; 11867d62b00eSchristos if ((arc = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 11877d62b00eSchristos fd, 0)) == MAP_FAILED) 11887d62b00eSchristos return NULL; 11897d62b00eSchristos return arc; 11907d62b00eSchristos } 11917d62b00eSchristos 11927d62b00eSchristos /* Persist the header to disk. */ 11937d62b00eSchristos static int arc_mmap_writeout (int fd _libctf_unused_, void *header, 11947d62b00eSchristos size_t headersz, const char **errmsg) 11957d62b00eSchristos { 11967d62b00eSchristos if (msync (header, headersz, MS_ASYNC) < 0) 11977d62b00eSchristos { 11987d62b00eSchristos if (errmsg) 11997d62b00eSchristos *errmsg = N_("arc_mmap_writeout(): cannot sync after writing " 12007d62b00eSchristos "to %s: %s"); 12017d62b00eSchristos return -1; 12027d62b00eSchristos } 12037d62b00eSchristos return 0; 12047d62b00eSchristos } 12057d62b00eSchristos 12067d62b00eSchristos /* Unmap the region. */ 12077d62b00eSchristos static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg) 12087d62b00eSchristos { 12097d62b00eSchristos if (munmap (header, headersz) < 0) 12107d62b00eSchristos { 12117d62b00eSchristos if (errmsg) 12127d62b00eSchristos *errmsg = N_("arc_mmap_munmap(): cannot unmap after writing " 12137d62b00eSchristos "to %s: %s"); 12147d62b00eSchristos return -1; 12157d62b00eSchristos } 12167d62b00eSchristos return 0; 12177d62b00eSchristos } 12187d62b00eSchristos #else 12197d62b00eSchristos /* Map the header in. Only used on new, empty files. */ 12207d62b00eSchristos static void *arc_mmap_header (int fd _libctf_unused_, size_t headersz) 12217d62b00eSchristos { 12227d62b00eSchristos void *hdr; 12237d62b00eSchristos if ((hdr = malloc (headersz)) == NULL) 12247d62b00eSchristos return NULL; 12257d62b00eSchristos return hdr; 12267d62b00eSchristos } 12277d62b00eSchristos 12287d62b00eSchristos /* Pull in the whole file, for reading only. We assume the current file 12297d62b00eSchristos position is at the start of the file. */ 12307d62b00eSchristos static void *arc_mmap_file (int fd, size_t size) 12317d62b00eSchristos { 12327d62b00eSchristos char *data; 12337d62b00eSchristos 12347d62b00eSchristos if ((data = malloc (size)) == NULL) 12357d62b00eSchristos return NULL; 12367d62b00eSchristos 12377d62b00eSchristos if (ctf_pread (fd, data, size, 0) < 0) 12387d62b00eSchristos { 12397d62b00eSchristos free (data); 12407d62b00eSchristos return NULL; 12417d62b00eSchristos } 12427d62b00eSchristos return data; 12437d62b00eSchristos } 12447d62b00eSchristos 12457d62b00eSchristos /* Persist the header to disk. */ 12467d62b00eSchristos static int arc_mmap_writeout (int fd, void *header, size_t headersz, 12477d62b00eSchristos const char **errmsg) 12487d62b00eSchristos { 12497d62b00eSchristos ssize_t len; 12507d62b00eSchristos size_t acc = 0; 12517d62b00eSchristos char *data = (char *) header; 12527d62b00eSchristos ssize_t count = headersz; 12537d62b00eSchristos 12547d62b00eSchristos if ((lseek (fd, 0, SEEK_SET)) < 0) 12557d62b00eSchristos { 12567d62b00eSchristos if (errmsg) 12577d62b00eSchristos *errmsg = N_("arc_mmap_writeout(): cannot seek while writing header to " 12587d62b00eSchristos "%s: %s"); 12597d62b00eSchristos return -1; 12607d62b00eSchristos } 12617d62b00eSchristos 12627d62b00eSchristos while (headersz > 0) 12637d62b00eSchristos { 12647d62b00eSchristos if ((len = write (fd, data, count)) < 0) 12657d62b00eSchristos { 12667d62b00eSchristos if (errmsg) 12677d62b00eSchristos *errmsg = N_("arc_mmap_writeout(): cannot write header to %s: %s"); 12687d62b00eSchristos return len; 12697d62b00eSchristos } 12707d62b00eSchristos if (len == EINTR) 12717d62b00eSchristos continue; 12727d62b00eSchristos 12737d62b00eSchristos acc += len; 12747d62b00eSchristos if (len == 0) /* EOF. */ 12757d62b00eSchristos break; 12767d62b00eSchristos 12777d62b00eSchristos count -= len; 12787d62b00eSchristos data += len; 12797d62b00eSchristos } 12807d62b00eSchristos return 0; 12817d62b00eSchristos } 12827d62b00eSchristos 12837d62b00eSchristos /* Unmap the region. */ 12847d62b00eSchristos static int arc_mmap_unmap (void *header, size_t headersz _libctf_unused_, 12857d62b00eSchristos const char **errmsg _libctf_unused_) 12867d62b00eSchristos { 12877d62b00eSchristos free (header); 12887d62b00eSchristos return 0; 12897d62b00eSchristos } 12907d62b00eSchristos #endif 1291