aboutsummaryrefslogtreecommitdiff
path: root/libctf
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2019-12-13 12:01:12 +0000
committerNick Alcock <nick.alcock@oracle.com>2020-06-26 15:56:39 +0100
commit2f6ecaed667d1597c67991224948e0a3da427cc9 (patch)
tree0ee2edd3637d01e08332ecb6868e5c1ae5336637 /libctf
parent8ffcdf1823d186c94eb3a1781e366a155646140a (diff)
downloadbinutils-2f6ecaed667d1597c67991224948e0a3da427cc9.zip
binutils-2f6ecaed667d1597c67991224948e0a3da427cc9.tar.gz
binutils-2f6ecaed667d1597c67991224948e0a3da427cc9.tar.bz2
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.
Diffstat (limited to 'libctf')
-rw-r--r--libctf/ChangeLog12
-rw-r--r--libctf/ctf-archive.c76
-rw-r--r--libctf/ctf-impl.h6
-rw-r--r--libctf/ctf-open-bfd.c68
-rw-r--r--libctf/libctf.ver1
5 files changed, 88 insertions, 75 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index 3ab0a6c..5e473a7 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,5 +1,17 @@
2020-06-26 Nick Alcock <nick.alcock@oracle.com>
+ * 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.
+
+2020-06-26 Nick Alcock <nick.alcock@oracle.com>
+
* ctf-create.c (ctf_add_forward): Intern in the right namespace.
(ctf_dtd_delete): Remove correspondingly.
(ctf_rollback): Likewise.
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index 73d772f..d27b27e 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -343,21 +343,71 @@ search_modent_by_name (const void *key, const void *ent)
return strcmp (k, &search_nametbl[le64toh (v->name_offset)]);
}
-/* A trivial wrapper: open a CTF archive, from data in a buffer (which the
- caller must preserve until ctf_arc_close() time). Returns the archive, or
- NULL and an error in *err (if not NULL). */
-struct ctf_archive *
-ctf_arc_bufopen (const void *buf, size_t size _libctf_unused_, int *errp)
+/* 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. */
+
+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 *arc = (struct ctf_archive *) buf;
+ struct ctf_archive_internal *arci;
- if (le64toh (arc->ctfa_magic) != CTFA_MAGIC)
+ if ((arci = calloc (1, sizeof (struct ctf_archive_internal))) == NULL)
{
- if (errp)
- *errp = ECTF_FMT;
- return NULL;
+ if (is_archive)
+ ctf_arc_close_internal (arc);
+ else
+ ctf_file_close (fp);
+ return (ctf_set_open_errno (errp, errno));
}
- return arc;
+ 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));
+ arci->ctfi_free_symsect = 0;
+
+ return arci;
+}
+
+/* Open a CTF archive or dictionary from data in a buffer (which the caller must
+ preserve until ctf_arc_close() time). Returns the archive, or NULL and an
+ error in *err (if not NULL). */
+ctf_archive_t *
+ctf_arc_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
+ const ctf_sect_t *strsect, int *errp)
+{
+ struct ctf_archive *arc = NULL;
+ int is_archive;
+ ctf_file_t *fp = NULL;
+
+ if (ctfsect->cts_size > sizeof (uint64_t) &&
+ ((*(uint64_t *) ctfsect->cts_data) == CTFA_MAGIC))
+ {
+ /* The archive is mmappable, so this operation is trivial. */
+
+ is_archive = 1;
+ arc = (struct ctf_archive *) ctfsect->cts_data;
+ }
+ else
+ {
+ is_archive = 0;
+ if ((fp = ctf_bufopen (ctfsect, symsect, strsect, errp)) == NULL)
+ {
+ ctf_dprintf ("ctf_internal_open(): cannot open CTF: %s\n",
+ ctf_errmsg (*errp));
+ return NULL;
+ }
+ }
+ return ctf_new_archive_internal (is_archive, arc, fp, symsect, strsect,
+ errp);
}
/* Open a CTF archive. Returns the archive, or NULL and an error in *err (if
@@ -436,8 +486,8 @@ ctf_arc_close (ctf_archive_t *arc)
ctf_arc_close_internal (arc->ctfi_archive);
else
ctf_file_close (arc->ctfi_file);
- free ((void *) arc->ctfi_symsect.cts_data);
- /* Do not free the ctfi_strsect: it is bound to the bfd. */
+ if (arc->ctfi_free_symsect)
+ free ((void *) arc->ctfi_symsect.cts_data);
free (arc->ctfi_data);
if (arc->ctfi_bfd_close)
arc->ctfi_bfd_close (arc);
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 56ef9a3..ade1a6e 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -309,6 +309,7 @@ struct ctf_archive_internal
struct ctf_archive *ctfi_archive;
ctf_sect_t ctfi_symsect;
ctf_sect_t ctfi_strsect;
+ int ctfi_free_symsect;
void *ctfi_data;
bfd *ctfi_abfd; /* Optional source of section data. */
void (*ctfi_bfd_close) (struct ctf_archive_internal *);
@@ -435,8 +436,11 @@ extern void ctf_str_rollback (ctf_file_t *, ctf_snapshot_id_t);
extern void ctf_str_purge_refs (ctf_file_t *);
extern ctf_strs_writable_t ctf_str_write_strtab (ctf_file_t *);
+extern 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);
extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
-extern struct ctf_archive *ctf_arc_bufopen (const void *, size_t, int *);
extern void ctf_arc_close_internal (struct ctf_archive *);
extern void *ctf_set_open_errno (int *, int);
extern unsigned long ctf_set_errno (ctf_file_t *, int);
diff --git a/libctf/ctf-open-bfd.c b/libctf/ctf-open-bfd.c
index 24c0403..630a158 100644
--- a/libctf/ctf-open-bfd.c
+++ b/libctf/ctf-open-bfd.c
@@ -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
+ arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp);
+ if (arci)
{
- 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;
- }
+ /* Request freeing of the symsect. */
+ arci->ctfi_free_symsect = 1;
+ return arci;
}
- arci = ctf_new_archive_internal (is_archive, arc, fp, symsectp, strsectp,
- errp);
-
- if (arci)
- return arci;
- err_free_str: ;
#ifdef HAVE_BFD_ELF
err_free_sym:
free (symtab);
diff --git a/libctf/libctf.ver b/libctf/libctf.ver
index 14ca413..aad304b 100644
--- a/libctf/libctf.ver
+++ b/libctf/libctf.ver
@@ -128,6 +128,7 @@ LIBCTF_1.0 {
ctf_arc_write;
ctf_arc_write_fd;
ctf_arc_open;
+ ctf_arc_bufopen;
ctf_arc_close;
ctf_arc_open_by_name;
ctf_arc_open_by_name_sections;