From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14437 invoked by alias); 17 May 2019 22:10:25 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 14381 invoked by uid 89); 17 May 2019 22:10:25 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.3 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,SPF_HELO_PASS,SPF_PASS,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 spammy= X-HELO: aserp2130.oracle.com Received: from aserp2130.oracle.com (HELO aserp2130.oracle.com) (141.146.126.79) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 17 May 2019 22:10:21 +0000 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x4HM8loL057461 for ; Fri, 17 May 2019 22:10:19 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2018-07-02; bh=dlhYkFr/xzoHd/gZpdV7j6UY0LET/Dp2zkpi5Nf//3A=; b=5alyyZdyY09Xzui4KYcBXspkkXPV5azButotq6SIAB3KqZGRDvaBHfN+795z8yzYGdad MFU1nDzuEtUO1bT5fiHSN8IiKTowXe6+yJwwgA8pRPw3vDPC6r766kqqVPVRxKsX1VRb OqShgbEc0MbZZba4VOhj6lUtu+w6oGpHILmoV1GL0rSgicOTT4utYlAK42/V8Vzu0gmL H/+GN1dD+Xv9230FlkiTQNRlt1XdI381QFNWnwUwORH3vfaamxNhtNjLZH29bByHS+JV EUffGagHfSzEf5SGmyCy0hf4JROsTNGlzxSo5hb9e3QWF/3unT8M1aQ5CaMnagLy3QOL nw== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by aserp2130.oracle.com with ESMTP id 2sdkwecfse-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 17 May 2019 22:10:19 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x4HM9iMW159985 for ; Fri, 17 May 2019 22:10:18 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userp3020.oracle.com with ESMTP id 2shh5ha70h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 17 May 2019 22:10:18 +0000 Received: from abhmp0011.oracle.com (abhmp0011.oracle.com [141.146.116.17]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id x4HMAHt1002726 for ; Fri, 17 May 2019 22:10:17 GMT Received: from loom.srvr.nix (/81.187.191.129) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 17 May 2019 15:10:17 -0700 From: Nick Alcock To: binutils@sourceware.org Subject: [PATCH v2 10/19] libctf: ELF file opening via BFD Date: Fri, 17 May 2019 22:10:00 -0000 Message-Id: <20190517221002.408822-11-nick.alcock@oracle.com> In-Reply-To: <20190517221002.408822-1-nick.alcock@oracle.com> References: <20190517221002.408822-1-nick.alcock@oracle.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-IsSubscribed: yes X-SW-Source: 2019-05/txt/msg00213.txt.bz2 These functions let you open an ELF file with a customarily-named CTF section in it, automatically opening the CTF file and associating the symbol and string tables in the ELF file with the CTF container, so that you can look up the types of symbols in the ELF file via ctf_lookup_by_symbol(), and so that strings can be shared between the ELF file and CTF container, to save space. It uses BFD machinery to do so. I have no idea if I'm using this machinery right, and it hasn't been thoroughly tested yet, but it is better than the manual thrashing that was there before. We use a forward declaration for the struct bfd in ctf-api.h, so that ctf-api.h users are not required to pull in . (This is mostly for the sake of readelf.) These functions have not been tested since their CTF rewrite: this will happen soon, once we have enough linker machinery together to build ELF files with all the necessary sections in at once. Changes from v1: - Correct erroneous license (GPLv2+ -> v3+) and reset copyright years. - Move out of ctf_lib.c; functions now based on BFD, and located in ctf-open-bfd.c. - New ctf_bfdopen() to do the low-level opening given a bfd. - New ctf_bfdopen_ctfsect() to do the low-level opening given a bfd and a separately-specified CTF section (will later be used to open archives using a bfd). libctf/ * ctf-open-bfd.c: New file. * ctf-impl.h: Include bfd.h. (ctf_file): New members ctf_abfd, ctf_data_alloced, ctf_data_mmapped, ctf_data_mmapped_len, ctf_symtab_alloced, ctf_strtab_alloced, ctf_bfd_close. (ctf_bfdopen_ctfsect): New declaration. (_CTF_SECTION): likewise. include/ * ctf-api.h (struct bfd): New forward. (ctf_fdopen): New. (ctf_bfdopen): Likewise. (ctf_open): Likewise. --- include/ctf-api.h | 8 ++ libctf/ctf-impl.h | 11 ++ libctf/ctf-open-bfd.c | 264 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 libctf/ctf-open-bfd.c diff --git a/include/ctf-api.h b/include/ctf-api.h index c5eb9c676b..4c532f2867 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -45,6 +45,11 @@ typedef struct ctf_file ctf_file_t; typedef struct ctf_archive ctf_archive_t; typedef long ctf_id_t; +/* This opaque definition allows libctf to accept BFD data structures without + importing all the BFD noise into users' namespaces. */ + +struct bfd; + /* If the debugger needs to provide the CTF library with a set of raw buffers for use as the CTF data, symbol table, and string table, it can do so by filling in ctf_sect_t structures and passing them to ctf_bufopen(). @@ -200,8 +205,11 @@ enum extern ctf_file_t *ctf_simple_open (const char *, size_t, const char *, size_t, size_t, const char *, size_t, int *); +extern ctf_file_t *ctf_bfdopen (struct bfd *, int *); extern ctf_file_t *ctf_bufopen (const ctf_sect_t *, const ctf_sect_t *, const ctf_sect_t *, int *); +extern ctf_file_t *ctf_fdopen (int, const char *, int *); +extern ctf_file_t *ctf_open (const char *, int *); extern ctf_file_t *ctf_create (int *); extern void ctf_close (ctf_file_t *); extern ctf_sect_t ctf_getdatasect (const ctf_file_t *); diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 53d062745a..3944cfeaee 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" @@ -185,9 +186,15 @@ typedef struct ctf_bundle struct ctf_file { const ctf_fileops_t *ctf_fileops; /* Version-specific file operations. */ + bfd *ctf_abfd; /* Optional source of section data. */ ctf_sect_t ctf_data; /* CTF data from object file. */ ctf_sect_t ctf_symtab; /* Symbol table from object file. */ ctf_sect_t ctf_strtab; /* String table from object file. */ + void *ctf_data_alloced; /* CTF data we allocated, to free later. */ + void *ctf_data_mmapped; /* CTF data we mmapped, to free later. */ + size_t ctf_data_mmapped_len; /* Length of CTF data we mmapped. */ + void *ctf_symtab_alloced; /* symtab data we allocated. */ + void *ctf_strtab_alloced; /* symtab data we allocated. */ ctf_hash_t *ctf_structs; /* Hash table of struct types. */ ctf_hash_t *ctf_unions; /* Hash table of union types. */ ctf_hash_t *ctf_enums; /* Hash table of enum types. */ @@ -226,6 +233,7 @@ struct ctf_file unsigned long ctf_snapshot_lu; /* ctf_snapshot() call count at last update. */ char *ctf_tmp_typeslice; /* Storage for slicing up type names. */ size_t ctf_tmp_typeslicelen; /* Size of the typeslice. */ + void (*ctf_bfd_close) (struct ctf_file *); /* Frees BFD bits on close. */ void *ctf_specific; /* Data for ctf_get/setspecific(). */ }; @@ -311,6 +319,8 @@ extern const char *ctf_strptr (ctf_file_t *, uint32_t); extern ctf_file_t *ctf_set_open_errno (int *, int); extern long ctf_set_errno (ctf_file_t *, int); +extern ctf_file_t *ctf_bfdopen_ctfsect (struct bfd *, const ctf_sect_t *, + int *); _libctf_malloc_ extern void *ctf_data_alloc (size_t); @@ -342,6 +352,7 @@ extern Elf64_Sym *ctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst); /* Variables, all underscore-prepended. */ +extern const char _CTF_SECTION[]; /* name of CTF ELF section */ extern const char _CTF_NULLSTR[]; /* empty string */ extern int _libctf_debug; /* debugging messages enabled */ diff --git a/libctf/ctf-open-bfd.c b/libctf/ctf-open-bfd.c new file mode 100644 index 0000000000..8dee8a35fa --- /dev/null +++ b/libctf/ctf-open-bfd.c @@ -0,0 +1,264 @@ +/* Opening CTF files with BFD. + Copyright (C) 2019 Free Software Foundation, Inc. + + This file is part of libctf. + + libctf is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf-bfd.h" + +/* Free the BFD bits of a CTF file on ctf_close(). */ +static void +ctf_bfdclose (ctf_file_t *fp) +{ + if (fp->ctf_abfd != NULL) + if (!bfd_close_all_done (fp->ctf_abfd)) + ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error())); +} + +/* Open a CTF file given the specified BFD. */ + +ctf_file_t * +ctf_bfdopen (struct bfd *abfd, int *errp) +{ + ctf_file_t *fp; + asection *ctf_asect; + bfd_byte *contents; + ctf_sect_t ctfsect; + + libctf_init_debug(); + + if ((ctf_asect = bfd_get_section_by_name (abfd, _CTF_SECTION)) == NULL) + { + return (ctf_set_open_errno (errp, ECTF_NOCTFDATA)); + } + + if (!bfd_malloc_and_get_section (abfd, ctf_asect, &contents)) + { + ctf_dprintf ("ctf_bfdopen(): cannot malloc CTF section: %s\n", + bfd_errmsg (bfd_get_error())); + return (ctf_set_open_errno (errp, ECTF_FMT)); + } + + ctfsect.cts_name = _CTF_SECTION; + ctfsect.cts_type = SHT_PROGBITS; + ctfsect.cts_flags = 0; + ctfsect.cts_entsize = 1; + ctfsect.cts_offset = 0; + ctfsect.cts_size = bfd_section_size (abfd, ctf_asect); + ctfsect.cts_data = contents; + + if ((fp = ctf_bfdopen_ctfsect (abfd, &ctfsect, errp)) != NULL) + { + fp->ctf_data_alloced = (void *) ctfsect.cts_data; + return fp; + } + + free (contents); + return NULL; /* errno is set for us. */ +} + +/* Open a CTF file given the specified BFD and CTF section. */ + +ctf_file_t * +ctf_bfdopen_ctfsect (struct bfd *abfd, const ctf_sect_t *ctfsect, int *errp) +{ + ctf_file_t *fp; + ctf_sect_t *symsectp = NULL; + ctf_sect_t *strsectp = NULL; + const char *bfderrstr = NULL; + + asection *sym_asect; + ctf_sect_t symsect, strsect; + /* TODO: handle SYMTAB_SHNDX. */ + + if ((sym_asect = bfd_section_from_elf_index (abfd, + elf_onesymtab (abfd))) != NULL) + { + Elf_Internal_Shdr *symhdr = &elf_symtab_hdr (abfd); + asection *str_asect = NULL; + bfd_byte *contents; + + if (symhdr->sh_link != SHN_UNDEF && + symhdr->sh_link <= elf_numsections (abfd)) + str_asect = bfd_section_from_elf_index (abfd, symhdr->sh_link); + + Elf_Internal_Shdr *strhdr = elf_elfsections (abfd)[symhdr->sh_link]; + + if (sym_asect && str_asect) + { + if (!bfd_malloc_and_get_section (abfd, str_asect, &contents)) + { + bfderrstr = "Cannot malloc string table"; + free (contents); + goto err; + } + strsect.cts_data = contents; + strsect.cts_name = (char *) strsect.cts_data + strhdr->sh_name; + strsect.cts_type = strhdr->sh_type; + strsect.cts_flags = strhdr->sh_flags; + strsect.cts_entsize = strhdr->sh_size; + strsect.cts_offset = strhdr->sh_offset; + strsectp = &strsect; + + if (!bfd_malloc_and_get_section (abfd, sym_asect, &contents)) + { + bfderrstr = "Cannot malloc symbol table"; + free (contents); + goto err_free_str; + } + + symsect.cts_name = (char *) strsect.cts_data + symhdr->sh_name; + symsect.cts_type = symhdr->sh_type; + symsect.cts_flags = symhdr->sh_flags; + symsect.cts_entsize = symhdr->sh_size; + symsect.cts_data = contents; + symsect.cts_offset = symhdr->sh_offset; + symsectp = &symsect; + } + } + + if ((fp = ctf_bufopen (ctfsect, symsectp, strsectp, errp)) != NULL) + { + if (symsectp) + fp->ctf_symtab_alloced = (void *) symsectp->cts_data; + if (strsectp) + fp->ctf_strtab_alloced = (void *) strsectp->cts_data; + fp->ctf_bfd_close = ctf_bfdclose; + return fp; + } + ctf_dprintf ("ctf_internal_open(): cannot open CTF: %s\n", + ctf_errmsg (*errp)); + +err_free_str: + free ((void *) strsect.cts_data); +err: _libctf_unused_; + if (bfderrstr) + { + ctf_dprintf ("ctf_bfdopen(): %s: %s\n", bfderrstr, + bfd_errmsg (bfd_get_error())); + ctf_set_open_errno (errp, ECTF_FMT); + } + return NULL; +} + + +/* Open the specified file descriptor and return a pointer to a CTF container. + The file can be either an ELF file or raw CTF file. The caller is + responsible for closing the file descriptor when it is no longer needed. + + TODO: handle CTF archives too. */ + +ctf_file_t * +ctf_fdopen (int fd, const char *filename, int *errp) +{ + ctf_file_t *fp = NULL; + bfd *abfd; + int nfd; + + struct stat st; + ssize_t nbytes; + + ctf_preamble_t ctfhdr; + + memset (&ctfhdr, 0, sizeof (ctfhdr)); + + libctf_init_debug(); + + if (fstat (fd, &st) == -1) + return (ctf_set_open_errno (errp, errno)); + + if ((nbytes = ctf_pread (fd, &ctfhdr, sizeof (ctfhdr), 0)) <= 0) + return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT)); + + /* If we have read enough bytes to form a CTF header and the magic + string matches, attempt to interpret the file as raw CTF. */ + + if ((size_t) nbytes >= sizeof (ctf_preamble_t) && + ctfhdr.ctp_magic == CTF_MAGIC) + { + void *data; + + if (ctfhdr.ctp_version > CTF_VERSION) + return (ctf_set_open_errno (errp, ECTF_CTFVERS)); + + if ((data = ctf_mmap (st.st_size, 0, fd)) == NULL) + return (ctf_set_open_errno (errp, errno)); + + if ((fp = ctf_simple_open (data, (size_t) st.st_size, NULL, 0, 0, + NULL, 0, errp)) == NULL) + ctf_munmap (data, (size_t) st.st_size); + fp->ctf_data_mmapped = data; + fp->ctf_data_mmapped_len = (size_t) st.st_size; + + return fp; + } + + /* Attempt to open the file with BFD. We must dup the fd first, since bfd + takes ownership of the passed fd. */ + + if ((nfd = dup (fd)) < 0) + return (ctf_set_open_errno (errp, errno)); + + if ((abfd = bfd_fdopenr (filename, NULL, nfd)) == NULL) + { + ctf_dprintf ("Cannot open BFD from %s: %s\n", + filename ? filename : "(unknown file)", + bfd_errmsg (bfd_get_error())); + return (ctf_set_open_errno (errp, ECTF_FMT)); + } + + if ((fp = ctf_bfdopen (abfd, errp)) == NULL) + { + if (!bfd_close_all_done (abfd)) + ctf_dprintf ("Cannot close BFD: %s\n", bfd_errmsg (bfd_get_error())); + return NULL; /* errno is set for us. */ + } + fp->ctf_abfd = abfd; + + return fp; +} + +/* Open the specified file and return a pointer to a CTF container. The file + can be either an ELF file or raw CTF file. This is just a convenient + wrapper around ctf_fdopen() for callers. */ + +ctf_file_t * +ctf_open (const char *filename, int *errp) +{ + ctf_file_t *fp; + int fd; + + if ((fd = open (filename, O_RDONLY)) == -1) + { + if (errp != NULL) + *errp = errno; + return NULL; + } + + fp = ctf_fdopen (fd, filename, errp); + (void) close (fd); + return fp; +} -- 2.21.0.237.gd0cfaa883d