diff mbox series

[dwarves,2/2] btf_encoder: add "distilled_base" BTF feature to split BTF generation

Message ID 20240729111317.140816-3-alan.maguire@oracle.com (mailing list archive)
State Not Applicable
Headers show
Series add distilled base BTF support to pahole | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Alan Maguire July 29, 2024, 11:13 a.m. UTC
Adding "distilled_base" to --btf_features when generating split BTF will
create split and .BTF.base BTF - the latter allows us to map references
from split BTF to base BTF, even if that base BTF has changed.  It does
this by providing just enough information about the base types in the
.BTF.base section. See [1] for more.

One note - with non-embedded libbpf, we need to guard against versions
of libbpf (<1.5) which do not have btf__distill_base(); in such a case,
silently skip distillation in line with other unrecognized BTF features.

[1] https://lore.kernel.org/bpf/20240613095014.357981-1-alan.maguire@oracle.com/

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 btf_encoder.c      | 50 ++++++++++++++++++++++++++++++++++------------
 dwarves.h          |  1 +
 man-pages/pahole.1 |  4 ++++
 pahole.c           |  1 +
 4 files changed, 43 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/btf_encoder.c b/btf_encoder.c
index c2df2bc..b8b1adb 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -93,7 +93,8 @@  struct btf_encoder {
 			  gen_floats,
 			  skip_encoding_decl_tag,
 			  tag_kfuncs,
-			  is_rel;
+			  is_rel,
+			  gen_distilled_base;
 	uint32_t	  array_index_id;
 	struct {
 		struct var_info *vars;
@@ -1284,9 +1285,9 @@  static int btf_encoder__write_raw_file(struct btf_encoder *encoder)
 	return err;
 }
 
-static int btf_encoder__write_elf(struct btf_encoder *encoder)
+static int btf_encoder__write_elf(struct btf_encoder *encoder, const struct btf *btf,
+				  const char *btf_secname)
 {
-	struct btf *btf = encoder->btf;
 	const char *filename = encoder->filename;
 	GElf_Shdr shdr_mem, *shdr;
 	Elf_Data *btf_data = NULL;
@@ -1326,7 +1327,7 @@  static int btf_encoder__write_elf(struct btf_encoder *encoder)
 		if (shdr == NULL)
 			continue;
 		char *secname = elf_strptr(elf, strndx, shdr->sh_name);
-		if (strcmp(secname, ".BTF") == 0) {
+		if (strcmp(secname, btf_secname) == 0) {
 			btf_data = elf_getdata(scn, btf_data);
 			break;
 		}
@@ -1370,11 +1371,11 @@  static int btf_encoder__write_elf(struct btf_encoder *encoder)
 			goto unlink;
 		}
 
-		snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
-			 llvm_objcopy, tmp_fn, filename);
+		snprintf(cmd, sizeof(cmd), "%s --add-section %s=%s %s",
+			 llvm_objcopy, btf_secname, tmp_fn, filename);
 		if (system(cmd)) {
-			fprintf(stderr, "%s: failed to add .BTF section to '%s': %d!\n",
-				__func__, filename, errno);
+			fprintf(stderr, "%s: failed to add %s section to '%s': %d!\n",
+				__func__, btf_secname, filename, errno);
 			goto unlink;
 		}
 
@@ -1755,12 +1756,34 @@  int btf_encoder__encode(struct btf_encoder *encoder)
 		fprintf(stderr, "%s: btf__dedup failed!\n", __func__);
 		return -1;
 	}
-
-	if (encoder->raw_output)
+	if (encoder->raw_output) {
 		err = btf_encoder__write_raw_file(encoder);
-	else
-		err = btf_encoder__write_elf(encoder);
-
+	} else {
+		/* non-embedded libbpf may not have btf__distill_base() or a
+		 * definition of BTF_BASE_ELF_SEC, so conditionally compile
+		 * distillation code.  Like other --btf_features, it will
+		 * silently ignore the feature request if libbpf does not
+		 * support it.
+		 */
+#if LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 5
+		if (encoder->gen_distilled_base) {
+			struct btf *btf = NULL, *distilled_base = NULL;
+
+			if (btf__distill_base(encoder->btf, &distilled_base, &btf) < 0) {
+				fprintf(stderr, "could not generate distilled base BTF: %s\n",
+					strerror(errno));
+				return -1;
+			}
+			err = btf_encoder__write_elf(encoder, btf, BTF_ELF_SEC);
+			if (!err)
+				err = btf_encoder__write_elf(encoder, distilled_base, BTF_BASE_ELF_SEC);
+			btf__free(btf);
+			btf__free(distilled_base);
+			return err;
+		}
+#endif
+		err = btf_encoder__write_elf(encoder, encoder->btf, BTF_ELF_SEC);
+	}
 	return err;
 }
 
@@ -2037,6 +2060,7 @@  struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		encoder->skip_encoding_vars = conf_load->skip_encoding_btf_vars;
 		encoder->skip_encoding_decl_tag	 = conf_load->skip_encoding_btf_decl_tag;
 		encoder->tag_kfuncs	 = conf_load->btf_decl_tag_kfuncs;
+		encoder->gen_distilled_base = conf_load->btf_gen_distilled_base;
 		encoder->verbose	 = verbose;
 		encoder->has_index_type  = false;
 		encoder->need_index_type = false;
diff --git a/dwarves.h b/dwarves.h
index f5ae79f..ad26951 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -95,6 +95,7 @@  struct conf_load {
 	bool			btf_encode_force;
 	bool			reproducible_build;
 	bool			btf_decl_tag_kfuncs;
+	bool			btf_gen_distilled_base;
 	uint8_t			hashtable_bits;
 	uint8_t			max_hashtable_bits;
 	uint16_t		kabi_prefix_len;
diff --git a/man-pages/pahole.1 b/man-pages/pahole.1
index f060593..2f623b4 100644
--- a/man-pages/pahole.1
+++ b/man-pages/pahole.1
@@ -317,6 +317,10 @@  Supported non-standard features (not enabled for 'default')
 	                   without this parallel BTF encoding can result in
 	                   inconsistent BTF ids.
 	decl_tag_kfuncs    Inject a BTF_KIND_DECL_TAG for each discovered kfunc.
+	distilled_base     For split BTF, generate a distilled version of
+	                   the associated base BTF to support later relocation
+	                   of split BTF with a possibly changed base, storing
+	                   it in a .BTF.base ELF section.
 .fi
 
 So for example, specifying \-\-btf_encode=var,enum64 will result in a BTF encoding that (as well as encoding basic BTF information) will contain variables and enum64 values.
diff --git a/pahole.c b/pahole.c
index 954498d..fdb65d4 100644
--- a/pahole.c
+++ b/pahole.c
@@ -1291,6 +1291,7 @@  struct btf_feature {
 	BTF_DEFAULT_FEATURE(consistent_func, skip_encoding_btf_inconsistent_proto, false),
 	BTF_DEFAULT_FEATURE(decl_tag_kfuncs, btf_decl_tag_kfuncs, false),
 	BTF_NON_DEFAULT_FEATURE(reproducible_build, reproducible_build, false),
+	BTF_NON_DEFAULT_FEATURE(distilled_base, btf_gen_distilled_base, false),
 };
 
 #define BTF_MAX_FEATURE_STR	1024