aboutsummaryrefslogtreecommitdiff
path: root/ld/ldelf.c
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2022-05-25 14:41:47 +0100
committerAlan Modra <amodra@gmail.com>2022-05-26 12:56:12 +0930
commit9e2bb0cb5e74aed4158f08495534922d7108f928 (patch)
treeed3ed33aef50a4bd5e0f16d3072340a81d0d0b4f /ld/ldelf.c
parentd1a24139adfb2f029c9d52a9c43da44a617f90a4 (diff)
downloadgdb-9e2bb0cb5e74aed4158f08495534922d7108f928.zip
gdb-9e2bb0cb5e74aed4158f08495534922d7108f928.tar.gz
gdb-9e2bb0cb5e74aed4158f08495534922d7108f928.tar.bz2
ld: add --package-metadata
Generate a .note.package FDO package metadata ELF note, following the spec: https://systemd.io/ELF_PACKAGE_METADATA/ If the jansson library is available at build time (and it is explicitly enabled), link ld to it, and use it to validate that the input is correct JSON, to avoid writing garbage to the file. The configure option --enable-jansson has to be used to explicitly enable it (error out when not found). This allows bootstrappers (or others who are not interested) to seamlessly skip it without issues.
Diffstat (limited to 'ld/ldelf.c')
-rw-r--r--ld/ldelf.c135
1 files changed, 133 insertions, 2 deletions
diff --git a/ld/ldelf.c b/ld/ldelf.c
index 4094640..bfa0d54 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -39,6 +39,9 @@
#include <glob.h>
#endif
#include "ldelf.h"
+#ifdef HAVE_JANSSON
+#include <jansson.h>
+#endif
struct dt_needed
{
@@ -49,6 +52,9 @@ struct dt_needed
/* Style of .note.gnu.build-id section. */
const char *ldelf_emit_note_gnu_build_id;
+/* Content of .note.package section. */
+const char *ldelf_emit_note_fdo_package_metadata;
+
/* These variables are required to pass information back and forth
between after_open and check_needed and stat_needed and vercheck. */
@@ -1249,7 +1255,8 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
}
}
- if (ldelf_emit_note_gnu_build_id != NULL)
+ if (ldelf_emit_note_gnu_build_id != NULL
+ || ldelf_emit_note_fdo_package_metadata != NULL)
{
/* Find an ELF input. */
for (abfd = link_info.input_bfds;
@@ -1262,11 +1269,20 @@ ldelf_after_open (int use_libpath, int native, int is_linux, int is_freebsd,
/* PR 10555: If there are no ELF input files do not try to
create a .note.gnu-build-id section. */
if (abfd == NULL
- || !ldelf_setup_build_id (abfd))
+ || (ldelf_emit_note_gnu_build_id != NULL
+ && !ldelf_setup_build_id (abfd)))
{
free ((char *) ldelf_emit_note_gnu_build_id);
ldelf_emit_note_gnu_build_id = NULL;
}
+
+ if (abfd == NULL
+ || (ldelf_emit_note_fdo_package_metadata != NULL
+ && !ldelf_setup_package_metadata (abfd)))
+ {
+ free ((char *) ldelf_emit_note_fdo_package_metadata);
+ ldelf_emit_note_fdo_package_metadata = NULL;
+ }
}
get_elf_backend_data (link_info.output_bfd)->setup_gnu_properties (&link_info);
@@ -1501,6 +1517,121 @@ ldelf_setup_build_id (bfd *ibfd)
return false;
}
+static bool
+write_package_metadata (bfd *abfd)
+{
+ struct elf_obj_tdata *t = elf_tdata (abfd);
+ const char *json;
+ asection *asec;
+ Elf_Internal_Shdr *i_shdr;
+ unsigned char *contents, *json_bits;
+ bfd_size_type size;
+ file_ptr position;
+ Elf_External_Note *e_note;
+
+ json = t->o->package_metadata.json;
+ asec = t->o->package_metadata.sec;
+ if (bfd_is_abs_section (asec->output_section))
+ {
+ einfo (_("%P: warning: .note.package section discarded,"
+ " --package-metadata ignored\n"));
+ return true;
+ }
+ i_shdr = &elf_section_data (asec->output_section)->this_hdr;
+
+ if (i_shdr->contents == NULL)
+ {
+ if (asec->contents == NULL)
+ asec->contents = (unsigned char *) xmalloc (asec->size);
+ contents = asec->contents;
+ }
+ else
+ contents = i_shdr->contents + asec->output_offset;
+
+ e_note = (Elf_External_Note *) contents;
+ size = offsetof (Elf_External_Note, name[sizeof "FDO"]);
+ size = (size + 3) & -(bfd_size_type) 4;
+ json_bits = contents + size;
+ size = asec->size - size;
+
+ /* Clear the package metadata field. */
+ memset (json_bits, 0, size);
+
+ bfd_h_put_32 (abfd, sizeof "FDO", &e_note->namesz);
+ bfd_h_put_32 (abfd, size, &e_note->descsz);
+ bfd_h_put_32 (abfd, FDO_PACKAGING_METADATA, &e_note->type);
+ memcpy (e_note->name, "FDO", sizeof "FDO");
+ memcpy (json_bits, json, strlen(json));
+
+ position = i_shdr->sh_offset + asec->output_offset;
+ size = asec->size;
+ return (bfd_seek (abfd, position, SEEK_SET) == 0
+ && bfd_bwrite (contents, size, abfd) == size);
+}
+
+/* Make .note.package section.
+ https://systemd.io/ELF_PACKAGE_METADATA/ */
+
+bool
+ldelf_setup_package_metadata (bfd *ibfd)
+{
+ asection *s;
+ bfd_size_type size;
+ size_t json_length;
+ flagword flags;
+
+ /* If the option wasn't specified, silently return. */
+ if (!ldelf_emit_note_fdo_package_metadata)
+ return false;
+
+ /* The option was specified, but it's empty, log and return. */
+ json_length = strlen (ldelf_emit_note_fdo_package_metadata);
+ if (json_length == 0)
+ {
+ einfo (_("%P: warning: --package-metadata is empty, ignoring\n"));
+ return false;
+ }
+
+#ifdef HAVE_JANSSON
+ json_error_t json_error;
+ json_t *json = json_loads (ldelf_emit_note_fdo_package_metadata,
+ 0, &json_error);
+ if (!json)
+ {
+ einfo (_("%P: warning: --package-metadata=%s does not contain valid "
+ "JSON, ignoring: %s\n"),
+ ldelf_emit_note_fdo_package_metadata, json_error.text);
+ return false;
+ }
+ else
+ json_decref (json);
+#endif
+
+ size = offsetof (Elf_External_Note, name[sizeof "FDO"]);
+ size += json_length + 1;
+ size = (size + 3) & -(bfd_size_type) 4;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+ s = bfd_make_section_anyway_with_flags (ibfd, ".note.package",
+ flags);
+ if (s != NULL && bfd_set_section_alignment (s, 2))
+ {
+ struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd);
+ t->o->package_metadata.after_write_object_contents
+ = &write_package_metadata;
+ t->o->package_metadata.json = ldelf_emit_note_fdo_package_metadata;
+ t->o->package_metadata.sec = s;
+ elf_section_type (s) = SHT_NOTE;
+ s->size = size;
+ return true;
+ }
+
+ einfo (_("%P: warning: cannot create .note.package section,"
+ " --package-metadata ignored\n"));
+ return false;
+}
+
/* Look through an expression for an assignment statement. */
static void