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

@@ -1117,7 +1117,10 @@ extern int ctf_write_suppress_kind (ctf_dict_t *fp, int kind, int prohibited);
object files into a single .ctf section which is an archive possibly
containing members containing types whose names collide across multiple
compilation units, but they are usable by other programs as well and are not
private to the linker. */
private to the linker.
They should be called in the order they appear below, though some are
optional. */
/* Add a CTF archive to the link with a given NAME (usually the name of the
containing object file). The dict added to is usually a new dict created
@@ -1136,7 +1139,7 @@ extern int ctf_link_add_ctf (ctf_dict_t *, ctf_archive_t *, const char *name);
extern int ctf_link (ctf_dict_t *, int flags);
/* Symtab linker handling, called after ctf_link to set up the symbol type
information used by ctf_*_lookup_symbol. */
information used by ctf_*_lookup_symbol. Optional. */
/* Add strings to the link from the ELF string table, repeatedly calling
ADD_STRING to add each string and its corresponding offset in turn. */
@@ -1153,19 +1156,28 @@ extern int ctf_link_add_strtab (ctf_dict_t *,
extern int ctf_link_add_linker_symbol (ctf_dict_t *, ctf_link_sym_t *);
/* Impose an ordering on symbols, as defined by the strtab and symbol
added by earlier calls to the above two functions. */
added by earlier calls to the above two functions. Optional. */
extern int ctf_link_shuffle_syms (ctf_dict_t *);
/* Determine the file format of the dict that will be written out after the
calls above is compatible with pure BTF or would require CTF. (Other things
may nonetheless require CTF, in particular, compression.) */
extern int ctf_link_output_is_btf (ctf_dict_t *);
/* Return the serialized form of this ctf_linked dict as a new
dynamically-allocated string, compressed if size over THRESHOLD.
May be a CTF dict or a CTF archive (this library mostly papers over the
differences so you can open both the same way, treat both as ctf_archive_t
and so on). */
and so on).
If IS_BTF is set on return, the output is BTF-compatible and can be stored
in a .BTF section. */
extern unsigned char *ctf_link_write (ctf_dict_t *, size_t *size,
size_t threshold);
size_t threshold, int *is_btf);
/* Specialist linker functions. These functions are not used by ld, but can be
used by other programs making use of the linker machinery for other purposes

View File

@@ -793,6 +793,7 @@ extern void ctf_str_purge_refs (ctf_dict_t *fp);
extern void ctf_str_rollback (ctf_dict_t *, ctf_snapshot_id_t);
extern const ctf_strs_writable_t *ctf_str_write_strtab (ctf_dict_t *);
extern int ctf_serialize_output_format (ctf_dict_t *fp, int force_ctf);
extern int ctf_preserialize (ctf_dict_t *fp, int force_ctf);
extern void ctf_depreserialize (ctf_dict_t *fp);

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;
}

View File

@@ -201,6 +201,7 @@ LIBCTF_2.0 {
ctf_link;
ctf_link_add_strtab;
ctf_link_shuffle_syms;
ctf_link_output_is_btf;
ctf_link_write;
ctf_link_add_linker_symbol;