17d62b00eSchristos /* Opening CTF files with BFD. 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 <stddef.h> 227d62b00eSchristos #include <assert.h> 237d62b00eSchristos #include <sys/types.h> 247d62b00eSchristos #include <sys/stat.h> 257d62b00eSchristos #include <errno.h> 267d62b00eSchristos #include <string.h> 277d62b00eSchristos #include <fcntl.h> 287d62b00eSchristos #include <unistd.h> 297d62b00eSchristos #include <elf.h> 307d62b00eSchristos #include <bfd.h> 317d62b00eSchristos #include "swap.h" 327d62b00eSchristos #include "ctf-endian.h" 337d62b00eSchristos 347d62b00eSchristos #include "elf-bfd.h" 357d62b00eSchristos 367d62b00eSchristos /* Free the BFD bits of a CTF file on ctf_arc_close(). */ 377d62b00eSchristos 387d62b00eSchristos static void 397d62b00eSchristos ctf_bfdclose (struct ctf_archive_internal *arci) 407d62b00eSchristos { 417d62b00eSchristos if (arci->ctfi_abfd != NULL) 427d62b00eSchristos if (!bfd_close_all_done (arci->ctfi_abfd)) 437d62b00eSchristos ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"), 447d62b00eSchristos bfd_errmsg (bfd_get_error ())); 457d62b00eSchristos } 467d62b00eSchristos 477d62b00eSchristos /* Open a CTF file given the specified BFD. */ 487d62b00eSchristos 497d62b00eSchristos ctf_archive_t * 507d62b00eSchristos ctf_bfdopen (struct bfd *abfd, int *errp) 517d62b00eSchristos { 527d62b00eSchristos ctf_archive_t *arc; 537d62b00eSchristos asection *ctf_asect; 547d62b00eSchristos bfd_byte *contents; 557d62b00eSchristos ctf_sect_t ctfsect; 567d62b00eSchristos 577d62b00eSchristos libctf_init_debug(); 587d62b00eSchristos 597d62b00eSchristos if ((ctf_asect = bfd_get_section_by_name (abfd, _CTF_SECTION)) == NULL) 607d62b00eSchristos { 617d62b00eSchristos return (ctf_set_open_errno (errp, ECTF_NOCTFDATA)); 627d62b00eSchristos } 637d62b00eSchristos 647d62b00eSchristos if (!bfd_malloc_and_get_section (abfd, ctf_asect, &contents)) 657d62b00eSchristos { 667d62b00eSchristos ctf_err_warn (NULL, 0, 0, _("ctf_bfdopen(): cannot malloc " 677d62b00eSchristos "CTF section: %s"), 687d62b00eSchristos bfd_errmsg (bfd_get_error ())); 697d62b00eSchristos return (ctf_set_open_errno (errp, ECTF_FMT)); 707d62b00eSchristos } 717d62b00eSchristos 727d62b00eSchristos ctfsect.cts_name = _CTF_SECTION; 737d62b00eSchristos ctfsect.cts_entsize = 1; 747d62b00eSchristos ctfsect.cts_size = bfd_section_size (ctf_asect); 757d62b00eSchristos ctfsect.cts_data = contents; 767d62b00eSchristos 777d62b00eSchristos if ((arc = ctf_bfdopen_ctfsect (abfd, &ctfsect, errp)) != NULL) 787d62b00eSchristos { 797d62b00eSchristos /* This frees the cts_data later. */ 807d62b00eSchristos arc->ctfi_data = (void *) ctfsect.cts_data; 817d62b00eSchristos return arc; 827d62b00eSchristos } 837d62b00eSchristos 847d62b00eSchristos free (contents); 857d62b00eSchristos return NULL; /* errno is set for us. */ 867d62b00eSchristos } 877d62b00eSchristos 887d62b00eSchristos /* Open a CTF file given the specified BFD and CTF section (which may contain a 897d62b00eSchristos CTF archive or a file). */ 907d62b00eSchristos 917d62b00eSchristos ctf_archive_t * 927d62b00eSchristos ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_, 937d62b00eSchristos const ctf_sect_t *ctfsect, int *errp) 947d62b00eSchristos { 957d62b00eSchristos ctf_archive_t *arci; 967d62b00eSchristos ctf_sect_t *symsectp = NULL; 977d62b00eSchristos ctf_sect_t *strsectp = NULL; 987d62b00eSchristos const char *bfderrstr = NULL; 997d62b00eSchristos char *strtab_alloc = NULL; 100*6881a400Schristos int symsect_endianness = -1; 101*6881a400Schristos 102*6881a400Schristos libctf_init_debug(); 1037d62b00eSchristos 1047d62b00eSchristos #ifdef HAVE_BFD_ELF 1057d62b00eSchristos ctf_sect_t symsect, strsect; 106*6881a400Schristos Elf_Internal_Shdr *symhdr; 1077d62b00eSchristos size_t symcount; 1087d62b00eSchristos Elf_Internal_Sym *isymbuf; 1097d62b00eSchristos bfd_byte *symtab = NULL; 110*6881a400Schristos const char *symtab_name; 1117d62b00eSchristos const char *strtab = NULL; 112*6881a400Schristos const char *strtab_name; 1137d62b00eSchristos size_t strsize; 114*6881a400Schristos const ctf_preamble_t *preamble; 115*6881a400Schristos 116*6881a400Schristos if (ctfsect->cts_data == NULL) 117*6881a400Schristos { 118*6881a400Schristos bfderrstr = N_("CTF section is NULL"); 119*6881a400Schristos goto err; 120*6881a400Schristos } 121*6881a400Schristos preamble = ctf_arc_bufpreamble (ctfsect); 122*6881a400Schristos 123*6881a400Schristos if (preamble->ctp_flags & CTF_F_DYNSTR) 124*6881a400Schristos { 125*6881a400Schristos symhdr = &elf_tdata (abfd)->dynsymtab_hdr; 126*6881a400Schristos strtab_name = ".dynstr"; 127*6881a400Schristos symtab_name = ".dynsym"; 128*6881a400Schristos } 129*6881a400Schristos else 130*6881a400Schristos { 131*6881a400Schristos symhdr = &elf_tdata (abfd)->symtab_hdr; 132*6881a400Schristos strtab_name = ".strtab"; 133*6881a400Schristos symtab_name = ".symtab"; 134*6881a400Schristos } 135*6881a400Schristos 1367d62b00eSchristos /* TODO: handle SYMTAB_SHNDX. */ 1377d62b00eSchristos 1387d62b00eSchristos /* Get the symtab, and the strtab associated with it. */ 1397d62b00eSchristos if (elf_tdata (abfd) && symhdr && symhdr->sh_size && symhdr->sh_entsize) 1407d62b00eSchristos { 1417d62b00eSchristos symcount = symhdr->sh_size / symhdr->sh_entsize; 1427d62b00eSchristos if ((symtab = malloc (symhdr->sh_size)) == NULL) 1437d62b00eSchristos { 1447d62b00eSchristos bfderrstr = N_("cannot malloc symbol table"); 1457d62b00eSchristos goto err; 1467d62b00eSchristos } 1477d62b00eSchristos 1487d62b00eSchristos isymbuf = bfd_elf_get_elf_syms (abfd, symhdr, symcount, 0, 1497d62b00eSchristos NULL, symtab, NULL); 1507d62b00eSchristos free (isymbuf); 1517d62b00eSchristos if (isymbuf == NULL) 1527d62b00eSchristos { 1537d62b00eSchristos bfderrstr = N_("cannot read symbol table"); 1547d62b00eSchristos goto err_free_sym; 1557d62b00eSchristos } 1567d62b00eSchristos 1577d62b00eSchristos if (elf_elfsections (abfd) != NULL 1587d62b00eSchristos && symhdr->sh_link < elf_numsections (abfd)) 1597d62b00eSchristos { 1607d62b00eSchristos Elf_Internal_Shdr *strhdr = elf_elfsections (abfd)[symhdr->sh_link]; 1617d62b00eSchristos 1627d62b00eSchristos strsize = strhdr->sh_size; 1637d62b00eSchristos if (strhdr->contents == NULL) 1647d62b00eSchristos { 1657d62b00eSchristos if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL) 1667d62b00eSchristos { 1677d62b00eSchristos bfderrstr = N_("cannot read string table"); 1687d62b00eSchristos goto err_free_sym; 1697d62b00eSchristos } 1707d62b00eSchristos } 1717d62b00eSchristos else 1727d62b00eSchristos strtab = (const char *) strhdr->contents; 1737d62b00eSchristos } 1747d62b00eSchristos } 175*6881a400Schristos else /* No symtab: just try getting .strtab or .dynstr by name. */ 1767d62b00eSchristos { 1777d62b00eSchristos bfd_byte *str_bcontents; 1787d62b00eSchristos asection *str_asect; 1797d62b00eSchristos 180*6881a400Schristos if ((str_asect = bfd_get_section_by_name (abfd, strtab_name)) != NULL) 1817d62b00eSchristos { 1827d62b00eSchristos if (bfd_malloc_and_get_section (abfd, str_asect, &str_bcontents)) 1837d62b00eSchristos { 1847d62b00eSchristos strtab = (const char *) str_bcontents; 1857d62b00eSchristos strtab_alloc = (char *) str_bcontents; 1867d62b00eSchristos strsize = str_asect->size; 1877d62b00eSchristos } 1887d62b00eSchristos } 1897d62b00eSchristos } 1907d62b00eSchristos 1917d62b00eSchristos if (strtab) 1927d62b00eSchristos { 1937d62b00eSchristos /* The names here are more or less arbitrary, but there is no point 1947d62b00eSchristos thrashing around digging the name out of the shstrtab given that we don't 1957d62b00eSchristos use it for anything but debugging. */ 1967d62b00eSchristos 1977d62b00eSchristos strsect.cts_data = strtab; 198*6881a400Schristos strsect.cts_name = strtab_name; 1997d62b00eSchristos strsect.cts_size = strsize; 2007d62b00eSchristos strsectp = &strsect; 2017d62b00eSchristos } 2027d62b00eSchristos 2037d62b00eSchristos if (symtab) 2047d62b00eSchristos { 2057d62b00eSchristos assert (symhdr->sh_entsize == get_elf_backend_data (abfd)->s->sizeof_sym); 206*6881a400Schristos symsect.cts_name = symtab_name; 2077d62b00eSchristos symsect.cts_entsize = symhdr->sh_entsize; 2087d62b00eSchristos symsect.cts_size = symhdr->sh_size; 2097d62b00eSchristos symsect.cts_data = symtab; 2107d62b00eSchristos symsectp = &symsect; 2117d62b00eSchristos } 212*6881a400Schristos 213*6881a400Schristos symsect_endianness = bfd_little_endian (abfd); 2147d62b00eSchristos #endif 2157d62b00eSchristos 2167d62b00eSchristos arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp); 2177d62b00eSchristos if (arci) 2187d62b00eSchristos { 2197d62b00eSchristos /* Request freeing of the symsect and possibly the strsect. */ 2207d62b00eSchristos arci->ctfi_free_symsect = 1; 2217d62b00eSchristos if (strtab_alloc) 2227d62b00eSchristos arci->ctfi_free_strsect = 1; 223*6881a400Schristos 224*6881a400Schristos /* Get the endianness right. */ 225*6881a400Schristos if (symsect_endianness > -1) 226*6881a400Schristos ctf_arc_symsect_endianness (arci, symsect_endianness); 2277d62b00eSchristos return arci; 2287d62b00eSchristos } 2297d62b00eSchristos #ifdef HAVE_BFD_ELF 2307d62b00eSchristos err_free_sym: 2317d62b00eSchristos free (symtab); 2327d62b00eSchristos free (strtab_alloc); 2337d62b00eSchristos #endif 2347d62b00eSchristos err: _libctf_unused_; 2357d62b00eSchristos if (bfderrstr) 2367d62b00eSchristos { 2377d62b00eSchristos ctf_err_warn (NULL, 0, 0, "ctf_bfdopen(): %s: %s", gettext (bfderrstr), 2387d62b00eSchristos bfd_errmsg (bfd_get_error())); 2397d62b00eSchristos ctf_set_open_errno (errp, ECTF_FMT); 2407d62b00eSchristos } 2417d62b00eSchristos return NULL; 2427d62b00eSchristos } 2437d62b00eSchristos 2447d62b00eSchristos /* Open the specified file descriptor and return a pointer to a CTF archive that 245*6881a400Schristos contains one or more CTF dicts. The file can be an ELF file, a file 246*6881a400Schristos containing raw CTF, or a CTF archive. The caller is responsible for closing 247*6881a400Schristos the file descriptor when it is no longer needed. If this is an ELF file, 248*6881a400Schristos TARGET, if non-NULL, should be the name of a suitable BFD target. */ 2497d62b00eSchristos 2507d62b00eSchristos ctf_archive_t * 2517d62b00eSchristos ctf_fdopen (int fd, const char *filename, const char *target, int *errp) 2527d62b00eSchristos { 2537d62b00eSchristos ctf_archive_t *arci; 2547d62b00eSchristos bfd *abfd; 2557d62b00eSchristos int nfd; 2567d62b00eSchristos 2577d62b00eSchristos struct stat st; 2587d62b00eSchristos ssize_t nbytes; 2597d62b00eSchristos 2607d62b00eSchristos ctf_preamble_t ctfhdr; 2617d62b00eSchristos uint64_t arc_magic; 2627d62b00eSchristos 2637d62b00eSchristos memset (&ctfhdr, 0, sizeof (ctfhdr)); 2647d62b00eSchristos 2657d62b00eSchristos libctf_init_debug(); 2667d62b00eSchristos 2677d62b00eSchristos if (fstat (fd, &st) == -1) 2687d62b00eSchristos return (ctf_set_open_errno (errp, errno)); 2697d62b00eSchristos 2707d62b00eSchristos if ((nbytes = ctf_pread (fd, &ctfhdr, sizeof (ctfhdr), 0)) <= 0) 2717d62b00eSchristos return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT)); 2727d62b00eSchristos 2737d62b00eSchristos /* If we have read enough bytes to form a CTF header and the magic string 2747d62b00eSchristos matches, in either endianness, attempt to interpret the file as raw 2757d62b00eSchristos CTF. */ 2767d62b00eSchristos 2777d62b00eSchristos if ((size_t) nbytes >= sizeof (ctf_preamble_t) 2787d62b00eSchristos && (ctfhdr.ctp_magic == CTF_MAGIC 2797d62b00eSchristos || ctfhdr.ctp_magic == bswap_16 (CTF_MAGIC))) 2807d62b00eSchristos { 281*6881a400Schristos ctf_dict_t *fp = NULL; 2827d62b00eSchristos void *data; 2837d62b00eSchristos 2847d62b00eSchristos if ((data = ctf_mmap (st.st_size, 0, fd)) == NULL) 2857d62b00eSchristos return (ctf_set_open_errno (errp, errno)); 2867d62b00eSchristos 2877d62b00eSchristos if ((fp = ctf_simple_open (data, (size_t) st.st_size, NULL, 0, 0, 2887d62b00eSchristos NULL, 0, errp)) == NULL) 2897d62b00eSchristos { 2907d62b00eSchristos ctf_munmap (data, (size_t) st.st_size); 2917d62b00eSchristos return NULL; /* errno is set for us. */ 2927d62b00eSchristos } 2937d62b00eSchristos 2947d62b00eSchristos fp->ctf_data_mmapped = data; 2957d62b00eSchristos fp->ctf_data_mmapped_len = (size_t) st.st_size; 2967d62b00eSchristos 2977d62b00eSchristos return ctf_new_archive_internal (0, 1, NULL, fp, NULL, NULL, errp); 2987d62b00eSchristos } 2997d62b00eSchristos 3007d62b00eSchristos if ((nbytes = ctf_pread (fd, &arc_magic, sizeof (arc_magic), 0)) <= 0) 3017d62b00eSchristos return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT)); 3027d62b00eSchristos 3037d62b00eSchristos if ((size_t) nbytes >= sizeof (uint64_t) && le64toh (arc_magic) == CTFA_MAGIC) 3047d62b00eSchristos { 3057d62b00eSchristos struct ctf_archive *arc; 3067d62b00eSchristos 3077d62b00eSchristos if ((arc = ctf_arc_open_internal (filename, errp)) == NULL) 3087d62b00eSchristos return NULL; /* errno is set for us. */ 3097d62b00eSchristos 3107d62b00eSchristos return ctf_new_archive_internal (1, 1, arc, NULL, NULL, NULL, errp); 3117d62b00eSchristos } 3127d62b00eSchristos 3137d62b00eSchristos /* Attempt to open the file with BFD. We must dup the fd first, since bfd 3147d62b00eSchristos takes ownership of the passed fd. */ 3157d62b00eSchristos 3167d62b00eSchristos if ((nfd = dup (fd)) < 0) 3177d62b00eSchristos return (ctf_set_open_errno (errp, errno)); 3187d62b00eSchristos 3197d62b00eSchristos if ((abfd = bfd_fdopenr (filename, target, nfd)) == NULL) 3207d62b00eSchristos { 3217d62b00eSchristos ctf_err_warn (NULL, 0, 0, _("cannot open BFD from %s: %s"), 3227d62b00eSchristos filename ? filename : _("(unknown file)"), 3237d62b00eSchristos bfd_errmsg (bfd_get_error ())); 3247d62b00eSchristos return (ctf_set_open_errno (errp, ECTF_FMT)); 3257d62b00eSchristos } 3267d62b00eSchristos bfd_set_cacheable (abfd, 1); 3277d62b00eSchristos 3287d62b00eSchristos if (!bfd_check_format (abfd, bfd_object)) 3297d62b00eSchristos { 3307d62b00eSchristos ctf_err_warn (NULL, 0, 0, _("BFD format problem in %s: %s"), 3317d62b00eSchristos filename ? filename : _("(unknown file)"), 3327d62b00eSchristos bfd_errmsg (bfd_get_error ())); 3337d62b00eSchristos if (bfd_get_error() == bfd_error_file_ambiguously_recognized) 3347d62b00eSchristos return (ctf_set_open_errno (errp, ECTF_BFD_AMBIGUOUS)); 3357d62b00eSchristos else 3367d62b00eSchristos return (ctf_set_open_errno (errp, ECTF_FMT)); 3377d62b00eSchristos } 3387d62b00eSchristos 3397d62b00eSchristos if ((arci = ctf_bfdopen (abfd, errp)) == NULL) 3407d62b00eSchristos { 3417d62b00eSchristos if (!bfd_close_all_done (abfd)) 3427d62b00eSchristos ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"), 3437d62b00eSchristos bfd_errmsg (bfd_get_error ())); 3447d62b00eSchristos return NULL; /* errno is set for us. */ 3457d62b00eSchristos } 3467d62b00eSchristos arci->ctfi_bfd_close = ctf_bfdclose; 3477d62b00eSchristos arci->ctfi_abfd = abfd; 3487d62b00eSchristos 3497d62b00eSchristos return arci; 3507d62b00eSchristos } 3517d62b00eSchristos 352*6881a400Schristos /* Open the specified file and return a pointer to a CTF dict. The file 3537d62b00eSchristos can be either an ELF file or raw CTF file. This is just a convenient 3547d62b00eSchristos wrapper around ctf_fdopen() for callers. */ 3557d62b00eSchristos 3567d62b00eSchristos ctf_archive_t * 3577d62b00eSchristos ctf_open (const char *filename, const char *target, int *errp) 3587d62b00eSchristos { 3597d62b00eSchristos ctf_archive_t *arc; 3607d62b00eSchristos int fd; 3617d62b00eSchristos 3627d62b00eSchristos if ((fd = open (filename, O_RDONLY)) == -1) 3637d62b00eSchristos { 3647d62b00eSchristos if (errp != NULL) 3657d62b00eSchristos *errp = errno; 3667d62b00eSchristos return NULL; 3677d62b00eSchristos } 3687d62b00eSchristos 3697d62b00eSchristos arc = ctf_fdopen (fd, filename, target, errp); 3707d62b00eSchristos (void) close (fd); 3717d62b00eSchristos return arc; 3727d62b00eSchristos } 3737d62b00eSchristos 3747d62b00eSchristos /* Public entry point: open a CTF archive, or CTF file. Returns the archive, or 3757d62b00eSchristos NULL and an error in *err. Despite the fact that this uses CTF archives, it 3767d62b00eSchristos must be in this file to avoid dragging in BFD into non-BFD-using programs. */ 3777d62b00eSchristos ctf_archive_t * 3787d62b00eSchristos ctf_arc_open (const char *filename, int *errp) 3797d62b00eSchristos { 3807d62b00eSchristos return ctf_open (filename, NULL, errp); 3817d62b00eSchristos } 382