public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
To: "Jose E. Marchesi via Libabigail" <libabigail@sourceware.org>
Subject: Re: [PATCH V2] ctf: make libabigail::ctf_reader::read_corpus reentrant
Date: Fri, 05 Nov 2021 13:43:50 +0100	[thread overview]
Message-ID: <871r3uai2h.fsf@oracle.com> (raw)
In-Reply-To: <20211103135820.6233-1-jose.marchesi@oracle.com> (Jose E. Marchesi via Libabigail's message of "Wed, 3 Nov 2021 14:58:20 +0100")


ping

> [Changes from V1:
> - Make sure that the string table passed to libctf is the one related
>   to the symbol table.]
>
> The libctf call ctf_open is not reentrant.  This is because it uses
> bfd_open (and other BFD calls) internally in order to fetch the
> different bits of CTF from the ELF file.
>
> This is unfortunate, as it makes libabigail::ctf_reader::read_corpus
> non-reentrant.  We detected this problem thanks to one of the
> libabigail test driver, that exercises tests in parallel using
> threads.
>
> Fortunately libctf provides an alternate way to decode CTF data, that
> involves the user to provide the raw contents of the relevant ELF
> sections (.ctf, the symtab, the string table) to ctf_arc_bufopen
> call.
>
> This patch changes the CTF reader in libabigail to use this
> mechanism.  libelf is used in order to extract the contents of these
> sections.
>
> 	* src/abg-ctf-reader.cc (class read_context): New attributes
> 	elf_handler, elf_fd, ctf_sect, symtab_sec and strtab_sect.
> 	(read_context): Do not read the CTF archive here.
> 	(slurp_elf_info): Adjust to use attributes instead of locals, and
> 	fetch the raw ELF section contents for libctf.
> 	(close_elf_handler): New function.
> 	(fill_ctf_section): Likewise.
> 	(read_corpus): Call open_elf_handler, close_elf_handler and build
> 	the CTF archive using ctf_arc_bufopen instead of ctf_open.
>
> Signed-by: Jose E. Marchesi <jose.marchesi@oracle.com>
> ---
>  src/abg-ctf-reader.cc | 143 +++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 112 insertions(+), 31 deletions(-)
>
> diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index 1c41ea02..d107fac8 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> @@ -58,9 +58,20 @@ public:
>    /// is used to reuse already generated types.
>    unordered_map<ctf_id_t,type_base_sptr> types_map;
>  
> +  /// libelf handler for the ELF file from which we read the CTF data,
> +  /// and the corresponding file descriptor.
> +  Elf *elf_handler;
> +  int elf_fd;
> +
>    /// The symtab read from the ELF file.
>    symtab_reader::symtab_sptr symtab;
>  
> +  /// Raw contents of several sections from the ELF file.  These are
> +  /// used by libctf.
> +  ctf_sect_t ctf_sect;
> +  ctf_sect_t symtab_sect;
> +  ctf_sect_t strtab_sect;
> +
>    /// Associate a given CTF type ID with a given libabigail IR type.
>    void add_type(ctf_id_t ctf_type, type_base_sptr type)
>    {
> @@ -93,15 +104,12 @@ public:
>    /// @param elf_path the path to the ELF file.
>    read_context(string elf_path, ir::environment *env)
>    {
> -    int err;
> -
>      types_map.clear();
>      filename = elf_path;
>      ir_env = env;
> -    ctfa = ctf_open(filename.c_str(), NULL /* BFD target */, &err);
> -
> -    if (ctfa == NULL)
> -      fprintf(stderr, "cannot open %s: %s\n", filename.c_str(), ctf_errmsg(err));
> +    elf_handler = NULL;
> +    elf_fd = -1;
> +    ctfa = NULL;
>    }
>  
>    /// Destructor of the @ref read_context type.
> @@ -939,50 +947,115 @@ process_ctf_archive(read_context *ctxt, corpus_sptr corp)
>  
>  }
>  
> -/// Slurp certain information from the ELF file described by a given
> -/// read context and install it in a libabigail corpus.
> -///
> -/// @param ctxt the read context
> -/// @param corp the libabigail corpus in which to install the info.
> +/// Open the ELF file described by the given read context.
>  ///
> -/// @return 0 if there is an error.
> +/// @param ctxt the read context.
> +/// @return 0 if the ELF file can't be opened.
>  /// @return 1 otherwise.
>  
>  static int
> -slurp_elf_info(read_context *ctxt, corpus_sptr corp)
> +open_elf_handler (read_context *ctxt)
>  {
>    /* libelf requires to negotiate/set the version of ELF.  */
>    if (elf_version(EV_CURRENT) == EV_NONE)
>      return 0;
>  
>    /* Open an ELF handler.  */
> -  int elf_fd = open(ctxt->filename.c_str(), O_RDONLY);
> -  if (elf_fd == -1)
> +  ctxt->elf_fd = open(ctxt->filename.c_str(), O_RDONLY);
> +  if (ctxt->elf_fd == -1)
>      return 0;
>  
> -  Elf *elf_handler = elf_begin(elf_fd, ELF_C_READ, NULL);
> -  if (elf_handler == NULL)
> +  ctxt->elf_handler = elf_begin(ctxt->elf_fd, ELF_C_READ, NULL);
> +  if (ctxt->elf_handler == NULL)
>      {
>        fprintf(stderr, "cannot open %s: %s\n",
>                 ctxt->filename.c_str(), elf_errmsg(elf_errno()));
> -      close(elf_fd);
> +      close(ctxt->elf_fd);
>        return 0;
>      }
>  
> +  return 1;
> +}
> +
> +/// Close the ELF file described by the given read context.
> +///
> +/// @param ctxt the read context.
> +
> +static void
> +close_elf_handler (read_context *ctxt)
> +{
> +  /* Finish the ELF handler and close the associated file.  */
> +  elf_end(ctxt->elf_handler);
> +  close(ctxt->elf_fd);
> +}
> +
> +/// Fill a CTF section description with the information in a given ELF
> +/// section.
> +///
> +/// @param ctxt the read context.
> +/// @param elf_section the ELF section from which to get.
> +/// @param ctf_section the CTF section to fill with the raw data.
> +
> +static void
> +fill_ctf_section(read_context *ctxt, Elf_Scn *elf_section, ctf_sect_t *ctf_section)
> +{
> +  GElf_Shdr section_header_mem, *section_header;
> +  Elf_Data *section_data;
> +
> +  section_header = gelf_getshdr(elf_section, &section_header_mem);
> +  section_data = elf_getdata(elf_section, 0);
> +
> +  ABG_ASSERT (section_header != NULL);
> +  ABG_ASSERT (section_data != NULL);
> +
> +  ctf_section->cts_name = ""; /* This is not actually used by libctf.  */
> +  ctf_section->cts_data = (char *) section_data->d_buf;
> +  ctf_section->cts_size = section_data->d_size;
> +  ctf_section->cts_entsize = section_header->sh_entsize;
> +}
> +
> +/// Slurp certain information from the ELF file described by a given
> +/// read context and install it in a libabigail corpus.
> +///
> +/// @param ctxt the read context
> +/// @param corp the libabigail corpus in which to install the info.
> +///
> +/// @return 0 if there is an error.
> +/// @return 1 otherwise.
> +
> +static int
> +slurp_elf_info(read_context *ctxt, corpus_sptr corp)
> +{
>    /* Set the ELF architecture.  */
>    GElf_Ehdr eh_mem;
> -  GElf_Ehdr *ehdr = gelf_getehdr(elf_handler, &eh_mem);
> +  GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
>    corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
>  
>    /* Read the symtab from the ELF file and set it in the corpus.  */
>    ctxt->symtab =
> -    symtab_reader::symtab::load(elf_handler, ctxt->ir_env,
> +    symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env,
>                                  0 /* No suppressions.  */);
>    corp->set_symtab(ctxt->symtab);
>  
> -  /* Finish the ELF handler and close the associated file.  */
> -  elf_end(elf_handler);
> -  close(elf_fd);
> +  /* Get the raw ELF section contents for libctf.  The .ctf section
> +     and the symtab are straightforward enough.  */
> +  Elf_Scn *ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
> +  Elf_Scn *symtab_scn = elf_helpers::find_symbol_table_section(ctxt->elf_handler);
> +
> +  if (ctf_scn == NULL || symtab_scn == NULL)
> +    return 0;
> +
> +  /* The string table that libctf expects is the one related to the
> +     symbol table by virtue of sh_link.  */
> +  GElf_Shdr symtab_shdr_mem, *symtab_shdr = gelf_getshdr(symtab_scn, &symtab_shdr_mem);
> +  Elf_Scn *strtab_scn = elf_getscn(ctxt->elf_handler, symtab_shdr->sh_link);
> +
> +  if (strtab_scn == NULL)
> +    return 0;
> +
> +  fill_ctf_section(ctxt, ctf_scn, &ctxt->ctf_sect);
> +  fill_ctf_section(ctxt, symtab_scn, &ctxt->symtab_sect);
> +  fill_ctf_section(ctxt, strtab_scn, &ctxt->strtab_sect);
>  
>    return 1;
>  }
> @@ -1012,19 +1085,27 @@ read_corpus(read_context *ctxt)
>    corpus_sptr corp
>      = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
>  
> +  /* Open the ELF file.  */
> +  if (!open_elf_handler(ctxt))
> +    return corp;
> +
>    /* Set some properties of the corpus first.  */
>    corp->set_origin(corpus::CTF_ORIGIN);
>    if (!slurp_elf_info(ctxt, corp))
>      return corp;
>  
> -  /* Get out now if no CTF debug info is found.  */
> -  if (ctxt->ctfa == NULL)
> -    return corp;
> -
> -  /* Process the CTF archive in the read context, if any.  Information
> -     about the types, variables, functions, etc contained in the
> -     archive are added to the given corpus.  */
> -  process_ctf_archive(ctxt, corp);
> +  /* Build the cfta from the contents of the relevant ELF sections,
> +     and process the CTF archive in the read context, if any.
> +     Information about the types, variables, functions, etc contained
> +     in the archive are added to the given corpus.  */
> +  int errp;
> +  ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
> +                               &ctxt->strtab_sect, &errp);
> +  if (ctxt->ctfa != NULL)
> +    process_ctf_archive(ctxt, corp);
> +
> +  /* Cleanup and return.  */
> +  close_elf_handler(ctxt);
>    return corp;
>  }

  reply	other threads:[~2021-11-05 12:44 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-03 13:58 Jose E. Marchesi
2021-11-05 12:43 ` Jose E. Marchesi [this message]
2021-11-09 10:40 ` Dodji Seketeli
2021-11-10 12:08   ` Jose E. Marchesi
2021-11-10 12:15     ` Jose E. Marchesi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=871r3uai2h.fsf@oracle.com \
    --to=jose.marchesi@oracle.com \
    --cc=libabigail@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).