+
+/* We want to emit CTF early if and only if we are not targetting ELF with this
+ invocation. */
+
+int
+ldelf_emit_ctf_early (void)
+{
+ if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
+ return 0;
+ return 1;
+}
+
+/* Callbacks used to map from bfd types to libctf types, under libctf's
+ control. */
+
+struct ctf_strsym_iter_cb_arg
+{
+ struct elf_sym_strtab *syms;
+ bfd_size_type symcount;
+ struct elf_strtab_hash *symstrtab;
+ size_t next_i;
+ size_t next_idx;
+};
+
+/* Return strings from the strtab to libctf, one by one. Returns NULL when
+ iteration is complete. */
+
+static const char *
+ldelf_ctf_strtab_iter_cb (uint32_t *offset, void *arg_)
+{
+ bfd_size_type off;
+ const char *ret;
+
+ struct ctf_strsym_iter_cb_arg *arg =
+ (struct ctf_strsym_iter_cb_arg *) arg_;
+
+ /* There is no zeroth string. */
+ if (arg->next_i == 0)
+ arg->next_i = 1;
+
+ if (arg->next_i >= _bfd_elf_strtab_len (arg->symstrtab))
+ {
+ arg->next_i = 0;
+ return NULL;
+ }
+
+ ret = _bfd_elf_strtab_str (arg->symstrtab, arg->next_i++, &off);
+ *offset = off;
+
+ /* If we've overflowed, we cannot share any further strings: the CTF
+ format cannot encode strings with such high offsets. */
+ if (*offset != off)
+ return NULL;
+
+ return ret;
+}
+
+/* Return symbols from the symbol table to libctf, one by one. We assume (and
+ assert) that the symbols in the elf_link_hash_table are in strictly ascending
+ order, and that none will be added in between existing ones. Returns NULL
+ when iteration is complete. */
+
+static struct ctf_link_sym *
+ldelf_ctf_symbols_iter_cb (struct ctf_link_sym *dest,
+ void *arg_)
+{
+ struct ctf_strsym_iter_cb_arg *arg =
+ (struct ctf_strsym_iter_cb_arg *) arg_;
+
+ if (arg->next_i > arg->symcount)
+ {
+ arg->next_i = 0;
+ arg->next_idx = 0;
+ return NULL;
+ }
+
+ ASSERT (arg->syms[arg->next_i].dest_index == arg->next_idx);
+ dest->st_name = _bfd_elf_strtab_str (arg->symstrtab, arg->next_i, NULL);
+ dest->st_shndx = arg->syms[arg->next_i].sym.st_shndx;
+ dest->st_type = ELF_ST_TYPE (arg->syms[arg->next_i].sym.st_info);
+ dest->st_value = arg->syms[arg->next_i].sym.st_value;
+ arg->next_i++;
+ return dest;
+}
+
+void
+ldelf_examine_strtab_for_ctf
+ (struct ctf_file *ctf_output, struct elf_sym_strtab *syms,
+ bfd_size_type symcount, struct elf_strtab_hash *symstrtab)
+{
+ struct ctf_strsym_iter_cb_arg args = { syms, symcount, symstrtab,
+ 0, 0 };
+ if (!ctf_output)
+ return;
+
+ if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+ && !bfd_link_relocatable (&link_info))
+ {
+ if (ctf_link_add_strtab (ctf_output, ldelf_ctf_strtab_iter_cb,
+ &args) < 0)
+ einfo (_("%F%P: warning: CTF strtab association failed; strings will "
+ "not be shared: %s\n"),
+ ctf_errmsg (ctf_errno (ctf_output)));
+
+ if (ctf_link_shuffle_syms (ctf_output, ldelf_ctf_symbols_iter_cb,
+ &args) < 0)
+ einfo (_("%F%P: warning: CTF symbol shuffling failed; slight space "
+ "cost: %s\n"), ctf_errmsg (ctf_errno (ctf_output)));
+ }
+}