libctf, binutils: support CTF archives like objdump

objdump and readelf have one major CTF-related behavioural difference:
objdump can read .ctf sections that contain CTF archives and extract and
dump their members, while readelf cannot.  Since the linker often emits
CTF archives, this means that readelf intermittently and (from the
user's perspective) randomly fails to read CTF in files that ld emits,
with a confusing error message wrongly claiming that the CTF content is
corrupt.  This is purely because the archive-opening code in libctf was
needlessly tangled up with the BFD code, so readelf couldn't use it.

Here, we disentangle it, moving ctf_new_archive_internal from
ctf-open-bfd.c into ctf-archive.c and merging it with the helper
function in ctf-archive.c it was already using.  We add a new public API
function ctf_arc_bufopen, that looks very like ctf_bufopen but returns
an archive given suitable section data rather than a ctf_file_t: the
archive is a ctf_archive_t, so it can be called on raw CTF dictionaries
(with no archive present) and will return a single-member synthetic
"archive".

There is a tiny lifetime tweak here: before now, the archive code could
assume that the symbol section in the ctf_archive_internal wrapper
structure was always owned by BFD if it was present and should always be
freed: now, the caller can pass one in via ctf_arc_bufopen, wihch has
the usual lifetime rules for such sections (caller frees): so we add an
extra field to track whether this is an internal call from ctf-open-bfd,
in which case we still free the symbol section.

include/
	* ctf-api.h (ctf_arc_bufopen): New.
libctf/
	* ctf-impl.h (ctf_new_archive_internal): Declare.
	(ctf_arc_bufopen): Remove.
	(ctf_archive_internal) <ctfi_free_symsect>: New.
	* ctf-archive.c (ctf_arc_close): Use it.
	(ctf_arc_bufopen): Fuse into...
	(ctf_new_archive_internal): ... this, moved across from...
	* ctf-open-bfd.c: ... here.
	(ctf_bfdopen_ctfsect): Use ctf_arc_bufopen.
	* libctf.ver: Add it.
binutils/
	* readelf.c (dump_section_as_ctf): Support .ctf archives using
	ctf_arc_bufopen.  Automatically load the .ctf member of such
	archives as the parent of all other members, unless specifically
	overridden via --ctf-parent.  Split out dumping code into...
	(dump_ctf_archive_member): ... here, as in objdump, and call
	it once per archive member.
	(dump_ctf_indent_lines): Code style fix.
This commit is contained in:
Nick Alcock 2019-12-13 12:01:12 +00:00
parent 8ffcdf1823
commit 2f6ecaed66
9 changed files with 184 additions and 111 deletions

View file

@ -32,40 +32,6 @@
#include "elf-bfd.h"
/* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
ctf_file. Closes ARC and/or FP on error. Arrange to free the SYMSECT or
STRSECT, as needed, on close (though the STRSECT interior is bound to the bfd
* and is not actually freed by this machinery). */
static struct ctf_archive_internal *
ctf_new_archive_internal (int is_archive, struct ctf_archive *arc,
ctf_file_t *fp, const ctf_sect_t *symsect,
const ctf_sect_t *strsect,
int *errp)
{
struct ctf_archive_internal *arci;
if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
{
if (is_archive)
ctf_arc_close_internal (arc);
else
ctf_file_close (fp);
return (ctf_set_open_errno (errp, errno));
}
arci->ctfi_is_archive = is_archive;
if (is_archive)
arci->ctfi_archive = arc;
else
arci->ctfi_file = fp;
if (symsect)
memcpy (&arci->ctfi_symsect, symsect, sizeof (struct ctf_sect));
if (strsect)
memcpy (&arci->ctfi_strsect, strsect, sizeof (struct ctf_sect));
return arci;
}
/* Free the BFD bits of a CTF file on ctf_arc_close(). */
static void
@ -107,6 +73,7 @@ ctf_bfdopen (struct bfd *abfd, int *errp)
if ((arc = ctf_bfdopen_ctfsect (abfd, &ctfsect, errp)) != NULL)
{
/* This frees the cts_data later. */
arc->ctfi_data = (void *) ctfsect.cts_data;
return arc;
}
@ -116,20 +83,16 @@ ctf_bfdopen (struct bfd *abfd, int *errp)
}
/* Open a CTF file given the specified BFD and CTF section (which may contain a
CTF archive or a file). Takes ownership of the ctfsect, and frees it
later. */
CTF archive or a file). */
ctf_archive_t *
ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
const ctf_sect_t *ctfsect, int *errp)
{
struct ctf_archive *arc = NULL;
ctf_archive_t *arci;
ctf_file_t *fp = NULL;
ctf_sect_t *symsectp = NULL;
ctf_sect_t *strsectp = NULL;
const char *bfderrstr = NULL;
int is_archive;
#ifdef HAVE_BFD_ELF
ctf_sect_t symsect, strsect;
@ -192,30 +155,13 @@ ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_,
}
#endif
if (ctfsect->cts_size > sizeof (uint64_t) &&
((*(uint64_t *) ctfsect->cts_data) == CTFA_MAGIC))
{
is_archive = 1;
if ((arc = ctf_arc_bufopen ((void *) ctfsect->cts_data,
ctfsect->cts_size, errp)) == NULL)
goto err_free_str;
}
else
{
is_archive = 0;
if ((fp = ctf_bufopen (ctfsect, symsectp, strsectp, errp)) == NULL)
{
ctf_dprintf ("ctf_internal_open(): cannot open CTF: %s\n",
ctf_errmsg (*errp));
goto err_free_str;
}
}
arci = ctf_new_archive_internal (is_archive, arc, fp, symsectp, strsectp,
errp);
arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp);
if (arci)
return arci;
err_free_str: ;
{
/* Request freeing of the symsect. */
arci->ctfi_free_symsect = 1;
return arci;
}
#ifdef HAVE_BFD_ELF
err_free_sym:
free (symtab);