xref: /netbsd-src/external/gpl3/gdb.old/dist/libctf/ctf-open-bfd.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
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