From: Nick Alcock Date: Fri, 25 Apr 2025 17:22:07 +0000 (+0100) Subject: libctf: link: BTF support X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9ea8bea7f0901b1eb6464aa1fcfb734945df08e1;p=thirdparty%2Fbinutils-gdb.git 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. --- diff --git a/include/ctf-api.h b/include/ctf-api.h index e9fadefa678..3db50062f14 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -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 diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index d029db52f7e..e0145bdd4e6 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -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); diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index b3092fce465..f552cacca46 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -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; } diff --git a/libctf/libctf.ver b/libctf/libctf.ver index 3ad5176a141..1d0ddc403b1 100644 --- a/libctf/libctf.ver +++ b/libctf/libctf.ver @@ -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;