libctf: link: BTF support

This is in two parts, one new API function and one change.

New API:
+int ctf_link_output_is_btf (ctf_dict_t *);

Changed API:
unsigned char *ctf_link_write (ctf_dict_t *, size_t *size,
-			      size_t threshold);
+			      size_t threshold, int *is_btf);

The idea here is that callers can call ctf_link_output_is_btf on a
ctf_link()ed (deduplicated) dict to tell whether a link will yield
BTF-compatible output before actually generating that output, so
they can e.g. decide whether to avoid trying to compress the dict
if they know it would be BTF otherwise (since compressing a dict
renders it non-BTF-compatible).

ctf_link_write() gains an optional is_btf output parameter that
reports whether the dict that was finally generated is actually BTF
after all, perhaps because the caller didn't call
ctf_link_output_is_btf or wants to be robust against possible future
changes that may add other reasons why a written-out dict can't be BTF
at the last minute.

These are simple wrappers around already-existing machinery earlier in
this series.
This commit is contained in:
Nick Alcock
2025-04-25 18:22:07 +01:00
parent 343de78445
commit 9ea8bea7f0
4 changed files with 67 additions and 11 deletions

View File

@@ -44,10 +44,10 @@
const char *
ctf_link_input_name (ctf_dict_t *fp)
{
if (fp->ctf_parent && fp->ctf_parent->ctf_cuname)
return fp->ctf_parent->ctf_cuname;
else if (fp->ctf_cuname)
return fp->ctf_cuname;
if (fp->ctf_parent && fp->ctf_parent->ctf_cu_name)
return fp->ctf_parent->ctf_cu_name;
else if (fp->ctf_cu_name)
return fp->ctf_cu_name;
else
return "(unnamed)";
}
@@ -1501,6 +1501,11 @@ ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym)
if (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC)
return 0;
/* If emitting BTF, there is no symtypetab so linker symbols are ignored. */
if (fp->ctf_serialize.cs_is_btf)
return 0;
/* Add the symbol to the in-flight list. */
if ((cid = malloc (sizeof (ctf_in_flight_dynsym_t))) == NULL)
@@ -1533,6 +1538,11 @@ ctf_link_shuffle_syms (ctf_dict_t *fp)
if (fp->ctf_stypes > 0)
return ctf_set_errno (fp, ECTF_RDONLY);
/* If emitting BTF, there is no symtypetab to shuffle. */
if (fp->ctf_serialize.cs_is_btf)
return 0;
if (!fp->ctf_dynsyms)
{
fp->ctf_dynsyms = ctf_dynhash_create (ctf_hash_string,
@@ -1732,6 +1742,28 @@ ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src
return dst;
}
/* Determine whether the archive that will be built from this linked dict is compatible
with pure BTF or would require CTF. (Other things may nonetheless require CTF, in
particular, compression.) */
int
ctf_link_output_is_btf (ctf_dict_t *fp)
{
/* Can't call when nothing has been linked yet. */
if (!fp->ctf_link_outputs)
return (ctf_set_errno (fp, EINVAL));
/* Cannot be BTF if child dicts are present. */
if (ctf_dynhash_elements (fp->ctf_link_outputs) != 0)
return 0;
if (ctf_serialize_output_format (fp, 0) < 0)
return -1; /* errno is set for us. */
return fp->ctf_serialize.cs_is_btf;
}
typedef struct ctf_name_list_accum_cb_arg
{
char **names;
@@ -1863,9 +1895,12 @@ ctf_link_warn_outdated_inputs (ctf_dict_t *fp)
/* Write out a CTF archive (if there are per-CU CTF files) or a CTF file
(otherwise) into a new dynamically-allocated string, and return it.
Members with sizes above THRESHOLD are compressed. */
Members with sizes above THRESHOLD are compressed.
The optional arg IS_BTF is set to 1 if the written output is valid BTF
(no archives, no CTF-specific types). */
unsigned char *
ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold, int *is_btf)
{
ctf_name_list_accum_cb_arg_t arg;
char **names;
@@ -1894,11 +1929,18 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
}
}
if (is_btf)
*is_btf = 0;
/* No extra outputs? Just write a simple ctf_dict_t. */
if (arg.i == 0)
{
unsigned char *ret = ctf_write_mem (fp, size, threshold);
fp->ctf_flags &= ~LCTF_LINKING;
if (is_btf && fp->ctf_serialize.cs_is_btf)
*is_btf = 1;
return ret;
}