aboutsummaryrefslogtreecommitdiff
path: root/binutils
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 /binutils
parent8ffcdf1823d186c94eb3a1781e366a155646140a (diff)
downloadgdb-2f6ecaed667d1597c67991224948e0a3da427cc9.zip
gdb-2f6ecaed667d1597c67991224948e0a3da427cc9.tar.gz
gdb-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 'binutils')
-rw-r--r--binutils/ChangeLog10
-rw-r--r--binutils/readelf.c110
2 files changed, 86 insertions, 34 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 1532a37..95a868a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,5 +1,15 @@
2020-06-26 Nick Alcock <nick.alcock@oracle.com>
+ * 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.
+
+2020-06-26 Nick Alcock <nick.alcock@oracle.com>
+
* configure.ac [--enable-libctf]: New, default yes.
Set ENABLE_LIBCTF accordingly.
* Makefile.am [!ENABLE_LIBCTF]: Empty LIBCTF and LIBCTF_NOBFD.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 2f0cd77..1d7cfbc 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -14151,8 +14151,9 @@ shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
it is passed, or a pointer to newly-allocated storage, in which case
dump_ctf() will free it when it no longer needs it. */
-static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
- char *s, void *arg)
+static char *
+dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
+ char *s, void *arg)
{
const char *blanks = arg;
char *new_s;
@@ -14162,6 +14163,55 @@ static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
return new_s;
}
+/* Dump one CTF archive member. */
+
+static int
+dump_ctf_archive_member (ctf_file_t *ctf, const char *name, void *arg)
+{
+ ctf_file_t *parent = (ctf_file_t *) arg;
+ const char *things[] = {"Header", "Labels", "Data objects",
+ "Function objects", "Variables", "Types", "Strings",
+ ""};
+ const char **thing;
+ size_t i;
+
+ /* Only print out the name of non-default-named archive members.
+ The name .ctf appears everywhere, even for things that aren't
+ really archives, so printing it out is liable to be confusing.
+
+ The parent, if there is one, is the default-owned archive member:
+ avoid importing it into itself. (This does no harm, but looks
+ confusing.) */
+
+ if (strcmp (name, ".ctf") != 0)
+ {
+ printf (_("\nCTF archive member: %s:\n"), name);
+ ctf_import (ctf, parent);
+ }
+
+ for (i = 0, thing = things; *thing[0]; thing++, i++)
+ {
+ ctf_dump_state_t *s = NULL;
+ char *item;
+
+ printf ("\n %s:\n", *thing);
+ while ((item = ctf_dump (ctf, &s, i, dump_ctf_indent_lines,
+ (void *) " ")) != NULL)
+ {
+ printf ("%s\n", item);
+ free (item);
+ }
+
+ if (ctf_errno (ctf))
+ {
+ error (_("Iteration failed: %s, %s\n"), *thing,
+ ctf_errmsg (ctf_errno (ctf)));
+ return 1;
+ }
+ }
+ return 0;
+}
+
static bfd_boolean
dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
{
@@ -14175,16 +14225,12 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
ctf_sect_t ctfsect, symsect, strsect, parentsect;
ctf_sect_t * symsectp = NULL;
ctf_sect_t * strsectp = NULL;
- ctf_file_t * ctf = NULL;
- ctf_file_t * parent = NULL;
+ ctf_archive_t * ctfa = NULL;
+ ctf_archive_t * parenta = NULL, *lookparent;
+ ctf_file_t * parent = NULL;
- const char *things[] = {"Header", "Labels", "Data objects",
- "Function objects", "Variables", "Types", "Strings",
- ""};
- const char **thing;
int err;
bfd_boolean ret = FALSE;
- size_t i;
shdr_to_ctf_sect (&ctfsect, section, filedata);
data = get_section_contents (section, filedata);
@@ -14243,9 +14289,11 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
parentsect.cts_data = parentdata;
}
- /* Load the CTF file and dump it. */
+ /* Load the CTF file and dump it. It may be a raw CTF section, or an archive:
+ libctf papers over the difference, so we can pretend it is always an
+ archive. Possibly open the parent as well, if one was specified. */
- if ((ctf = ctf_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
+ if ((ctfa = ctf_arc_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
{
error (_("CTF open failure: %s\n"), ctf_errmsg (err));
goto fail;
@@ -14253,13 +14301,24 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
if (parentdata)
{
- if ((parent = ctf_bufopen (&parentsect, symsectp, strsectp, &err)) == NULL)
+ if ((parenta = ctf_arc_bufopen (&parentsect, symsectp, strsectp,
+ &err)) == NULL)
{
error (_("CTF open failure: %s\n"), ctf_errmsg (err));
goto fail;
}
+ lookparent = parenta;
+ }
+ else
+ lookparent = ctfa;
- ctf_import (ctf, parent);
+ /* Assume that the applicable parent archive member is the default one.
+ (This is what all known implementations are expected to do, if they
+ put CTFs and their parents in archives together.) */
+ if ((parent = ctf_arc_open_by_name (lookparent, NULL, &err)) == NULL)
+ {
+ error (_("CTF open failure: %s\n"), ctf_errmsg (err));
+ goto fail;
}
ret = TRUE;
@@ -14267,30 +14326,13 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
printf (_("\nDump of CTF section '%s':\n"),
printable_section_name (filedata, section));
- for (i = 0, thing = things; *thing[0]; thing++, i++)
- {
- ctf_dump_state_t *s = NULL;
- char *item;
-
- printf ("\n %s:\n", *thing);
- while ((item = ctf_dump (ctf, &s, i, dump_ctf_indent_lines,
- (void *) " ")) != NULL)
- {
- printf ("%s\n", item);
- free (item);
- }
-
- if (ctf_errno (ctf))
- {
- error (_("Iteration failed: %s, %s\n"), *thing,
- ctf_errmsg (ctf_errno (ctf)));
- ret = FALSE;
- }
- }
+ if (ctf_archive_iter (ctfa, dump_ctf_archive_member, parent) != 0)
+ ret = FALSE;
fail:
- ctf_file_close (ctf);
ctf_file_close (parent);
+ ctf_close (ctfa);
+ ctf_close (parenta);
free (parentdata);
free (data);
free (symdata);