Home | History | Annotate | Line # | Download | only in libctf
ctf-open-bfd.c revision 1.1
      1  1.1  christos /* Opening CTF files with BFD.
      2  1.1  christos    Copyright (C) 2019-2020 Free Software Foundation, Inc.
      3  1.1  christos 
      4  1.1  christos    This file is part of libctf.
      5  1.1  christos 
      6  1.1  christos    libctf is free software; you can redistribute it and/or modify it under
      7  1.1  christos    the terms of the GNU General Public License as published by the Free
      8  1.1  christos    Software Foundation; either version 3, or (at your option) any later
      9  1.1  christos    version.
     10  1.1  christos 
     11  1.1  christos    This program is distributed in the hope that it will be useful, but
     12  1.1  christos    WITHOUT ANY WARRANTY; without even the implied warranty of
     13  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14  1.1  christos    See the GNU General Public License for more details.
     15  1.1  christos 
     16  1.1  christos    You should have received a copy of the GNU General Public License
     17  1.1  christos    along with this program; see the file COPYING.  If not see
     18  1.1  christos    <http://www.gnu.org/licenses/>.  */
     19  1.1  christos 
     20  1.1  christos #include <ctf-impl.h>
     21  1.1  christos #include <stddef.h>
     22  1.1  christos #include <assert.h>
     23  1.1  christos #include <sys/types.h>
     24  1.1  christos #include <sys/stat.h>
     25  1.1  christos #include <errno.h>
     26  1.1  christos #include <string.h>
     27  1.1  christos #include <fcntl.h>
     28  1.1  christos #include <elf.h>
     29  1.1  christos #include <bfd.h>
     30  1.1  christos #include "swap.h"
     31  1.1  christos #include "ctf-endian.h"
     32  1.1  christos 
     33  1.1  christos #include "elf-bfd.h"
     34  1.1  christos 
     35  1.1  christos /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
     36  1.1  christos    ctf_file.  Closes ARC and/or FP on error.  Arrange to free the SYMSECT or
     37  1.1  christos    STRSECT, as needed, on close (though the STRSECT interior is bound to the bfd
     38  1.1  christos    * and is not actually freed by this machinery).  */
     39  1.1  christos 
     40  1.1  christos static struct ctf_archive_internal *
     41  1.1  christos ctf_new_archive_internal (int is_archive, struct ctf_archive *arc,
     42  1.1  christos 			  ctf_file_t *fp, const ctf_sect_t *symsect,
     43  1.1  christos 			  const ctf_sect_t *strsect,
     44  1.1  christos 			  int *errp)
     45  1.1  christos {
     46  1.1  christos   struct ctf_archive_internal *arci;
     47  1.1  christos 
     48  1.1  christos   if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
     49  1.1  christos     {
     50  1.1  christos       if (is_archive)
     51  1.1  christos 	ctf_arc_close_internal (arc);
     52  1.1  christos       else
     53  1.1  christos 	ctf_file_close (fp);
     54  1.1  christos       return (ctf_set_open_errno (errp, errno));
     55  1.1  christos     }
     56  1.1  christos   arci->ctfi_is_archive = is_archive;
     57  1.1  christos   if (is_archive)
     58  1.1  christos     arci->ctfi_archive = arc;
     59  1.1  christos   else
     60  1.1  christos     arci->ctfi_file = fp;
     61  1.1  christos   if (symsect)
     62  1.1  christos      memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect));
     63  1.1  christos   if (strsect)
     64  1.1  christos      memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
     65  1.1  christos 
     66  1.1  christos   return arci;
     67  1.1  christos }
     68  1.1  christos 
     69  1.1  christos /* Free the BFD bits of a CTF file on ctf_arc_close().  */
     70  1.1  christos 
     71  1.1  christos static void
     72  1.1  christos ctf_bfdclose (struct ctf_archive_internal *arci)
     73  1.1  christos {
     74  1.1  christos   if (arci->ctfi_abfd != NULL)
     75  1.1  christos     if (!bfd_close_all_done (arci->ctfi_abfd))
     76  1.1  christos       ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error()));
     77  1.1  christos }
     78  1.1  christos 
     79  1.1  christos /* Open a CTF file given the specified BFD.  */
     80  1.1  christos 
     81  1.1  christos ctf_archive_t *
     82  1.1  christos ctf_bfdopen (struct bfd *abfd, int *errp)
     83  1.1  christos {
     84  1.1  christos   ctf_archive_t *arc;
     85  1.1  christos   asection *ctf_asect;
     86  1.1  christos   bfd_byte *contents;
     87  1.1  christos   ctf_sect_t ctfsect;
     88  1.1  christos 
     89  1.1  christos   libctf_init_debug();
     90  1.1  christos 
     91  1.1  christos   if ((ctf_asect = bfd_get_section_by_name (abfd, _CTF_SECTION)) == NULL)
     92  1.1  christos     {
     93  1.1  christos       return (ctf_set_open_errno (errp, ECTF_NOCTFDATA));
     94  1.1  christos     }
     95  1.1  christos 
     96  1.1  christos   if (!bfd_malloc_and_get_section (abfd, ctf_asect, &contents))
     97  1.1  christos     {
     98  1.1  christos       ctf_dprintf ("ctf_bfdopen(): cannot malloc CTF section: %s\n",
     99  1.1  christos 		   bfd_errmsg (bfd_get_error()));
    100  1.1  christos       return (ctf_set_open_errno (errp, ECTF_FMT));
    101  1.1  christos     }
    102  1.1  christos 
    103  1.1  christos   ctfsect.cts_name = _CTF_SECTION;
    104  1.1  christos   ctfsect.cts_entsize = 1;
    105  1.1  christos   ctfsect.cts_size = bfd_section_size (ctf_asect);
    106  1.1  christos   ctfsect.cts_data = contents;
    107  1.1  christos 
    108  1.1  christos   if ((arc = ctf_bfdopen_ctfsect (abfd, &ctfsect, errp)) != NULL)
    109  1.1  christos     {
    110  1.1  christos       arc->ctfi_data = (void *) ctfsect.cts_data;
    111  1.1  christos       return arc;
    112  1.1  christos     }
    113  1.1  christos 
    114  1.1  christos   free (contents);
    115  1.1  christos   return NULL;				/* errno is set for us.  */
    116  1.1  christos }
    117  1.1  christos 
    118  1.1  christos /* Open a CTF file given the specified BFD and CTF section (which may contain a
    119  1.1  christos    CTF archive or a file).  Takes ownership of the ctfsect, and frees it
    120  1.1  christos    later.  */
    121  1.1  christos 
    122  1.1  christos ctf_archive_t *
    123  1.1  christos ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
    124  1.1  christos 		     const ctf_sect_t *ctfsect, int *errp)
    125  1.1  christos {
    126  1.1  christos   struct ctf_archive *arc = NULL;
    127  1.1  christos   ctf_archive_t *arci;
    128  1.1  christos   ctf_file_t *fp = NULL;
    129  1.1  christos   ctf_sect_t *symsectp = NULL;
    130  1.1  christos   ctf_sect_t *strsectp = NULL;
    131  1.1  christos   const char *bfderrstr = NULL;
    132  1.1  christos   int is_archive;
    133  1.1  christos 
    134  1.1  christos #ifdef HAVE_BFD_ELF
    135  1.1  christos   ctf_sect_t symsect, strsect;
    136  1.1  christos   Elf_Internal_Shdr *strhdr;
    137  1.1  christos   Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd);
    138  1.1  christos   size_t symcount = symhdr->sh_size / symhdr->sh_entsize;
    139  1.1  christos   Elf_Internal_Sym *isymbuf;
    140  1.1  christos   bfd_byte *symtab;
    141  1.1  christos   const char *strtab = NULL;
    142  1.1  christos   /* TODO: handle SYMTAB_SHNDX.  */
    143  1.1  christos 
    144  1.1  christos   if ((symtab = malloc (symhdr->sh_size)) == NULL)
    145  1.1  christos     {
    146  1.1  christos       bfderrstr = "Cannot malloc symbol table";
    147  1.1  christos       goto err;
    148  1.1  christos     }
    149  1.1  christos 
    150  1.1  christos   isymbuf = bfd_elf_get_elf_syms (abfd, symhdr, symcount, 0,
    151  1.1  christos 				  NULL, symtab, NULL);
    152  1.1  christos   free (isymbuf);
    153  1.1  christos   if (isymbuf == NULL)
    154  1.1  christos     {
    155  1.1  christos       bfderrstr = "Cannot read symbol table";
    156  1.1  christos       goto err_free_sym;
    157  1.1  christos     }
    158  1.1  christos 
    159  1.1  christos   if (elf_elfsections (abfd) != NULL
    160  1.1  christos       && symhdr->sh_link < elf_numsections (abfd))
    161  1.1  christos     {
    162  1.1  christos       strhdr = elf_elfsections (abfd)[symhdr->sh_link];
    163  1.1  christos       if (strhdr->contents == NULL)
    164  1.1  christos 	{
    165  1.1  christos 	  if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL)
    166  1.1  christos 	    {
    167  1.1  christos 	      bfderrstr = "Cannot read string table";
    168  1.1  christos 	      goto err_free_sym;
    169  1.1  christos 	    }
    170  1.1  christos 	}
    171  1.1  christos       else
    172  1.1  christos 	strtab = (const char *) strhdr->contents;
    173  1.1  christos     }
    174  1.1  christos 
    175  1.1  christos   if (strtab)
    176  1.1  christos     {
    177  1.1  christos       /* The names here are more or less arbitrary, but there is no point
    178  1.1  christos 	 thrashing around digging the name out of the shstrtab given that we don't
    179  1.1  christos 	 use it for anything but debugging.  */
    180  1.1  christos 
    181  1.1  christos       strsect.cts_data = strtab;
    182  1.1  christos       strsect.cts_name = ".strtab";
    183  1.1  christos       strsect.cts_size = strhdr->sh_size;
    184  1.1  christos       strsectp = &strsect;
    185  1.1  christos 
    186  1.1  christos       assert (symhdr->sh_entsize == get_elf_backend_data (abfd)->s->sizeof_sym);
    187  1.1  christos       symsect.cts_name = ".symtab";
    188  1.1  christos       symsect.cts_entsize = symhdr->sh_entsize;
    189  1.1  christos       symsect.cts_size = symhdr->sh_size;
    190  1.1  christos       symsect.cts_data = symtab;
    191  1.1  christos       symsectp = &symsect;
    192  1.1  christos     }
    193  1.1  christos #endif
    194  1.1  christos 
    195  1.1  christos   if (ctfsect->cts_size > sizeof (uint64_t) &&
    196  1.1  christos       ((*(uint64_t *) ctfsect->cts_data) == CTFA_MAGIC))
    197  1.1  christos     {
    198  1.1  christos       is_archive = 1;
    199  1.1  christos       if ((arc = ctf_arc_bufopen ((void *) ctfsect->cts_data,
    200  1.1  christos 				  ctfsect->cts_size, errp)) == NULL)
    201  1.1  christos 	goto err_free_str;
    202  1.1  christos     }
    203  1.1  christos   else
    204  1.1  christos     {
    205  1.1  christos       is_archive = 0;
    206  1.1  christos       if ((fp = ctf_bufopen (ctfsect, symsectp, strsectp, errp)) == NULL)
    207  1.1  christos 	{
    208  1.1  christos 	  ctf_dprintf ("ctf_internal_open(): cannot open CTF: %s\n",
    209  1.1  christos 		       ctf_errmsg (*errp));
    210  1.1  christos 	  goto err_free_str;
    211  1.1  christos 	}
    212  1.1  christos     }
    213  1.1  christos   arci = ctf_new_archive_internal (is_archive, arc, fp, symsectp, strsectp,
    214  1.1  christos 				   errp);
    215  1.1  christos 
    216  1.1  christos   if (arci)
    217  1.1  christos     return arci;
    218  1.1  christos  err_free_str: ;
    219  1.1  christos #ifdef HAVE_BFD_ELF
    220  1.1  christos  err_free_sym:
    221  1.1  christos   free (symtab);
    222  1.1  christos #endif
    223  1.1  christos err: _libctf_unused_;
    224  1.1  christos   if (bfderrstr)
    225  1.1  christos     {
    226  1.1  christos       ctf_dprintf ("ctf_bfdopen(): %s: %s\n", bfderrstr,
    227  1.1  christos 		   bfd_errmsg (bfd_get_error()));
    228  1.1  christos       ctf_set_open_errno (errp, ECTF_FMT);
    229  1.1  christos     }
    230  1.1  christos   return NULL;
    231  1.1  christos }
    232  1.1  christos 
    233  1.1  christos /* Open the specified file descriptor and return a pointer to a CTF archive that
    234  1.1  christos    contains one or more CTF containers.  The file can be an ELF file, a raw CTF
    235  1.1  christos    file, or a CTF archive.  The caller is responsible for closing the file
    236  1.1  christos    descriptor when it is no longer needed.  If this is an ELF file, TARGET, if
    237  1.1  christos    non-NULL, should be the name of a suitable BFD target.  */
    238  1.1  christos 
    239  1.1  christos ctf_archive_t *
    240  1.1  christos ctf_fdopen (int fd, const char *filename, const char *target, int *errp)
    241  1.1  christos {
    242  1.1  christos   ctf_archive_t *arci;
    243  1.1  christos   bfd *abfd;
    244  1.1  christos   int nfd;
    245  1.1  christos 
    246  1.1  christos   struct stat st;
    247  1.1  christos   ssize_t nbytes;
    248  1.1  christos 
    249  1.1  christos   ctf_preamble_t ctfhdr;
    250  1.1  christos   uint64_t arc_magic;
    251  1.1  christos 
    252  1.1  christos   memset (&ctfhdr, 0, sizeof (ctfhdr));
    253  1.1  christos 
    254  1.1  christos   libctf_init_debug();
    255  1.1  christos 
    256  1.1  christos   if (fstat (fd, &st) == -1)
    257  1.1  christos     return (ctf_set_open_errno (errp, errno));
    258  1.1  christos 
    259  1.1  christos   if ((nbytes = ctf_pread (fd, &ctfhdr, sizeof (ctfhdr), 0)) <= 0)
    260  1.1  christos     return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT));
    261  1.1  christos 
    262  1.1  christos   /* If we have read enough bytes to form a CTF header and the magic string
    263  1.1  christos      matches, in either endianness, attempt to interpret the file as raw
    264  1.1  christos      CTF.  */
    265  1.1  christos 
    266  1.1  christos   if ((size_t) nbytes >= sizeof (ctf_preamble_t)
    267  1.1  christos       && (ctfhdr.ctp_magic == CTF_MAGIC
    268  1.1  christos 	  || ctfhdr.ctp_magic == bswap_16 (CTF_MAGIC)))
    269  1.1  christos     {
    270  1.1  christos       ctf_file_t *fp = NULL;
    271  1.1  christos       void *data;
    272  1.1  christos 
    273  1.1  christos       if ((data = ctf_mmap (st.st_size, 0, fd)) == NULL)
    274  1.1  christos 	return (ctf_set_open_errno (errp, errno));
    275  1.1  christos 
    276  1.1  christos       if ((fp = ctf_simple_open (data, (size_t) st.st_size, NULL, 0, 0,
    277  1.1  christos 				 NULL, 0, errp)) == NULL)
    278  1.1  christos 	{
    279  1.1  christos 	  ctf_munmap (data, (size_t) st.st_size);
    280  1.1  christos 	  return NULL;			/* errno is set for us.  */
    281  1.1  christos 	}
    282  1.1  christos 
    283  1.1  christos       fp->ctf_data_mmapped = data;
    284  1.1  christos       fp->ctf_data_mmapped_len = (size_t) st.st_size;
    285  1.1  christos 
    286  1.1  christos       return ctf_new_archive_internal (0, NULL, fp, NULL, NULL, errp);
    287  1.1  christos     }
    288  1.1  christos 
    289  1.1  christos   if ((nbytes = ctf_pread (fd, &arc_magic, sizeof (arc_magic), 0)) <= 0)
    290  1.1  christos     return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT));
    291  1.1  christos 
    292  1.1  christos   if ((size_t) nbytes >= sizeof (uint64_t) && le64toh (arc_magic) == CTFA_MAGIC)
    293  1.1  christos     {
    294  1.1  christos       struct ctf_archive *arc;
    295  1.1  christos 
    296  1.1  christos       if ((arc = ctf_arc_open_internal (filename, errp)) == NULL)
    297  1.1  christos 	return NULL;			/* errno is set for us.  */
    298  1.1  christos 
    299  1.1  christos       return ctf_new_archive_internal (1, arc, NULL, NULL, NULL, errp);
    300  1.1  christos     }
    301  1.1  christos 
    302  1.1  christos   /* Attempt to open the file with BFD.  We must dup the fd first, since bfd
    303  1.1  christos      takes ownership of the passed fd.  */
    304  1.1  christos 
    305  1.1  christos   if ((nfd = dup (fd)) < 0)
    306  1.1  christos       return (ctf_set_open_errno (errp, errno));
    307  1.1  christos 
    308  1.1  christos   if ((abfd = bfd_fdopenr (filename, target, nfd)) == NULL)
    309  1.1  christos     {
    310  1.1  christos       ctf_dprintf ("Cannot open BFD from %s: %s\n",
    311  1.1  christos 		   filename ? filename : "(unknown file)",
    312  1.1  christos 		   bfd_errmsg (bfd_get_error()));
    313  1.1  christos       return (ctf_set_open_errno (errp, ECTF_FMT));
    314  1.1  christos     }
    315  1.1  christos   bfd_set_cacheable (abfd, 1);
    316  1.1  christos 
    317  1.1  christos   if (!bfd_check_format (abfd, bfd_object))
    318  1.1  christos     {
    319  1.1  christos       ctf_dprintf ("BFD format problem in %s: %s\n",
    320  1.1  christos 		   filename ? filename : "(unknown file)",
    321  1.1  christos 		   bfd_errmsg (bfd_get_error()));
    322  1.1  christos       if (bfd_get_error() == bfd_error_file_ambiguously_recognized)
    323  1.1  christos 	return (ctf_set_open_errno (errp, ECTF_BFD_AMBIGUOUS));
    324  1.1  christos       else
    325  1.1  christos 	return (ctf_set_open_errno (errp, ECTF_FMT));
    326  1.1  christos     }
    327  1.1  christos 
    328  1.1  christos   if ((arci = ctf_bfdopen (abfd, errp)) == NULL)
    329  1.1  christos     {
    330  1.1  christos       if (!bfd_close_all_done (abfd))
    331  1.1  christos 	ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error()));
    332  1.1  christos       return NULL;			/* errno is set for us.  */
    333  1.1  christos     }
    334  1.1  christos   arci->ctfi_bfd_close = ctf_bfdclose;
    335  1.1  christos   arci->ctfi_abfd = abfd;
    336  1.1  christos 
    337  1.1  christos   return arci;
    338  1.1  christos }
    339  1.1  christos 
    340  1.1  christos /* Open the specified file and return a pointer to a CTF container.  The file
    341  1.1  christos    can be either an ELF file or raw CTF file.  This is just a convenient
    342  1.1  christos    wrapper around ctf_fdopen() for callers.  */
    343  1.1  christos 
    344  1.1  christos ctf_archive_t *
    345  1.1  christos ctf_open (const char *filename, const char *target, int *errp)
    346  1.1  christos {
    347  1.1  christos   ctf_archive_t *arc;
    348  1.1  christos   int fd;
    349  1.1  christos 
    350  1.1  christos   if ((fd = open (filename, O_RDONLY)) == -1)
    351  1.1  christos     {
    352  1.1  christos       if (errp != NULL)
    353  1.1  christos 	*errp = errno;
    354  1.1  christos       return NULL;
    355  1.1  christos     }
    356  1.1  christos 
    357  1.1  christos   arc = ctf_fdopen (fd, filename, target, errp);
    358  1.1  christos   (void) close (fd);
    359  1.1  christos   return arc;
    360  1.1  christos }
    361  1.1  christos 
    362  1.1  christos /* Public entry point: open a CTF archive, or CTF file.  Returns the archive, or
    363  1.1  christos    NULL and an error in *err.  Despite the fact that this uses CTF archives, it
    364  1.1  christos    must be in this file to avoid dragging in BFD into non-BFD-using programs.  */
    365  1.1  christos ctf_archive_t *
    366  1.1  christos ctf_arc_open (const char *filename, int *errp)
    367  1.1  christos {
    368  1.1  christos   return ctf_open (filename, NULL, errp);
    369  1.1  christos }
    370