xref: /kernel/linux/linux-6.6/tools/bpf/bpftool/gen.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2019 Facebook */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#ifndef _GNU_SOURCE
562306a36Sopenharmony_ci#define _GNU_SOURCE
662306a36Sopenharmony_ci#endif
762306a36Sopenharmony_ci#include <ctype.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <fcntl.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <stdbool.h>
1262306a36Sopenharmony_ci#include <stdio.h>
1362306a36Sopenharmony_ci#include <string.h>
1462306a36Sopenharmony_ci#include <unistd.h>
1562306a36Sopenharmony_ci#include <bpf/bpf.h>
1662306a36Sopenharmony_ci#include <bpf/libbpf.h>
1762306a36Sopenharmony_ci#include <bpf/libbpf_internal.h>
1862306a36Sopenharmony_ci#include <sys/types.h>
1962306a36Sopenharmony_ci#include <sys/stat.h>
2062306a36Sopenharmony_ci#include <sys/mman.h>
2162306a36Sopenharmony_ci#include <bpf/btf.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "json_writer.h"
2462306a36Sopenharmony_ci#include "main.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define MAX_OBJ_NAME_LEN 64
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void sanitize_identifier(char *name)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	int i;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	for (i = 0; name[i]; i++)
3362306a36Sopenharmony_ci		if (!isalnum(name[i]) && name[i] != '_')
3462306a36Sopenharmony_ci			name[i] = '_';
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic bool str_has_prefix(const char *str, const char *prefix)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return strncmp(str, prefix, strlen(prefix)) == 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic bool str_has_suffix(const char *str, const char *suffix)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	size_t i, n1 = strlen(str), n2 = strlen(suffix);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (n1 < n2)
4762306a36Sopenharmony_ci		return false;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	for (i = 0; i < n2; i++) {
5062306a36Sopenharmony_ci		if (str[n1 - i - 1] != suffix[n2 - i - 1])
5162306a36Sopenharmony_ci			return false;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return true;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void get_obj_name(char *name, const char *file)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	/* Using basename() GNU version which doesn't modify arg. */
6062306a36Sopenharmony_ci	strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1);
6162306a36Sopenharmony_ci	name[MAX_OBJ_NAME_LEN - 1] = '\0';
6262306a36Sopenharmony_ci	if (str_has_suffix(name, ".o"))
6362306a36Sopenharmony_ci		name[strlen(name) - 2] = '\0';
6462306a36Sopenharmony_ci	sanitize_identifier(name);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void get_header_guard(char *guard, const char *obj_name, const char *suffix)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int i;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	sprintf(guard, "__%s_%s__", obj_name, suffix);
7262306a36Sopenharmony_ci	for (i = 0; guard[i]; i++)
7362306a36Sopenharmony_ci		guard[i] = toupper(guard[i]);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic bool get_map_ident(const struct bpf_map *map, char *buf, size_t buf_sz)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	static const char *sfxs[] = { ".data", ".rodata", ".bss", ".kconfig" };
7962306a36Sopenharmony_ci	const char *name = bpf_map__name(map);
8062306a36Sopenharmony_ci	int i, n;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (!bpf_map__is_internal(map)) {
8362306a36Sopenharmony_ci		snprintf(buf, buf_sz, "%s", name);
8462306a36Sopenharmony_ci		return true;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for  (i = 0, n = ARRAY_SIZE(sfxs); i < n; i++) {
8862306a36Sopenharmony_ci		const char *sfx = sfxs[i], *p;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		p = strstr(name, sfx);
9162306a36Sopenharmony_ci		if (p) {
9262306a36Sopenharmony_ci			snprintf(buf, buf_sz, "%s", p + 1);
9362306a36Sopenharmony_ci			sanitize_identifier(buf);
9462306a36Sopenharmony_ci			return true;
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return false;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic bool get_datasec_ident(const char *sec_name, char *buf, size_t buf_sz)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	static const char *pfxs[] = { ".data", ".rodata", ".bss", ".kconfig" };
10462306a36Sopenharmony_ci	int i, n;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	for  (i = 0, n = ARRAY_SIZE(pfxs); i < n; i++) {
10762306a36Sopenharmony_ci		const char *pfx = pfxs[i];
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		if (str_has_prefix(sec_name, pfx)) {
11062306a36Sopenharmony_ci			snprintf(buf, buf_sz, "%s", sec_name + 1);
11162306a36Sopenharmony_ci			sanitize_identifier(buf);
11262306a36Sopenharmony_ci			return true;
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return false;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	vprintf(fmt, args);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int codegen_datasec_def(struct bpf_object *obj,
12562306a36Sopenharmony_ci			       struct btf *btf,
12662306a36Sopenharmony_ci			       struct btf_dump *d,
12762306a36Sopenharmony_ci			       const struct btf_type *sec,
12862306a36Sopenharmony_ci			       const char *obj_name)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	const char *sec_name = btf__name_by_offset(btf, sec->name_off);
13162306a36Sopenharmony_ci	const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec);
13262306a36Sopenharmony_ci	int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec);
13362306a36Sopenharmony_ci	char var_ident[256], sec_ident[256];
13462306a36Sopenharmony_ci	bool strip_mods = false;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!get_datasec_ident(sec_name, sec_ident, sizeof(sec_ident)))
13762306a36Sopenharmony_ci		return 0;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (strcmp(sec_name, ".kconfig") != 0)
14062306a36Sopenharmony_ci		strip_mods = true;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	printf("	struct %s__%s {\n", obj_name, sec_ident);
14362306a36Sopenharmony_ci	for (i = 0; i < vlen; i++, sec_var++) {
14462306a36Sopenharmony_ci		const struct btf_type *var = btf__type_by_id(btf, sec_var->type);
14562306a36Sopenharmony_ci		const char *var_name = btf__name_by_offset(btf, var->name_off);
14662306a36Sopenharmony_ci		DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,
14762306a36Sopenharmony_ci			.field_name = var_ident,
14862306a36Sopenharmony_ci			.indent_level = 2,
14962306a36Sopenharmony_ci			.strip_mods = strip_mods,
15062306a36Sopenharmony_ci		);
15162306a36Sopenharmony_ci		int need_off = sec_var->offset, align_off, align;
15262306a36Sopenharmony_ci		__u32 var_type_id = var->type;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		/* static variables are not exposed through BPF skeleton */
15562306a36Sopenharmony_ci		if (btf_var(var)->linkage == BTF_VAR_STATIC)
15662306a36Sopenharmony_ci			continue;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		if (off > need_off) {
15962306a36Sopenharmony_ci			p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n",
16062306a36Sopenharmony_ci			      sec_name, i, need_off, off);
16162306a36Sopenharmony_ci			return -EINVAL;
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		align = btf__align_of(btf, var->type);
16562306a36Sopenharmony_ci		if (align <= 0) {
16662306a36Sopenharmony_ci			p_err("Failed to determine alignment of variable '%s': %d",
16762306a36Sopenharmony_ci			      var_name, align);
16862306a36Sopenharmony_ci			return -EINVAL;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci		/* Assume 32-bit architectures when generating data section
17162306a36Sopenharmony_ci		 * struct memory layout. Given bpftool can't know which target
17262306a36Sopenharmony_ci		 * host architecture it's emitting skeleton for, we need to be
17362306a36Sopenharmony_ci		 * conservative and assume 32-bit one to ensure enough padding
17462306a36Sopenharmony_ci		 * bytes are generated for pointer and long types. This will
17562306a36Sopenharmony_ci		 * still work correctly for 64-bit architectures, because in
17662306a36Sopenharmony_ci		 * the worst case we'll generate unnecessary padding field,
17762306a36Sopenharmony_ci		 * which on 64-bit architectures is not strictly necessary and
17862306a36Sopenharmony_ci		 * would be handled by natural 8-byte alignment. But it still
17962306a36Sopenharmony_ci		 * will be a correct memory layout, based on recorded offsets
18062306a36Sopenharmony_ci		 * in BTF.
18162306a36Sopenharmony_ci		 */
18262306a36Sopenharmony_ci		if (align > 4)
18362306a36Sopenharmony_ci			align = 4;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		align_off = (off + align - 1) / align * align;
18662306a36Sopenharmony_ci		if (align_off != need_off) {
18762306a36Sopenharmony_ci			printf("\t\tchar __pad%d[%d];\n",
18862306a36Sopenharmony_ci			       pad_cnt, need_off - off);
18962306a36Sopenharmony_ci			pad_cnt++;
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		/* sanitize variable name, e.g., for static vars inside
19362306a36Sopenharmony_ci		 * a function, it's name is '<function name>.<variable name>',
19462306a36Sopenharmony_ci		 * which we'll turn into a '<function name>_<variable name>'
19562306a36Sopenharmony_ci		 */
19662306a36Sopenharmony_ci		var_ident[0] = '\0';
19762306a36Sopenharmony_ci		strncat(var_ident, var_name, sizeof(var_ident) - 1);
19862306a36Sopenharmony_ci		sanitize_identifier(var_ident);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		printf("\t\t");
20162306a36Sopenharmony_ci		err = btf_dump__emit_type_decl(d, var_type_id, &opts);
20262306a36Sopenharmony_ci		if (err)
20362306a36Sopenharmony_ci			return err;
20462306a36Sopenharmony_ci		printf(";\n");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		off = sec_var->offset + sec_var->size;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci	printf("	} *%s;\n", sec_ident);
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic const struct btf_type *find_type_for_map(struct btf *btf, const char *map_ident)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	int n = btf__type_cnt(btf), i;
21562306a36Sopenharmony_ci	char sec_ident[256];
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	for (i = 1; i < n; i++) {
21862306a36Sopenharmony_ci		const struct btf_type *t = btf__type_by_id(btf, i);
21962306a36Sopenharmony_ci		const char *name;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		if (!btf_is_datasec(t))
22262306a36Sopenharmony_ci			continue;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		name = btf__str_by_offset(btf, t->name_off);
22562306a36Sopenharmony_ci		if (!get_datasec_ident(name, sec_ident, sizeof(sec_ident)))
22662306a36Sopenharmony_ci			continue;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		if (strcmp(sec_ident, map_ident) == 0)
22962306a36Sopenharmony_ci			return t;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	return NULL;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic bool is_internal_mmapable_map(const struct bpf_map *map, char *buf, size_t sz)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	if (!bpf_map__is_internal(map) || !(bpf_map__map_flags(map) & BPF_F_MMAPABLE))
23762306a36Sopenharmony_ci		return false;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (!get_map_ident(map, buf, sz))
24062306a36Sopenharmony_ci		return false;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return true;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct btf *btf = bpf_object__btf(obj);
24862306a36Sopenharmony_ci	struct btf_dump *d;
24962306a36Sopenharmony_ci	struct bpf_map *map;
25062306a36Sopenharmony_ci	const struct btf_type *sec;
25162306a36Sopenharmony_ci	char map_ident[256];
25262306a36Sopenharmony_ci	int err = 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);
25562306a36Sopenharmony_ci	if (!d)
25662306a36Sopenharmony_ci		return -errno;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
25962306a36Sopenharmony_ci		/* only generate definitions for memory-mapped internal maps */
26062306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, map_ident, sizeof(map_ident)))
26162306a36Sopenharmony_ci			continue;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		sec = find_type_for_map(btf, map_ident);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		/* In some cases (e.g., sections like .rodata.cst16 containing
26662306a36Sopenharmony_ci		 * compiler allocated string constants only) there will be
26762306a36Sopenharmony_ci		 * special internal maps with no corresponding DATASEC BTF
26862306a36Sopenharmony_ci		 * type. In such case, generate empty structs for each such
26962306a36Sopenharmony_ci		 * map. It will still be memory-mapped and its contents
27062306a36Sopenharmony_ci		 * accessible from user-space through BPF skeleton.
27162306a36Sopenharmony_ci		 */
27262306a36Sopenharmony_ci		if (!sec) {
27362306a36Sopenharmony_ci			printf("	struct %s__%s {\n", obj_name, map_ident);
27462306a36Sopenharmony_ci			printf("	} *%s;\n", map_ident);
27562306a36Sopenharmony_ci		} else {
27662306a36Sopenharmony_ci			err = codegen_datasec_def(obj, btf, d, sec, obj_name);
27762306a36Sopenharmony_ci			if (err)
27862306a36Sopenharmony_ci				goto out;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ciout:
28462306a36Sopenharmony_ci	btf_dump__free(d);
28562306a36Sopenharmony_ci	return err;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic bool btf_is_ptr_to_func_proto(const struct btf *btf,
28962306a36Sopenharmony_ci				     const struct btf_type *v)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return btf_is_ptr(v) && btf_is_func_proto(btf__type_by_id(btf, v->type));
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int codegen_subskel_datasecs(struct bpf_object *obj, const char *obj_name)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct btf *btf = bpf_object__btf(obj);
29762306a36Sopenharmony_ci	struct btf_dump *d;
29862306a36Sopenharmony_ci	struct bpf_map *map;
29962306a36Sopenharmony_ci	const struct btf_type *sec, *var;
30062306a36Sopenharmony_ci	const struct btf_var_secinfo *sec_var;
30162306a36Sopenharmony_ci	int i, err = 0, vlen;
30262306a36Sopenharmony_ci	char map_ident[256], sec_ident[256];
30362306a36Sopenharmony_ci	bool strip_mods = false, needs_typeof = false;
30462306a36Sopenharmony_ci	const char *sec_name, *var_name;
30562306a36Sopenharmony_ci	__u32 var_type_id;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);
30862306a36Sopenharmony_ci	if (!d)
30962306a36Sopenharmony_ci		return -errno;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
31262306a36Sopenharmony_ci		/* only generate definitions for memory-mapped internal maps */
31362306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, map_ident, sizeof(map_ident)))
31462306a36Sopenharmony_ci			continue;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		sec = find_type_for_map(btf, map_ident);
31762306a36Sopenharmony_ci		if (!sec)
31862306a36Sopenharmony_ci			continue;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		sec_name = btf__name_by_offset(btf, sec->name_off);
32162306a36Sopenharmony_ci		if (!get_datasec_ident(sec_name, sec_ident, sizeof(sec_ident)))
32262306a36Sopenharmony_ci			continue;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		strip_mods = strcmp(sec_name, ".kconfig") != 0;
32562306a36Sopenharmony_ci		printf("	struct %s__%s {\n", obj_name, sec_ident);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		sec_var = btf_var_secinfos(sec);
32862306a36Sopenharmony_ci		vlen = btf_vlen(sec);
32962306a36Sopenharmony_ci		for (i = 0; i < vlen; i++, sec_var++) {
33062306a36Sopenharmony_ci			DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,
33162306a36Sopenharmony_ci				.indent_level = 2,
33262306a36Sopenharmony_ci				.strip_mods = strip_mods,
33362306a36Sopenharmony_ci				/* we'll print the name separately */
33462306a36Sopenharmony_ci				.field_name = "",
33562306a36Sopenharmony_ci			);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci			var = btf__type_by_id(btf, sec_var->type);
33862306a36Sopenharmony_ci			var_name = btf__name_by_offset(btf, var->name_off);
33962306a36Sopenharmony_ci			var_type_id = var->type;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci			/* static variables are not exposed through BPF skeleton */
34262306a36Sopenharmony_ci			if (btf_var(var)->linkage == BTF_VAR_STATIC)
34362306a36Sopenharmony_ci				continue;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci			/* The datasec member has KIND_VAR but we want the
34662306a36Sopenharmony_ci			 * underlying type of the variable (e.g. KIND_INT).
34762306a36Sopenharmony_ci			 */
34862306a36Sopenharmony_ci			var = skip_mods_and_typedefs(btf, var->type, NULL);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci			printf("\t\t");
35162306a36Sopenharmony_ci			/* Func and array members require special handling.
35262306a36Sopenharmony_ci			 * Instead of producing `typename *var`, they produce
35362306a36Sopenharmony_ci			 * `typeof(typename) *var`. This allows us to keep a
35462306a36Sopenharmony_ci			 * similar syntax where the identifier is just prefixed
35562306a36Sopenharmony_ci			 * by *, allowing us to ignore C declaration minutiae.
35662306a36Sopenharmony_ci			 */
35762306a36Sopenharmony_ci			needs_typeof = btf_is_array(var) || btf_is_ptr_to_func_proto(btf, var);
35862306a36Sopenharmony_ci			if (needs_typeof)
35962306a36Sopenharmony_ci				printf("typeof(");
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci			err = btf_dump__emit_type_decl(d, var_type_id, &opts);
36262306a36Sopenharmony_ci			if (err)
36362306a36Sopenharmony_ci				goto out;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci			if (needs_typeof)
36662306a36Sopenharmony_ci				printf(")");
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			printf(" *%s;\n", var_name);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci		printf("	} %s;\n", sec_ident);
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciout:
37462306a36Sopenharmony_ci	btf_dump__free(d);
37562306a36Sopenharmony_ci	return err;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void codegen(const char *template, ...)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	const char *src, *end;
38162306a36Sopenharmony_ci	int skip_tabs = 0, n;
38262306a36Sopenharmony_ci	char *s, *dst;
38362306a36Sopenharmony_ci	va_list args;
38462306a36Sopenharmony_ci	char c;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	n = strlen(template);
38762306a36Sopenharmony_ci	s = malloc(n + 1);
38862306a36Sopenharmony_ci	if (!s)
38962306a36Sopenharmony_ci		exit(-1);
39062306a36Sopenharmony_ci	src = template;
39162306a36Sopenharmony_ci	dst = s;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* find out "baseline" indentation to skip */
39462306a36Sopenharmony_ci	while ((c = *src++)) {
39562306a36Sopenharmony_ci		if (c == '\t') {
39662306a36Sopenharmony_ci			skip_tabs++;
39762306a36Sopenharmony_ci		} else if (c == '\n') {
39862306a36Sopenharmony_ci			break;
39962306a36Sopenharmony_ci		} else {
40062306a36Sopenharmony_ci			p_err("unrecognized character at pos %td in template '%s': '%c'",
40162306a36Sopenharmony_ci			      src - template - 1, template, c);
40262306a36Sopenharmony_ci			free(s);
40362306a36Sopenharmony_ci			exit(-1);
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	while (*src) {
40862306a36Sopenharmony_ci		/* skip baseline indentation tabs */
40962306a36Sopenharmony_ci		for (n = skip_tabs; n > 0; n--, src++) {
41062306a36Sopenharmony_ci			if (*src != '\t') {
41162306a36Sopenharmony_ci				p_err("not enough tabs at pos %td in template '%s'",
41262306a36Sopenharmony_ci				      src - template - 1, template);
41362306a36Sopenharmony_ci				free(s);
41462306a36Sopenharmony_ci				exit(-1);
41562306a36Sopenharmony_ci			}
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci		/* trim trailing whitespace */
41862306a36Sopenharmony_ci		end = strchrnul(src, '\n');
41962306a36Sopenharmony_ci		for (n = end - src; n > 0 && isspace(src[n - 1]); n--)
42062306a36Sopenharmony_ci			;
42162306a36Sopenharmony_ci		memcpy(dst, src, n);
42262306a36Sopenharmony_ci		dst += n;
42362306a36Sopenharmony_ci		if (*end)
42462306a36Sopenharmony_ci			*dst++ = '\n';
42562306a36Sopenharmony_ci		src = *end ? end + 1 : end;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci	*dst++ = '\0';
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* print out using adjusted template */
43062306a36Sopenharmony_ci	va_start(args, template);
43162306a36Sopenharmony_ci	n = vprintf(s, args);
43262306a36Sopenharmony_ci	va_end(args);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	free(s);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic void print_hex(const char *data, int data_sz)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	int i, len;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	for (i = 0, len = 0; i < data_sz; i++) {
44262306a36Sopenharmony_ci		int w = data[i] ? 4 : 2;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		len += w;
44562306a36Sopenharmony_ci		if (len > 78) {
44662306a36Sopenharmony_ci			printf("\\\n");
44762306a36Sopenharmony_ci			len = w;
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci		if (!data[i])
45062306a36Sopenharmony_ci			printf("\\0");
45162306a36Sopenharmony_ci		else
45262306a36Sopenharmony_ci			printf("\\x%02x", (unsigned char)data[i]);
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic size_t bpf_map_mmap_sz(const struct bpf_map *map)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	long page_sz = sysconf(_SC_PAGE_SIZE);
45962306a36Sopenharmony_ci	size_t map_sz;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);
46262306a36Sopenharmony_ci	map_sz = roundup(map_sz, page_sz);
46362306a36Sopenharmony_ci	return map_sz;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci/* Emit type size asserts for all top-level fields in memory-mapped internal maps. */
46762306a36Sopenharmony_cistatic void codegen_asserts(struct bpf_object *obj, const char *obj_name)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct btf *btf = bpf_object__btf(obj);
47062306a36Sopenharmony_ci	struct bpf_map *map;
47162306a36Sopenharmony_ci	struct btf_var_secinfo *sec_var;
47262306a36Sopenharmony_ci	int i, vlen;
47362306a36Sopenharmony_ci	const struct btf_type *sec;
47462306a36Sopenharmony_ci	char map_ident[256], var_ident[256];
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (!btf)
47762306a36Sopenharmony_ci		return;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	codegen("\
48062306a36Sopenharmony_ci		\n\
48162306a36Sopenharmony_ci		__attribute__((unused)) static void			    \n\
48262306a36Sopenharmony_ci		%1$s__assert(struct %1$s *s __attribute__((unused)))	    \n\
48362306a36Sopenharmony_ci		{							    \n\
48462306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
48562306a36Sopenharmony_ci		#define _Static_assert static_assert			    \n\
48662306a36Sopenharmony_ci		#endif							    \n\
48762306a36Sopenharmony_ci		", obj_name);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
49062306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, map_ident, sizeof(map_ident)))
49162306a36Sopenharmony_ci			continue;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		sec = find_type_for_map(btf, map_ident);
49462306a36Sopenharmony_ci		if (!sec) {
49562306a36Sopenharmony_ci			/* best effort, couldn't find the type for this map */
49662306a36Sopenharmony_ci			continue;
49762306a36Sopenharmony_ci		}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		sec_var = btf_var_secinfos(sec);
50062306a36Sopenharmony_ci		vlen =  btf_vlen(sec);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		for (i = 0; i < vlen; i++, sec_var++) {
50362306a36Sopenharmony_ci			const struct btf_type *var = btf__type_by_id(btf, sec_var->type);
50462306a36Sopenharmony_ci			const char *var_name = btf__name_by_offset(btf, var->name_off);
50562306a36Sopenharmony_ci			long var_size;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci			/* static variables are not exposed through BPF skeleton */
50862306a36Sopenharmony_ci			if (btf_var(var)->linkage == BTF_VAR_STATIC)
50962306a36Sopenharmony_ci				continue;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci			var_size = btf__resolve_size(btf, var->type);
51262306a36Sopenharmony_ci			if (var_size < 0)
51362306a36Sopenharmony_ci				continue;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci			var_ident[0] = '\0';
51662306a36Sopenharmony_ci			strncat(var_ident, var_name, sizeof(var_ident) - 1);
51762306a36Sopenharmony_ci			sanitize_identifier(var_ident);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci			printf("\t_Static_assert(sizeof(s->%s->%s) == %ld, \"unexpected size of '%s'\");\n",
52062306a36Sopenharmony_ci			       map_ident, var_ident, var_size, var_ident);
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	codegen("\
52462306a36Sopenharmony_ci		\n\
52562306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
52662306a36Sopenharmony_ci		#undef _Static_assert					    \n\
52762306a36Sopenharmony_ci		#endif							    \n\
52862306a36Sopenharmony_ci		}							    \n\
52962306a36Sopenharmony_ci		");
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct bpf_program *prog;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
53762306a36Sopenharmony_ci		const char *tp_name;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		codegen("\
54062306a36Sopenharmony_ci			\n\
54162306a36Sopenharmony_ci			\n\
54262306a36Sopenharmony_ci			static inline int					    \n\
54362306a36Sopenharmony_ci			%1$s__%2$s__attach(struct %1$s *skel)			    \n\
54462306a36Sopenharmony_ci			{							    \n\
54562306a36Sopenharmony_ci				int prog_fd = skel->progs.%2$s.prog_fd;		    \n\
54662306a36Sopenharmony_ci			", obj_name, bpf_program__name(prog));
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		switch (bpf_program__type(prog)) {
54962306a36Sopenharmony_ci		case BPF_PROG_TYPE_RAW_TRACEPOINT:
55062306a36Sopenharmony_ci			tp_name = strchr(bpf_program__section_name(prog), '/') + 1;
55162306a36Sopenharmony_ci			printf("\tint fd = skel_raw_tracepoint_open(\"%s\", prog_fd);\n", tp_name);
55262306a36Sopenharmony_ci			break;
55362306a36Sopenharmony_ci		case BPF_PROG_TYPE_TRACING:
55462306a36Sopenharmony_ci		case BPF_PROG_TYPE_LSM:
55562306a36Sopenharmony_ci			if (bpf_program__expected_attach_type(prog) == BPF_TRACE_ITER)
55662306a36Sopenharmony_ci				printf("\tint fd = skel_link_create(prog_fd, 0, BPF_TRACE_ITER);\n");
55762306a36Sopenharmony_ci			else
55862306a36Sopenharmony_ci				printf("\tint fd = skel_raw_tracepoint_open(NULL, prog_fd);\n");
55962306a36Sopenharmony_ci			break;
56062306a36Sopenharmony_ci		default:
56162306a36Sopenharmony_ci			printf("\tint fd = ((void)prog_fd, 0); /* auto-attach not supported */\n");
56262306a36Sopenharmony_ci			break;
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci		codegen("\
56562306a36Sopenharmony_ci			\n\
56662306a36Sopenharmony_ci										    \n\
56762306a36Sopenharmony_ci				if (fd > 0)					    \n\
56862306a36Sopenharmony_ci					skel->links.%1$s_fd = fd;		    \n\
56962306a36Sopenharmony_ci				return fd;					    \n\
57062306a36Sopenharmony_ci			}							    \n\
57162306a36Sopenharmony_ci			", bpf_program__name(prog));
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	codegen("\
57562306a36Sopenharmony_ci		\n\
57662306a36Sopenharmony_ci									    \n\
57762306a36Sopenharmony_ci		static inline int					    \n\
57862306a36Sopenharmony_ci		%1$s__attach(struct %1$s *skel)				    \n\
57962306a36Sopenharmony_ci		{							    \n\
58062306a36Sopenharmony_ci			int ret = 0;					    \n\
58162306a36Sopenharmony_ci									    \n\
58262306a36Sopenharmony_ci		", obj_name);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
58562306a36Sopenharmony_ci		codegen("\
58662306a36Sopenharmony_ci			\n\
58762306a36Sopenharmony_ci				ret = ret < 0 ? ret : %1$s__%2$s__attach(skel);   \n\
58862306a36Sopenharmony_ci			", obj_name, bpf_program__name(prog));
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	codegen("\
59262306a36Sopenharmony_ci		\n\
59362306a36Sopenharmony_ci			return ret < 0 ? ret : 0;			    \n\
59462306a36Sopenharmony_ci		}							    \n\
59562306a36Sopenharmony_ci									    \n\
59662306a36Sopenharmony_ci		static inline void					    \n\
59762306a36Sopenharmony_ci		%1$s__detach(struct %1$s *skel)				    \n\
59862306a36Sopenharmony_ci		{							    \n\
59962306a36Sopenharmony_ci		", obj_name);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
60262306a36Sopenharmony_ci		codegen("\
60362306a36Sopenharmony_ci			\n\
60462306a36Sopenharmony_ci				skel_closenz(skel->links.%1$s_fd);	    \n\
60562306a36Sopenharmony_ci			", bpf_program__name(prog));
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	codegen("\
60962306a36Sopenharmony_ci		\n\
61062306a36Sopenharmony_ci		}							    \n\
61162306a36Sopenharmony_ci		");
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic void codegen_destroy(struct bpf_object *obj, const char *obj_name)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct bpf_program *prog;
61762306a36Sopenharmony_ci	struct bpf_map *map;
61862306a36Sopenharmony_ci	char ident[256];
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	codegen("\
62162306a36Sopenharmony_ci		\n\
62262306a36Sopenharmony_ci		static void						    \n\
62362306a36Sopenharmony_ci		%1$s__destroy(struct %1$s *skel)			    \n\
62462306a36Sopenharmony_ci		{							    \n\
62562306a36Sopenharmony_ci			if (!skel)					    \n\
62662306a36Sopenharmony_ci				return;					    \n\
62762306a36Sopenharmony_ci			%1$s__detach(skel);				    \n\
62862306a36Sopenharmony_ci		",
62962306a36Sopenharmony_ci		obj_name);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
63262306a36Sopenharmony_ci		codegen("\
63362306a36Sopenharmony_ci			\n\
63462306a36Sopenharmony_ci				skel_closenz(skel->progs.%1$s.prog_fd);	    \n\
63562306a36Sopenharmony_ci			", bpf_program__name(prog));
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
63962306a36Sopenharmony_ci		if (!get_map_ident(map, ident, sizeof(ident)))
64062306a36Sopenharmony_ci			continue;
64162306a36Sopenharmony_ci		if (bpf_map__is_internal(map) &&
64262306a36Sopenharmony_ci		    (bpf_map__map_flags(map) & BPF_F_MMAPABLE))
64362306a36Sopenharmony_ci			printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$zd);\n",
64462306a36Sopenharmony_ci			       ident, bpf_map_mmap_sz(map));
64562306a36Sopenharmony_ci		codegen("\
64662306a36Sopenharmony_ci			\n\
64762306a36Sopenharmony_ci				skel_closenz(skel->maps.%1$s.map_fd);	    \n\
64862306a36Sopenharmony_ci			", ident);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci	codegen("\
65162306a36Sopenharmony_ci		\n\
65262306a36Sopenharmony_ci			skel_free(skel);				    \n\
65362306a36Sopenharmony_ci		}							    \n\
65462306a36Sopenharmony_ci		",
65562306a36Sopenharmony_ci		obj_name);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);
66162306a36Sopenharmony_ci	struct bpf_map *map;
66262306a36Sopenharmony_ci	char ident[256];
66362306a36Sopenharmony_ci	int err = 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	err = bpf_object__gen_loader(obj, &opts);
66662306a36Sopenharmony_ci	if (err)
66762306a36Sopenharmony_ci		return err;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	err = bpf_object__load(obj);
67062306a36Sopenharmony_ci	if (err) {
67162306a36Sopenharmony_ci		p_err("failed to load object file");
67262306a36Sopenharmony_ci		goto out;
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci	/* If there was no error during load then gen_loader_opts
67562306a36Sopenharmony_ci	 * are populated with the loader program.
67662306a36Sopenharmony_ci	 */
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* finish generating 'struct skel' */
67962306a36Sopenharmony_ci	codegen("\
68062306a36Sopenharmony_ci		\n\
68162306a36Sopenharmony_ci		};							    \n\
68262306a36Sopenharmony_ci		", obj_name);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	codegen_attach_detach(obj, obj_name);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	codegen_destroy(obj, obj_name);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	codegen("\
69062306a36Sopenharmony_ci		\n\
69162306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
69262306a36Sopenharmony_ci		%1$s__open(void)					    \n\
69362306a36Sopenharmony_ci		{							    \n\
69462306a36Sopenharmony_ci			struct %1$s *skel;				    \n\
69562306a36Sopenharmony_ci									    \n\
69662306a36Sopenharmony_ci			skel = skel_alloc(sizeof(*skel));		    \n\
69762306a36Sopenharmony_ci			if (!skel)					    \n\
69862306a36Sopenharmony_ci				goto cleanup;				    \n\
69962306a36Sopenharmony_ci			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
70062306a36Sopenharmony_ci		",
70162306a36Sopenharmony_ci		obj_name, opts.data_sz);
70262306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
70362306a36Sopenharmony_ci		const void *mmap_data = NULL;
70462306a36Sopenharmony_ci		size_t mmap_size = 0;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, ident, sizeof(ident)))
70762306a36Sopenharmony_ci			continue;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		codegen("\
71062306a36Sopenharmony_ci		\n\
71162306a36Sopenharmony_ci			skel->%1$s = skel_prep_map_data((void *)\"\\	    \n\
71262306a36Sopenharmony_ci		", ident);
71362306a36Sopenharmony_ci		mmap_data = bpf_map__initial_value(map, &mmap_size);
71462306a36Sopenharmony_ci		print_hex(mmap_data, mmap_size);
71562306a36Sopenharmony_ci		codegen("\
71662306a36Sopenharmony_ci		\n\
71762306a36Sopenharmony_ci		\", %1$zd, %2$zd);					    \n\
71862306a36Sopenharmony_ci			if (!skel->%3$s)				    \n\
71962306a36Sopenharmony_ci				goto cleanup;				    \n\
72062306a36Sopenharmony_ci			skel->maps.%3$s.initial_value = (__u64) (long) skel->%3$s;\n\
72162306a36Sopenharmony_ci		", bpf_map_mmap_sz(map), mmap_size, ident);
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci	codegen("\
72462306a36Sopenharmony_ci		\n\
72562306a36Sopenharmony_ci			return skel;					    \n\
72662306a36Sopenharmony_ci		cleanup:						    \n\
72762306a36Sopenharmony_ci			%1$s__destroy(skel);				    \n\
72862306a36Sopenharmony_ci			return NULL;					    \n\
72962306a36Sopenharmony_ci		}							    \n\
73062306a36Sopenharmony_ci									    \n\
73162306a36Sopenharmony_ci		static inline int					    \n\
73262306a36Sopenharmony_ci		%1$s__load(struct %1$s *skel)				    \n\
73362306a36Sopenharmony_ci		{							    \n\
73462306a36Sopenharmony_ci			struct bpf_load_and_run_opts opts = {};		    \n\
73562306a36Sopenharmony_ci			int err;					    \n\
73662306a36Sopenharmony_ci									    \n\
73762306a36Sopenharmony_ci			opts.ctx = (struct bpf_loader_ctx *)skel;	    \n\
73862306a36Sopenharmony_ci			opts.data_sz = %2$d;				    \n\
73962306a36Sopenharmony_ci			opts.data = (void *)\"\\			    \n\
74062306a36Sopenharmony_ci		",
74162306a36Sopenharmony_ci		obj_name, opts.data_sz);
74262306a36Sopenharmony_ci	print_hex(opts.data, opts.data_sz);
74362306a36Sopenharmony_ci	codegen("\
74462306a36Sopenharmony_ci		\n\
74562306a36Sopenharmony_ci		\";							    \n\
74662306a36Sopenharmony_ci		");
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	codegen("\
74962306a36Sopenharmony_ci		\n\
75062306a36Sopenharmony_ci			opts.insns_sz = %d;				    \n\
75162306a36Sopenharmony_ci			opts.insns = (void *)\"\\			    \n\
75262306a36Sopenharmony_ci		",
75362306a36Sopenharmony_ci		opts.insns_sz);
75462306a36Sopenharmony_ci	print_hex(opts.insns, opts.insns_sz);
75562306a36Sopenharmony_ci	codegen("\
75662306a36Sopenharmony_ci		\n\
75762306a36Sopenharmony_ci		\";							    \n\
75862306a36Sopenharmony_ci			err = bpf_load_and_run(&opts);			    \n\
75962306a36Sopenharmony_ci			if (err < 0)					    \n\
76062306a36Sopenharmony_ci				return err;				    \n\
76162306a36Sopenharmony_ci		", obj_name);
76262306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
76362306a36Sopenharmony_ci		const char *mmap_flags;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, ident, sizeof(ident)))
76662306a36Sopenharmony_ci			continue;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		if (bpf_map__map_flags(map) & BPF_F_RDONLY_PROG)
76962306a36Sopenharmony_ci			mmap_flags = "PROT_READ";
77062306a36Sopenharmony_ci		else
77162306a36Sopenharmony_ci			mmap_flags = "PROT_READ | PROT_WRITE";
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		codegen("\
77462306a36Sopenharmony_ci		\n\
77562306a36Sopenharmony_ci			skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value,  \n\
77662306a36Sopenharmony_ci							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
77762306a36Sopenharmony_ci			if (!skel->%1$s)				    \n\
77862306a36Sopenharmony_ci				return -ENOMEM;				    \n\
77962306a36Sopenharmony_ci			",
78062306a36Sopenharmony_ci		       ident, bpf_map_mmap_sz(map), mmap_flags);
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci	codegen("\
78362306a36Sopenharmony_ci		\n\
78462306a36Sopenharmony_ci			return 0;					    \n\
78562306a36Sopenharmony_ci		}							    \n\
78662306a36Sopenharmony_ci									    \n\
78762306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
78862306a36Sopenharmony_ci		%1$s__open_and_load(void)				    \n\
78962306a36Sopenharmony_ci		{							    \n\
79062306a36Sopenharmony_ci			struct %1$s *skel;				    \n\
79162306a36Sopenharmony_ci									    \n\
79262306a36Sopenharmony_ci			skel = %1$s__open();				    \n\
79362306a36Sopenharmony_ci			if (!skel)					    \n\
79462306a36Sopenharmony_ci				return NULL;				    \n\
79562306a36Sopenharmony_ci			if (%1$s__load(skel)) {				    \n\
79662306a36Sopenharmony_ci				%1$s__destroy(skel);			    \n\
79762306a36Sopenharmony_ci				return NULL;				    \n\
79862306a36Sopenharmony_ci			}						    \n\
79962306a36Sopenharmony_ci			return skel;					    \n\
80062306a36Sopenharmony_ci		}							    \n\
80162306a36Sopenharmony_ci									    \n\
80262306a36Sopenharmony_ci		", obj_name);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	codegen_asserts(obj, obj_name);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	codegen("\
80762306a36Sopenharmony_ci		\n\
80862306a36Sopenharmony_ci									    \n\
80962306a36Sopenharmony_ci		#endif /* %s */						    \n\
81062306a36Sopenharmony_ci		",
81162306a36Sopenharmony_ci		header_guard);
81262306a36Sopenharmony_ci	err = 0;
81362306a36Sopenharmony_ciout:
81462306a36Sopenharmony_ci	return err;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic void
81862306a36Sopenharmony_cicodegen_maps_skeleton(struct bpf_object *obj, size_t map_cnt, bool mmaped)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct bpf_map *map;
82162306a36Sopenharmony_ci	char ident[256];
82262306a36Sopenharmony_ci	size_t i;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (!map_cnt)
82562306a36Sopenharmony_ci		return;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	codegen("\
82862306a36Sopenharmony_ci		\n\
82962306a36Sopenharmony_ci									\n\
83062306a36Sopenharmony_ci			/* maps */				    \n\
83162306a36Sopenharmony_ci			s->map_cnt = %zu;			    \n\
83262306a36Sopenharmony_ci			s->map_skel_sz = sizeof(*s->maps);	    \n\
83362306a36Sopenharmony_ci			s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);\n\
83462306a36Sopenharmony_ci			if (!s->maps) {				    \n\
83562306a36Sopenharmony_ci				err = -ENOMEM;			    \n\
83662306a36Sopenharmony_ci				goto err;			    \n\
83762306a36Sopenharmony_ci			}					    \n\
83862306a36Sopenharmony_ci		",
83962306a36Sopenharmony_ci		map_cnt
84062306a36Sopenharmony_ci	);
84162306a36Sopenharmony_ci	i = 0;
84262306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
84362306a36Sopenharmony_ci		if (!get_map_ident(map, ident, sizeof(ident)))
84462306a36Sopenharmony_ci			continue;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		codegen("\
84762306a36Sopenharmony_ci			\n\
84862306a36Sopenharmony_ci									\n\
84962306a36Sopenharmony_ci				s->maps[%zu].name = \"%s\";	    \n\
85062306a36Sopenharmony_ci				s->maps[%zu].map = &obj->maps.%s;   \n\
85162306a36Sopenharmony_ci			",
85262306a36Sopenharmony_ci			i, bpf_map__name(map), i, ident);
85362306a36Sopenharmony_ci		/* memory-mapped internal maps */
85462306a36Sopenharmony_ci		if (mmaped && is_internal_mmapable_map(map, ident, sizeof(ident))) {
85562306a36Sopenharmony_ci			printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n",
85662306a36Sopenharmony_ci				i, ident);
85762306a36Sopenharmony_ci		}
85862306a36Sopenharmony_ci		i++;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic void
86362306a36Sopenharmony_cicodegen_progs_skeleton(struct bpf_object *obj, size_t prog_cnt, bool populate_links)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct bpf_program *prog;
86662306a36Sopenharmony_ci	int i;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (!prog_cnt)
86962306a36Sopenharmony_ci		return;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	codegen("\
87262306a36Sopenharmony_ci		\n\
87362306a36Sopenharmony_ci									\n\
87462306a36Sopenharmony_ci			/* programs */				    \n\
87562306a36Sopenharmony_ci			s->prog_cnt = %zu;			    \n\
87662306a36Sopenharmony_ci			s->prog_skel_sz = sizeof(*s->progs);	    \n\
87762306a36Sopenharmony_ci			s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);\n\
87862306a36Sopenharmony_ci			if (!s->progs) {			    \n\
87962306a36Sopenharmony_ci				err = -ENOMEM;			    \n\
88062306a36Sopenharmony_ci				goto err;			    \n\
88162306a36Sopenharmony_ci			}					    \n\
88262306a36Sopenharmony_ci		",
88362306a36Sopenharmony_ci		prog_cnt
88462306a36Sopenharmony_ci	);
88562306a36Sopenharmony_ci	i = 0;
88662306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
88762306a36Sopenharmony_ci		codegen("\
88862306a36Sopenharmony_ci			\n\
88962306a36Sopenharmony_ci									\n\
89062306a36Sopenharmony_ci				s->progs[%1$zu].name = \"%2$s\";    \n\
89162306a36Sopenharmony_ci				s->progs[%1$zu].prog = &obj->progs.%2$s;\n\
89262306a36Sopenharmony_ci			",
89362306a36Sopenharmony_ci			i, bpf_program__name(prog));
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		if (populate_links) {
89662306a36Sopenharmony_ci			codegen("\
89762306a36Sopenharmony_ci				\n\
89862306a36Sopenharmony_ci					s->progs[%1$zu].link = &obj->links.%2$s;\n\
89962306a36Sopenharmony_ci				",
90062306a36Sopenharmony_ci				i, bpf_program__name(prog));
90162306a36Sopenharmony_ci		}
90262306a36Sopenharmony_ci		i++;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int do_skeleton(int argc, char **argv)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
90962306a36Sopenharmony_ci	size_t map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
91062306a36Sopenharmony_ci	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
91162306a36Sopenharmony_ci	char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
91262306a36Sopenharmony_ci	struct bpf_object *obj = NULL;
91362306a36Sopenharmony_ci	const char *file;
91462306a36Sopenharmony_ci	char ident[256];
91562306a36Sopenharmony_ci	struct bpf_program *prog;
91662306a36Sopenharmony_ci	int fd, err = -1;
91762306a36Sopenharmony_ci	struct bpf_map *map;
91862306a36Sopenharmony_ci	struct btf *btf;
91962306a36Sopenharmony_ci	struct stat st;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	if (!REQ_ARGS(1)) {
92262306a36Sopenharmony_ci		usage();
92362306a36Sopenharmony_ci		return -1;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci	file = GET_ARG();
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	while (argc) {
92862306a36Sopenharmony_ci		if (!REQ_ARGS(2))
92962306a36Sopenharmony_ci			return -1;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		if (is_prefix(*argv, "name")) {
93262306a36Sopenharmony_ci			NEXT_ARG();
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci			if (obj_name[0] != '\0') {
93562306a36Sopenharmony_ci				p_err("object name already specified");
93662306a36Sopenharmony_ci				return -1;
93762306a36Sopenharmony_ci			}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci			strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);
94062306a36Sopenharmony_ci			obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';
94162306a36Sopenharmony_ci		} else {
94262306a36Sopenharmony_ci			p_err("unknown arg %s", *argv);
94362306a36Sopenharmony_ci			return -1;
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		NEXT_ARG();
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	if (argc) {
95062306a36Sopenharmony_ci		p_err("extra unknown arguments");
95162306a36Sopenharmony_ci		return -1;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	if (stat(file, &st)) {
95562306a36Sopenharmony_ci		p_err("failed to stat() %s: %s", file, strerror(errno));
95662306a36Sopenharmony_ci		return -1;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	file_sz = st.st_size;
95962306a36Sopenharmony_ci	mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
96062306a36Sopenharmony_ci	fd = open(file, O_RDONLY);
96162306a36Sopenharmony_ci	if (fd < 0) {
96262306a36Sopenharmony_ci		p_err("failed to open() %s: %s", file, strerror(errno));
96362306a36Sopenharmony_ci		return -1;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci	obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
96662306a36Sopenharmony_ci	if (obj_data == MAP_FAILED) {
96762306a36Sopenharmony_ci		obj_data = NULL;
96862306a36Sopenharmony_ci		p_err("failed to mmap() %s: %s", file, strerror(errno));
96962306a36Sopenharmony_ci		goto out;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci	if (obj_name[0] == '\0')
97262306a36Sopenharmony_ci		get_obj_name(obj_name, file);
97362306a36Sopenharmony_ci	opts.object_name = obj_name;
97462306a36Sopenharmony_ci	if (verifier_logs)
97562306a36Sopenharmony_ci		/* log_level1 + log_level2 + stats, but not stable UAPI */
97662306a36Sopenharmony_ci		opts.kernel_log_level = 1 + 2 + 4;
97762306a36Sopenharmony_ci	obj = bpf_object__open_mem(obj_data, file_sz, &opts);
97862306a36Sopenharmony_ci	if (!obj) {
97962306a36Sopenharmony_ci		char err_buf[256];
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		err = -errno;
98262306a36Sopenharmony_ci		libbpf_strerror(err, err_buf, sizeof(err_buf));
98362306a36Sopenharmony_ci		p_err("failed to open BPF object file: %s", err_buf);
98462306a36Sopenharmony_ci		goto out;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
98862306a36Sopenharmony_ci		if (!get_map_ident(map, ident, sizeof(ident))) {
98962306a36Sopenharmony_ci			p_err("ignoring unrecognized internal map '%s'...",
99062306a36Sopenharmony_ci			      bpf_map__name(map));
99162306a36Sopenharmony_ci			continue;
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci		map_cnt++;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
99662306a36Sopenharmony_ci		prog_cnt++;
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	get_header_guard(header_guard, obj_name, "SKEL_H");
100062306a36Sopenharmony_ci	if (use_loader) {
100162306a36Sopenharmony_ci		codegen("\
100262306a36Sopenharmony_ci		\n\
100362306a36Sopenharmony_ci		/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
100462306a36Sopenharmony_ci		/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */		    \n\
100562306a36Sopenharmony_ci		#ifndef %2$s						    \n\
100662306a36Sopenharmony_ci		#define %2$s						    \n\
100762306a36Sopenharmony_ci									    \n\
100862306a36Sopenharmony_ci		#include <bpf/skel_internal.h>				    \n\
100962306a36Sopenharmony_ci									    \n\
101062306a36Sopenharmony_ci		struct %1$s {						    \n\
101162306a36Sopenharmony_ci			struct bpf_loader_ctx ctx;			    \n\
101262306a36Sopenharmony_ci		",
101362306a36Sopenharmony_ci		obj_name, header_guard
101462306a36Sopenharmony_ci		);
101562306a36Sopenharmony_ci	} else {
101662306a36Sopenharmony_ci		codegen("\
101762306a36Sopenharmony_ci		\n\
101862306a36Sopenharmony_ci		/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
101962306a36Sopenharmony_ci									    \n\
102062306a36Sopenharmony_ci		/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */		    \n\
102162306a36Sopenharmony_ci		#ifndef %2$s						    \n\
102262306a36Sopenharmony_ci		#define %2$s						    \n\
102362306a36Sopenharmony_ci									    \n\
102462306a36Sopenharmony_ci		#include <errno.h>					    \n\
102562306a36Sopenharmony_ci		#include <stdlib.h>					    \n\
102662306a36Sopenharmony_ci		#include <bpf/libbpf.h>					    \n\
102762306a36Sopenharmony_ci									    \n\
102862306a36Sopenharmony_ci		struct %1$s {						    \n\
102962306a36Sopenharmony_ci			struct bpf_object_skeleton *skeleton;		    \n\
103062306a36Sopenharmony_ci			struct bpf_object *obj;				    \n\
103162306a36Sopenharmony_ci		",
103262306a36Sopenharmony_ci		obj_name, header_guard
103362306a36Sopenharmony_ci		);
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (map_cnt) {
103762306a36Sopenharmony_ci		printf("\tstruct {\n");
103862306a36Sopenharmony_ci		bpf_object__for_each_map(map, obj) {
103962306a36Sopenharmony_ci			if (!get_map_ident(map, ident, sizeof(ident)))
104062306a36Sopenharmony_ci				continue;
104162306a36Sopenharmony_ci			if (use_loader)
104262306a36Sopenharmony_ci				printf("\t\tstruct bpf_map_desc %s;\n", ident);
104362306a36Sopenharmony_ci			else
104462306a36Sopenharmony_ci				printf("\t\tstruct bpf_map *%s;\n", ident);
104562306a36Sopenharmony_ci		}
104662306a36Sopenharmony_ci		printf("\t} maps;\n");
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	if (prog_cnt) {
105062306a36Sopenharmony_ci		printf("\tstruct {\n");
105162306a36Sopenharmony_ci		bpf_object__for_each_program(prog, obj) {
105262306a36Sopenharmony_ci			if (use_loader)
105362306a36Sopenharmony_ci				printf("\t\tstruct bpf_prog_desc %s;\n",
105462306a36Sopenharmony_ci				       bpf_program__name(prog));
105562306a36Sopenharmony_ci			else
105662306a36Sopenharmony_ci				printf("\t\tstruct bpf_program *%s;\n",
105762306a36Sopenharmony_ci				       bpf_program__name(prog));
105862306a36Sopenharmony_ci		}
105962306a36Sopenharmony_ci		printf("\t} progs;\n");
106062306a36Sopenharmony_ci		printf("\tstruct {\n");
106162306a36Sopenharmony_ci		bpf_object__for_each_program(prog, obj) {
106262306a36Sopenharmony_ci			if (use_loader)
106362306a36Sopenharmony_ci				printf("\t\tint %s_fd;\n",
106462306a36Sopenharmony_ci				       bpf_program__name(prog));
106562306a36Sopenharmony_ci			else
106662306a36Sopenharmony_ci				printf("\t\tstruct bpf_link *%s;\n",
106762306a36Sopenharmony_ci				       bpf_program__name(prog));
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_ci		printf("\t} links;\n");
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	btf = bpf_object__btf(obj);
107362306a36Sopenharmony_ci	if (btf) {
107462306a36Sopenharmony_ci		err = codegen_datasecs(obj, obj_name);
107562306a36Sopenharmony_ci		if (err)
107662306a36Sopenharmony_ci			goto out;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci	if (use_loader) {
107962306a36Sopenharmony_ci		err = gen_trace(obj, obj_name, header_guard);
108062306a36Sopenharmony_ci		goto out;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	codegen("\
108462306a36Sopenharmony_ci		\n\
108562306a36Sopenharmony_ci									    \n\
108662306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
108762306a36Sopenharmony_ci			static inline struct %1$s *open(const struct bpf_object_open_opts *opts = nullptr);\n\
108862306a36Sopenharmony_ci			static inline struct %1$s *open_and_load();	    \n\
108962306a36Sopenharmony_ci			static inline int load(struct %1$s *skel);	    \n\
109062306a36Sopenharmony_ci			static inline int attach(struct %1$s *skel);	    \n\
109162306a36Sopenharmony_ci			static inline void detach(struct %1$s *skel);	    \n\
109262306a36Sopenharmony_ci			static inline void destroy(struct %1$s *skel);	    \n\
109362306a36Sopenharmony_ci			static inline const void *elf_bytes(size_t *sz);    \n\
109462306a36Sopenharmony_ci		#endif /* __cplusplus */				    \n\
109562306a36Sopenharmony_ci		};							    \n\
109662306a36Sopenharmony_ci									    \n\
109762306a36Sopenharmony_ci		static void						    \n\
109862306a36Sopenharmony_ci		%1$s__destroy(struct %1$s *obj)				    \n\
109962306a36Sopenharmony_ci		{							    \n\
110062306a36Sopenharmony_ci			if (!obj)					    \n\
110162306a36Sopenharmony_ci				return;					    \n\
110262306a36Sopenharmony_ci			if (obj->skeleton)				    \n\
110362306a36Sopenharmony_ci				bpf_object__destroy_skeleton(obj->skeleton);\n\
110462306a36Sopenharmony_ci			free(obj);					    \n\
110562306a36Sopenharmony_ci		}							    \n\
110662306a36Sopenharmony_ci									    \n\
110762306a36Sopenharmony_ci		static inline int					    \n\
110862306a36Sopenharmony_ci		%1$s__create_skeleton(struct %1$s *obj);		    \n\
110962306a36Sopenharmony_ci									    \n\
111062306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
111162306a36Sopenharmony_ci		%1$s__open_opts(const struct bpf_object_open_opts *opts)    \n\
111262306a36Sopenharmony_ci		{							    \n\
111362306a36Sopenharmony_ci			struct %1$s *obj;				    \n\
111462306a36Sopenharmony_ci			int err;					    \n\
111562306a36Sopenharmony_ci									    \n\
111662306a36Sopenharmony_ci			obj = (struct %1$s *)calloc(1, sizeof(*obj));	    \n\
111762306a36Sopenharmony_ci			if (!obj) {					    \n\
111862306a36Sopenharmony_ci				errno = ENOMEM;				    \n\
111962306a36Sopenharmony_ci				return NULL;				    \n\
112062306a36Sopenharmony_ci			}						    \n\
112162306a36Sopenharmony_ci									    \n\
112262306a36Sopenharmony_ci			err = %1$s__create_skeleton(obj);		    \n\
112362306a36Sopenharmony_ci			if (err)					    \n\
112462306a36Sopenharmony_ci				goto err_out;				    \n\
112562306a36Sopenharmony_ci									    \n\
112662306a36Sopenharmony_ci			err = bpf_object__open_skeleton(obj->skeleton, opts);\n\
112762306a36Sopenharmony_ci			if (err)					    \n\
112862306a36Sopenharmony_ci				goto err_out;				    \n\
112962306a36Sopenharmony_ci									    \n\
113062306a36Sopenharmony_ci			return obj;					    \n\
113162306a36Sopenharmony_ci		err_out:						    \n\
113262306a36Sopenharmony_ci			%1$s__destroy(obj);				    \n\
113362306a36Sopenharmony_ci			errno = -err;					    \n\
113462306a36Sopenharmony_ci			return NULL;					    \n\
113562306a36Sopenharmony_ci		}							    \n\
113662306a36Sopenharmony_ci									    \n\
113762306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
113862306a36Sopenharmony_ci		%1$s__open(void)					    \n\
113962306a36Sopenharmony_ci		{							    \n\
114062306a36Sopenharmony_ci			return %1$s__open_opts(NULL);			    \n\
114162306a36Sopenharmony_ci		}							    \n\
114262306a36Sopenharmony_ci									    \n\
114362306a36Sopenharmony_ci		static inline int					    \n\
114462306a36Sopenharmony_ci		%1$s__load(struct %1$s *obj)				    \n\
114562306a36Sopenharmony_ci		{							    \n\
114662306a36Sopenharmony_ci			return bpf_object__load_skeleton(obj->skeleton);    \n\
114762306a36Sopenharmony_ci		}							    \n\
114862306a36Sopenharmony_ci									    \n\
114962306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
115062306a36Sopenharmony_ci		%1$s__open_and_load(void)				    \n\
115162306a36Sopenharmony_ci		{							    \n\
115262306a36Sopenharmony_ci			struct %1$s *obj;				    \n\
115362306a36Sopenharmony_ci			int err;					    \n\
115462306a36Sopenharmony_ci									    \n\
115562306a36Sopenharmony_ci			obj = %1$s__open();				    \n\
115662306a36Sopenharmony_ci			if (!obj)					    \n\
115762306a36Sopenharmony_ci				return NULL;				    \n\
115862306a36Sopenharmony_ci			err = %1$s__load(obj);				    \n\
115962306a36Sopenharmony_ci			if (err) {					    \n\
116062306a36Sopenharmony_ci				%1$s__destroy(obj);			    \n\
116162306a36Sopenharmony_ci				errno = -err;				    \n\
116262306a36Sopenharmony_ci				return NULL;				    \n\
116362306a36Sopenharmony_ci			}						    \n\
116462306a36Sopenharmony_ci			return obj;					    \n\
116562306a36Sopenharmony_ci		}							    \n\
116662306a36Sopenharmony_ci									    \n\
116762306a36Sopenharmony_ci		static inline int					    \n\
116862306a36Sopenharmony_ci		%1$s__attach(struct %1$s *obj)				    \n\
116962306a36Sopenharmony_ci		{							    \n\
117062306a36Sopenharmony_ci			return bpf_object__attach_skeleton(obj->skeleton);  \n\
117162306a36Sopenharmony_ci		}							    \n\
117262306a36Sopenharmony_ci									    \n\
117362306a36Sopenharmony_ci		static inline void					    \n\
117462306a36Sopenharmony_ci		%1$s__detach(struct %1$s *obj)				    \n\
117562306a36Sopenharmony_ci		{							    \n\
117662306a36Sopenharmony_ci			bpf_object__detach_skeleton(obj->skeleton);	    \n\
117762306a36Sopenharmony_ci		}							    \n\
117862306a36Sopenharmony_ci		",
117962306a36Sopenharmony_ci		obj_name
118062306a36Sopenharmony_ci	);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	codegen("\
118362306a36Sopenharmony_ci		\n\
118462306a36Sopenharmony_ci									    \n\
118562306a36Sopenharmony_ci		static inline const void *%1$s__elf_bytes(size_t *sz);	    \n\
118662306a36Sopenharmony_ci									    \n\
118762306a36Sopenharmony_ci		static inline int					    \n\
118862306a36Sopenharmony_ci		%1$s__create_skeleton(struct %1$s *obj)			    \n\
118962306a36Sopenharmony_ci		{							    \n\
119062306a36Sopenharmony_ci			struct bpf_object_skeleton *s;			    \n\
119162306a36Sopenharmony_ci			int err;					    \n\
119262306a36Sopenharmony_ci									    \n\
119362306a36Sopenharmony_ci			s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\
119462306a36Sopenharmony_ci			if (!s)	{					    \n\
119562306a36Sopenharmony_ci				err = -ENOMEM;				    \n\
119662306a36Sopenharmony_ci				goto err;				    \n\
119762306a36Sopenharmony_ci			}						    \n\
119862306a36Sopenharmony_ci									    \n\
119962306a36Sopenharmony_ci			s->sz = sizeof(*s);				    \n\
120062306a36Sopenharmony_ci			s->name = \"%1$s\";				    \n\
120162306a36Sopenharmony_ci			s->obj = &obj->obj;				    \n\
120262306a36Sopenharmony_ci		",
120362306a36Sopenharmony_ci		obj_name
120462306a36Sopenharmony_ci	);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	codegen_maps_skeleton(obj, map_cnt, true /*mmaped*/);
120762306a36Sopenharmony_ci	codegen_progs_skeleton(obj, prog_cnt, true /*populate_links*/);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	codegen("\
121062306a36Sopenharmony_ci		\n\
121162306a36Sopenharmony_ci									    \n\
121262306a36Sopenharmony_ci			s->data = %1$s__elf_bytes(&s->data_sz);		    \n\
121362306a36Sopenharmony_ci									    \n\
121462306a36Sopenharmony_ci			obj->skeleton = s;				    \n\
121562306a36Sopenharmony_ci			return 0;					    \n\
121662306a36Sopenharmony_ci		err:							    \n\
121762306a36Sopenharmony_ci			bpf_object__destroy_skeleton(s);		    \n\
121862306a36Sopenharmony_ci			return err;					    \n\
121962306a36Sopenharmony_ci		}							    \n\
122062306a36Sopenharmony_ci									    \n\
122162306a36Sopenharmony_ci		static inline const void *%1$s__elf_bytes(size_t *sz)	    \n\
122262306a36Sopenharmony_ci		{							    \n\
122362306a36Sopenharmony_ci			static const char data[] __attribute__((__aligned__(8))) = \"\\\n\
122462306a36Sopenharmony_ci		",
122562306a36Sopenharmony_ci		obj_name
122662306a36Sopenharmony_ci	);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/* embed contents of BPF object file */
122962306a36Sopenharmony_ci	print_hex(obj_data, file_sz);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	codegen("\
123262306a36Sopenharmony_ci		\n\
123362306a36Sopenharmony_ci		\";							    \n\
123462306a36Sopenharmony_ci									    \n\
123562306a36Sopenharmony_ci			*sz = sizeof(data) - 1;				    \n\
123662306a36Sopenharmony_ci			return (const void *)data;			    \n\
123762306a36Sopenharmony_ci		}							    \n\
123862306a36Sopenharmony_ci									    \n\
123962306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
124062306a36Sopenharmony_ci		struct %1$s *%1$s::open(const struct bpf_object_open_opts *opts) { return %1$s__open_opts(opts); }\n\
124162306a36Sopenharmony_ci		struct %1$s *%1$s::open_and_load() { return %1$s__open_and_load(); }	\n\
124262306a36Sopenharmony_ci		int %1$s::load(struct %1$s *skel) { return %1$s__load(skel); }		\n\
124362306a36Sopenharmony_ci		int %1$s::attach(struct %1$s *skel) { return %1$s__attach(skel); }	\n\
124462306a36Sopenharmony_ci		void %1$s::detach(struct %1$s *skel) { %1$s__detach(skel); }		\n\
124562306a36Sopenharmony_ci		void %1$s::destroy(struct %1$s *skel) { %1$s__destroy(skel); }		\n\
124662306a36Sopenharmony_ci		const void *%1$s::elf_bytes(size_t *sz) { return %1$s__elf_bytes(sz); } \n\
124762306a36Sopenharmony_ci		#endif /* __cplusplus */				    \n\
124862306a36Sopenharmony_ci									    \n\
124962306a36Sopenharmony_ci		",
125062306a36Sopenharmony_ci		obj_name);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	codegen_asserts(obj, obj_name);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	codegen("\
125562306a36Sopenharmony_ci		\n\
125662306a36Sopenharmony_ci									    \n\
125762306a36Sopenharmony_ci		#endif /* %1$s */					    \n\
125862306a36Sopenharmony_ci		",
125962306a36Sopenharmony_ci		header_guard);
126062306a36Sopenharmony_ci	err = 0;
126162306a36Sopenharmony_ciout:
126262306a36Sopenharmony_ci	bpf_object__close(obj);
126362306a36Sopenharmony_ci	if (obj_data)
126462306a36Sopenharmony_ci		munmap(obj_data, mmap_sz);
126562306a36Sopenharmony_ci	close(fd);
126662306a36Sopenharmony_ci	return err;
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci/* Subskeletons are like skeletons, except they don't own the bpf_object,
127062306a36Sopenharmony_ci * associated maps, links, etc. Instead, they know about the existence of
127162306a36Sopenharmony_ci * variables, maps, programs and are able to find their locations
127262306a36Sopenharmony_ci * _at runtime_ from an already loaded bpf_object.
127362306a36Sopenharmony_ci *
127462306a36Sopenharmony_ci * This allows for library-like BPF objects to have userspace counterparts
127562306a36Sopenharmony_ci * with access to their own items without having to know anything about the
127662306a36Sopenharmony_ci * final BPF object that the library was linked into.
127762306a36Sopenharmony_ci */
127862306a36Sopenharmony_cistatic int do_subskeleton(int argc, char **argv)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SUBSKEL_H__")];
128162306a36Sopenharmony_ci	size_t i, len, file_sz, map_cnt = 0, prog_cnt = 0, mmap_sz, var_cnt = 0, var_idx = 0;
128262306a36Sopenharmony_ci	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
128362306a36Sopenharmony_ci	char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
128462306a36Sopenharmony_ci	struct bpf_object *obj = NULL;
128562306a36Sopenharmony_ci	const char *file, *var_name;
128662306a36Sopenharmony_ci	char ident[256];
128762306a36Sopenharmony_ci	int fd, err = -1, map_type_id;
128862306a36Sopenharmony_ci	const struct bpf_map *map;
128962306a36Sopenharmony_ci	struct bpf_program *prog;
129062306a36Sopenharmony_ci	struct btf *btf;
129162306a36Sopenharmony_ci	const struct btf_type *map_type, *var_type;
129262306a36Sopenharmony_ci	const struct btf_var_secinfo *var;
129362306a36Sopenharmony_ci	struct stat st;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (!REQ_ARGS(1)) {
129662306a36Sopenharmony_ci		usage();
129762306a36Sopenharmony_ci		return -1;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci	file = GET_ARG();
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	while (argc) {
130262306a36Sopenharmony_ci		if (!REQ_ARGS(2))
130362306a36Sopenharmony_ci			return -1;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci		if (is_prefix(*argv, "name")) {
130662306a36Sopenharmony_ci			NEXT_ARG();
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci			if (obj_name[0] != '\0') {
130962306a36Sopenharmony_ci				p_err("object name already specified");
131062306a36Sopenharmony_ci				return -1;
131162306a36Sopenharmony_ci			}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci			strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);
131462306a36Sopenharmony_ci			obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';
131562306a36Sopenharmony_ci		} else {
131662306a36Sopenharmony_ci			p_err("unknown arg %s", *argv);
131762306a36Sopenharmony_ci			return -1;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci		NEXT_ARG();
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (argc) {
132462306a36Sopenharmony_ci		p_err("extra unknown arguments");
132562306a36Sopenharmony_ci		return -1;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (use_loader) {
132962306a36Sopenharmony_ci		p_err("cannot use loader for subskeletons");
133062306a36Sopenharmony_ci		return -1;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (stat(file, &st)) {
133462306a36Sopenharmony_ci		p_err("failed to stat() %s: %s", file, strerror(errno));
133562306a36Sopenharmony_ci		return -1;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	file_sz = st.st_size;
133862306a36Sopenharmony_ci	mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
133962306a36Sopenharmony_ci	fd = open(file, O_RDONLY);
134062306a36Sopenharmony_ci	if (fd < 0) {
134162306a36Sopenharmony_ci		p_err("failed to open() %s: %s", file, strerror(errno));
134262306a36Sopenharmony_ci		return -1;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci	obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
134562306a36Sopenharmony_ci	if (obj_data == MAP_FAILED) {
134662306a36Sopenharmony_ci		obj_data = NULL;
134762306a36Sopenharmony_ci		p_err("failed to mmap() %s: %s", file, strerror(errno));
134862306a36Sopenharmony_ci		goto out;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci	if (obj_name[0] == '\0')
135162306a36Sopenharmony_ci		get_obj_name(obj_name, file);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/* The empty object name allows us to use bpf_map__name and produce
135462306a36Sopenharmony_ci	 * ELF section names out of it. (".data" instead of "obj.data")
135562306a36Sopenharmony_ci	 */
135662306a36Sopenharmony_ci	opts.object_name = "";
135762306a36Sopenharmony_ci	obj = bpf_object__open_mem(obj_data, file_sz, &opts);
135862306a36Sopenharmony_ci	if (!obj) {
135962306a36Sopenharmony_ci		char err_buf[256];
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci		libbpf_strerror(errno, err_buf, sizeof(err_buf));
136262306a36Sopenharmony_ci		p_err("failed to open BPF object file: %s", err_buf);
136362306a36Sopenharmony_ci		obj = NULL;
136462306a36Sopenharmony_ci		goto out;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	btf = bpf_object__btf(obj);
136862306a36Sopenharmony_ci	if (!btf) {
136962306a36Sopenharmony_ci		err = -1;
137062306a36Sopenharmony_ci		p_err("need btf type information for %s", obj_name);
137162306a36Sopenharmony_ci		goto out;
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
137562306a36Sopenharmony_ci		prog_cnt++;
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* First, count how many variables we have to find.
137962306a36Sopenharmony_ci	 * We need this in advance so the subskel can allocate the right
138062306a36Sopenharmony_ci	 * amount of storage.
138162306a36Sopenharmony_ci	 */
138262306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
138362306a36Sopenharmony_ci		if (!get_map_ident(map, ident, sizeof(ident)))
138462306a36Sopenharmony_ci			continue;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		/* Also count all maps that have a name */
138762306a36Sopenharmony_ci		map_cnt++;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, ident, sizeof(ident)))
139062306a36Sopenharmony_ci			continue;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci		map_type_id = bpf_map__btf_value_type_id(map);
139362306a36Sopenharmony_ci		if (map_type_id <= 0) {
139462306a36Sopenharmony_ci			err = map_type_id;
139562306a36Sopenharmony_ci			goto out;
139662306a36Sopenharmony_ci		}
139762306a36Sopenharmony_ci		map_type = btf__type_by_id(btf, map_type_id);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		var = btf_var_secinfos(map_type);
140062306a36Sopenharmony_ci		len = btf_vlen(map_type);
140162306a36Sopenharmony_ci		for (i = 0; i < len; i++, var++) {
140262306a36Sopenharmony_ci			var_type = btf__type_by_id(btf, var->type);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci			if (btf_var(var_type)->linkage == BTF_VAR_STATIC)
140562306a36Sopenharmony_ci				continue;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci			var_cnt++;
140862306a36Sopenharmony_ci		}
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	get_header_guard(header_guard, obj_name, "SUBSKEL_H");
141262306a36Sopenharmony_ci	codegen("\
141362306a36Sopenharmony_ci	\n\
141462306a36Sopenharmony_ci	/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */	    \n\
141562306a36Sopenharmony_ci									    \n\
141662306a36Sopenharmony_ci	/* THIS FILE IS AUTOGENERATED! */				    \n\
141762306a36Sopenharmony_ci	#ifndef %2$s							    \n\
141862306a36Sopenharmony_ci	#define %2$s							    \n\
141962306a36Sopenharmony_ci									    \n\
142062306a36Sopenharmony_ci	#include <errno.h>						    \n\
142162306a36Sopenharmony_ci	#include <stdlib.h>						    \n\
142262306a36Sopenharmony_ci	#include <bpf/libbpf.h>						    \n\
142362306a36Sopenharmony_ci									    \n\
142462306a36Sopenharmony_ci	struct %1$s {							    \n\
142562306a36Sopenharmony_ci		struct bpf_object *obj;					    \n\
142662306a36Sopenharmony_ci		struct bpf_object_subskeleton *subskel;			    \n\
142762306a36Sopenharmony_ci	", obj_name, header_guard);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	if (map_cnt) {
143062306a36Sopenharmony_ci		printf("\tstruct {\n");
143162306a36Sopenharmony_ci		bpf_object__for_each_map(map, obj) {
143262306a36Sopenharmony_ci			if (!get_map_ident(map, ident, sizeof(ident)))
143362306a36Sopenharmony_ci				continue;
143462306a36Sopenharmony_ci			printf("\t\tstruct bpf_map *%s;\n", ident);
143562306a36Sopenharmony_ci		}
143662306a36Sopenharmony_ci		printf("\t} maps;\n");
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (prog_cnt) {
144062306a36Sopenharmony_ci		printf("\tstruct {\n");
144162306a36Sopenharmony_ci		bpf_object__for_each_program(prog, obj) {
144262306a36Sopenharmony_ci			printf("\t\tstruct bpf_program *%s;\n",
144362306a36Sopenharmony_ci				bpf_program__name(prog));
144462306a36Sopenharmony_ci		}
144562306a36Sopenharmony_ci		printf("\t} progs;\n");
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	err = codegen_subskel_datasecs(obj, obj_name);
144962306a36Sopenharmony_ci	if (err)
145062306a36Sopenharmony_ci		goto out;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* emit code that will allocate enough storage for all symbols */
145362306a36Sopenharmony_ci	codegen("\
145462306a36Sopenharmony_ci		\n\
145562306a36Sopenharmony_ci									    \n\
145662306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
145762306a36Sopenharmony_ci			static inline struct %1$s *open(const struct bpf_object *src);\n\
145862306a36Sopenharmony_ci			static inline void destroy(struct %1$s *skel);	    \n\
145962306a36Sopenharmony_ci		#endif /* __cplusplus */				    \n\
146062306a36Sopenharmony_ci		};							    \n\
146162306a36Sopenharmony_ci									    \n\
146262306a36Sopenharmony_ci		static inline void					    \n\
146362306a36Sopenharmony_ci		%1$s__destroy(struct %1$s *skel)			    \n\
146462306a36Sopenharmony_ci		{							    \n\
146562306a36Sopenharmony_ci			if (!skel)					    \n\
146662306a36Sopenharmony_ci				return;					    \n\
146762306a36Sopenharmony_ci			if (skel->subskel)				    \n\
146862306a36Sopenharmony_ci				bpf_object__destroy_subskeleton(skel->subskel);\n\
146962306a36Sopenharmony_ci			free(skel);					    \n\
147062306a36Sopenharmony_ci		}							    \n\
147162306a36Sopenharmony_ci									    \n\
147262306a36Sopenharmony_ci		static inline struct %1$s *				    \n\
147362306a36Sopenharmony_ci		%1$s__open(const struct bpf_object *src)		    \n\
147462306a36Sopenharmony_ci		{							    \n\
147562306a36Sopenharmony_ci			struct %1$s *obj;				    \n\
147662306a36Sopenharmony_ci			struct bpf_object_subskeleton *s;		    \n\
147762306a36Sopenharmony_ci			int err;					    \n\
147862306a36Sopenharmony_ci									    \n\
147962306a36Sopenharmony_ci			obj = (struct %1$s *)calloc(1, sizeof(*obj));	    \n\
148062306a36Sopenharmony_ci			if (!obj) {					    \n\
148162306a36Sopenharmony_ci				err = -ENOMEM;				    \n\
148262306a36Sopenharmony_ci				goto err;				    \n\
148362306a36Sopenharmony_ci			}						    \n\
148462306a36Sopenharmony_ci			s = (struct bpf_object_subskeleton *)calloc(1, sizeof(*s));\n\
148562306a36Sopenharmony_ci			if (!s) {					    \n\
148662306a36Sopenharmony_ci				err = -ENOMEM;				    \n\
148762306a36Sopenharmony_ci				goto err;				    \n\
148862306a36Sopenharmony_ci			}						    \n\
148962306a36Sopenharmony_ci			s->sz = sizeof(*s);				    \n\
149062306a36Sopenharmony_ci			s->obj = src;					    \n\
149162306a36Sopenharmony_ci			s->var_skel_sz = sizeof(*s->vars);		    \n\
149262306a36Sopenharmony_ci			obj->subskel = s;				    \n\
149362306a36Sopenharmony_ci									    \n\
149462306a36Sopenharmony_ci			/* vars */					    \n\
149562306a36Sopenharmony_ci			s->var_cnt = %2$d;				    \n\
149662306a36Sopenharmony_ci			s->vars = (struct bpf_var_skeleton *)calloc(%2$d, sizeof(*s->vars));\n\
149762306a36Sopenharmony_ci			if (!s->vars) {					    \n\
149862306a36Sopenharmony_ci				err = -ENOMEM;				    \n\
149962306a36Sopenharmony_ci				goto err;				    \n\
150062306a36Sopenharmony_ci			}						    \n\
150162306a36Sopenharmony_ci		",
150262306a36Sopenharmony_ci		obj_name, var_cnt
150362306a36Sopenharmony_ci	);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	/* walk through each symbol and emit the runtime representation */
150662306a36Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
150762306a36Sopenharmony_ci		if (!is_internal_mmapable_map(map, ident, sizeof(ident)))
150862306a36Sopenharmony_ci			continue;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci		map_type_id = bpf_map__btf_value_type_id(map);
151162306a36Sopenharmony_ci		if (map_type_id <= 0)
151262306a36Sopenharmony_ci			/* skip over internal maps with no type*/
151362306a36Sopenharmony_ci			continue;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci		map_type = btf__type_by_id(btf, map_type_id);
151662306a36Sopenharmony_ci		var = btf_var_secinfos(map_type);
151762306a36Sopenharmony_ci		len = btf_vlen(map_type);
151862306a36Sopenharmony_ci		for (i = 0; i < len; i++, var++) {
151962306a36Sopenharmony_ci			var_type = btf__type_by_id(btf, var->type);
152062306a36Sopenharmony_ci			var_name = btf__name_by_offset(btf, var_type->name_off);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci			if (btf_var(var_type)->linkage == BTF_VAR_STATIC)
152362306a36Sopenharmony_ci				continue;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci			/* Note that we use the dot prefix in .data as the
152662306a36Sopenharmony_ci			 * field access operator i.e. maps%s becomes maps.data
152762306a36Sopenharmony_ci			 */
152862306a36Sopenharmony_ci			codegen("\
152962306a36Sopenharmony_ci			\n\
153062306a36Sopenharmony_ci									    \n\
153162306a36Sopenharmony_ci				s->vars[%3$d].name = \"%1$s\";		    \n\
153262306a36Sopenharmony_ci				s->vars[%3$d].map = &obj->maps.%2$s;	    \n\
153362306a36Sopenharmony_ci				s->vars[%3$d].addr = (void **) &obj->%2$s.%1$s;\n\
153462306a36Sopenharmony_ci			", var_name, ident, var_idx);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci			var_idx++;
153762306a36Sopenharmony_ci		}
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	codegen_maps_skeleton(obj, map_cnt, false /*mmaped*/);
154162306a36Sopenharmony_ci	codegen_progs_skeleton(obj, prog_cnt, false /*links*/);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	codegen("\
154462306a36Sopenharmony_ci		\n\
154562306a36Sopenharmony_ci									    \n\
154662306a36Sopenharmony_ci			err = bpf_object__open_subskeleton(s);		    \n\
154762306a36Sopenharmony_ci			if (err)					    \n\
154862306a36Sopenharmony_ci				goto err;				    \n\
154962306a36Sopenharmony_ci									    \n\
155062306a36Sopenharmony_ci			return obj;					    \n\
155162306a36Sopenharmony_ci		err:							    \n\
155262306a36Sopenharmony_ci			%1$s__destroy(obj);				    \n\
155362306a36Sopenharmony_ci			errno = -err;					    \n\
155462306a36Sopenharmony_ci			return NULL;					    \n\
155562306a36Sopenharmony_ci		}							    \n\
155662306a36Sopenharmony_ci									    \n\
155762306a36Sopenharmony_ci		#ifdef __cplusplus					    \n\
155862306a36Sopenharmony_ci		struct %1$s *%1$s::open(const struct bpf_object *src) { return %1$s__open(src); }\n\
155962306a36Sopenharmony_ci		void %1$s::destroy(struct %1$s *skel) { %1$s__destroy(skel); }\n\
156062306a36Sopenharmony_ci		#endif /* __cplusplus */				    \n\
156162306a36Sopenharmony_ci									    \n\
156262306a36Sopenharmony_ci		#endif /* %2$s */					    \n\
156362306a36Sopenharmony_ci		",
156462306a36Sopenharmony_ci		obj_name, header_guard);
156562306a36Sopenharmony_ci	err = 0;
156662306a36Sopenharmony_ciout:
156762306a36Sopenharmony_ci	bpf_object__close(obj);
156862306a36Sopenharmony_ci	if (obj_data)
156962306a36Sopenharmony_ci		munmap(obj_data, mmap_sz);
157062306a36Sopenharmony_ci	close(fd);
157162306a36Sopenharmony_ci	return err;
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_cistatic int do_object(int argc, char **argv)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	struct bpf_linker *linker;
157762306a36Sopenharmony_ci	const char *output_file, *file;
157862306a36Sopenharmony_ci	int err = 0;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (!REQ_ARGS(2)) {
158162306a36Sopenharmony_ci		usage();
158262306a36Sopenharmony_ci		return -1;
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	output_file = GET_ARG();
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	linker = bpf_linker__new(output_file, NULL);
158862306a36Sopenharmony_ci	if (!linker) {
158962306a36Sopenharmony_ci		p_err("failed to create BPF linker instance");
159062306a36Sopenharmony_ci		return -1;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	while (argc) {
159462306a36Sopenharmony_ci		file = GET_ARG();
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		err = bpf_linker__add_file(linker, file, NULL);
159762306a36Sopenharmony_ci		if (err) {
159862306a36Sopenharmony_ci			p_err("failed to link '%s': %s (%d)", file, strerror(errno), errno);
159962306a36Sopenharmony_ci			goto out;
160062306a36Sopenharmony_ci		}
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	err = bpf_linker__finalize(linker);
160462306a36Sopenharmony_ci	if (err) {
160562306a36Sopenharmony_ci		p_err("failed to finalize ELF file: %s (%d)", strerror(errno), errno);
160662306a36Sopenharmony_ci		goto out;
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	err = 0;
161062306a36Sopenharmony_ciout:
161162306a36Sopenharmony_ci	bpf_linker__free(linker);
161262306a36Sopenharmony_ci	return err;
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic int do_help(int argc, char **argv)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	if (json_output) {
161862306a36Sopenharmony_ci		jsonw_null(json_wtr);
161962306a36Sopenharmony_ci		return 0;
162062306a36Sopenharmony_ci	}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	fprintf(stderr,
162362306a36Sopenharmony_ci		"Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n"
162462306a36Sopenharmony_ci		"       %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"
162562306a36Sopenharmony_ci		"       %1$s %2$s subskeleton FILE [name OBJECT_NAME]\n"
162662306a36Sopenharmony_ci		"       %1$s %2$s min_core_btf INPUT OUTPUT OBJECT [OBJECT...]\n"
162762306a36Sopenharmony_ci		"       %1$s %2$s help\n"
162862306a36Sopenharmony_ci		"\n"
162962306a36Sopenharmony_ci		"       " HELP_SPEC_OPTIONS " |\n"
163062306a36Sopenharmony_ci		"                    {-L|--use-loader} }\n"
163162306a36Sopenharmony_ci		"",
163262306a36Sopenharmony_ci		bin_name, "gen");
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	return 0;
163562306a36Sopenharmony_ci}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic int btf_save_raw(const struct btf *btf, const char *path)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	const void *data;
164062306a36Sopenharmony_ci	FILE *f = NULL;
164162306a36Sopenharmony_ci	__u32 data_sz;
164262306a36Sopenharmony_ci	int err = 0;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	data = btf__raw_data(btf, &data_sz);
164562306a36Sopenharmony_ci	if (!data)
164662306a36Sopenharmony_ci		return -ENOMEM;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	f = fopen(path, "wb");
164962306a36Sopenharmony_ci	if (!f)
165062306a36Sopenharmony_ci		return -errno;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	if (fwrite(data, 1, data_sz, f) != data_sz)
165362306a36Sopenharmony_ci		err = -errno;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	fclose(f);
165662306a36Sopenharmony_ci	return err;
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistruct btfgen_info {
166062306a36Sopenharmony_ci	struct btf *src_btf;
166162306a36Sopenharmony_ci	struct btf *marked_btf; /* btf structure used to mark used types */
166262306a36Sopenharmony_ci};
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic size_t btfgen_hash_fn(long key, void *ctx)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	return key;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic bool btfgen_equal_fn(long k1, long k2, void *ctx)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	return k1 == k2;
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_cistatic void btfgen_free_info(struct btfgen_info *info)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	if (!info)
167762306a36Sopenharmony_ci		return;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	btf__free(info->src_btf);
168062306a36Sopenharmony_ci	btf__free(info->marked_btf);
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	free(info);
168362306a36Sopenharmony_ci}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_cistatic struct btfgen_info *
168662306a36Sopenharmony_cibtfgen_new_info(const char *targ_btf_path)
168762306a36Sopenharmony_ci{
168862306a36Sopenharmony_ci	struct btfgen_info *info;
168962306a36Sopenharmony_ci	int err;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	info = calloc(1, sizeof(*info));
169262306a36Sopenharmony_ci	if (!info)
169362306a36Sopenharmony_ci		return NULL;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	info->src_btf = btf__parse(targ_btf_path, NULL);
169662306a36Sopenharmony_ci	if (!info->src_btf) {
169762306a36Sopenharmony_ci		err = -errno;
169862306a36Sopenharmony_ci		p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));
169962306a36Sopenharmony_ci		goto err_out;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	info->marked_btf = btf__parse(targ_btf_path, NULL);
170362306a36Sopenharmony_ci	if (!info->marked_btf) {
170462306a36Sopenharmony_ci		err = -errno;
170562306a36Sopenharmony_ci		p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));
170662306a36Sopenharmony_ci		goto err_out;
170762306a36Sopenharmony_ci	}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	return info;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cierr_out:
171262306a36Sopenharmony_ci	btfgen_free_info(info);
171362306a36Sopenharmony_ci	errno = -err;
171462306a36Sopenharmony_ci	return NULL;
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci#define MARKED UINT32_MAX
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_cistatic void btfgen_mark_member(struct btfgen_info *info, int type_id, int idx)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	const struct btf_type *t = btf__type_by_id(info->marked_btf, type_id);
172262306a36Sopenharmony_ci	struct btf_member *m = btf_members(t) + idx;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	m->name_off = MARKED;
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic int
172862306a36Sopenharmony_cibtfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_pointers)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	const struct btf_type *btf_type = btf__type_by_id(info->src_btf, type_id);
173162306a36Sopenharmony_ci	struct btf_type *cloned_type;
173262306a36Sopenharmony_ci	struct btf_param *param;
173362306a36Sopenharmony_ci	struct btf_array *array;
173462306a36Sopenharmony_ci	int err, i;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (type_id == 0)
173762306a36Sopenharmony_ci		return 0;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* mark type on cloned BTF as used */
174062306a36Sopenharmony_ci	cloned_type = (struct btf_type *) btf__type_by_id(info->marked_btf, type_id);
174162306a36Sopenharmony_ci	cloned_type->name_off = MARKED;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* recursively mark other types needed by it */
174462306a36Sopenharmony_ci	switch (btf_kind(btf_type)) {
174562306a36Sopenharmony_ci	case BTF_KIND_UNKN:
174662306a36Sopenharmony_ci	case BTF_KIND_INT:
174762306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
174862306a36Sopenharmony_ci	case BTF_KIND_ENUM:
174962306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
175062306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
175162306a36Sopenharmony_ci	case BTF_KIND_UNION:
175262306a36Sopenharmony_ci		break;
175362306a36Sopenharmony_ci	case BTF_KIND_PTR:
175462306a36Sopenharmony_ci		if (follow_pointers) {
175562306a36Sopenharmony_ci			err = btfgen_mark_type(info, btf_type->type, follow_pointers);
175662306a36Sopenharmony_ci			if (err)
175762306a36Sopenharmony_ci				return err;
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci		break;
176062306a36Sopenharmony_ci	case BTF_KIND_CONST:
176162306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
176262306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
176362306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
176462306a36Sopenharmony_ci		err = btfgen_mark_type(info, btf_type->type, follow_pointers);
176562306a36Sopenharmony_ci		if (err)
176662306a36Sopenharmony_ci			return err;
176762306a36Sopenharmony_ci		break;
176862306a36Sopenharmony_ci	case BTF_KIND_ARRAY:
176962306a36Sopenharmony_ci		array = btf_array(btf_type);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		/* mark array type */
177262306a36Sopenharmony_ci		err = btfgen_mark_type(info, array->type, follow_pointers);
177362306a36Sopenharmony_ci		/* mark array's index type */
177462306a36Sopenharmony_ci		err = err ? : btfgen_mark_type(info, array->index_type, follow_pointers);
177562306a36Sopenharmony_ci		if (err)
177662306a36Sopenharmony_ci			return err;
177762306a36Sopenharmony_ci		break;
177862306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
177962306a36Sopenharmony_ci		/* mark ret type */
178062306a36Sopenharmony_ci		err = btfgen_mark_type(info, btf_type->type, follow_pointers);
178162306a36Sopenharmony_ci		if (err)
178262306a36Sopenharmony_ci			return err;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci		/* mark parameters types */
178562306a36Sopenharmony_ci		param = btf_params(btf_type);
178662306a36Sopenharmony_ci		for (i = 0; i < btf_vlen(btf_type); i++) {
178762306a36Sopenharmony_ci			err = btfgen_mark_type(info, param->type, follow_pointers);
178862306a36Sopenharmony_ci			if (err)
178962306a36Sopenharmony_ci				return err;
179062306a36Sopenharmony_ci			param++;
179162306a36Sopenharmony_ci		}
179262306a36Sopenharmony_ci		break;
179362306a36Sopenharmony_ci	/* tells if some other type needs to be handled */
179462306a36Sopenharmony_ci	default:
179562306a36Sopenharmony_ci		p_err("unsupported kind: %s (%d)", btf_kind_str(btf_type), type_id);
179662306a36Sopenharmony_ci		return -EINVAL;
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	return 0;
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic int btfgen_record_field_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	struct btf *btf = info->src_btf;
180562306a36Sopenharmony_ci	const struct btf_type *btf_type;
180662306a36Sopenharmony_ci	struct btf_member *btf_member;
180762306a36Sopenharmony_ci	struct btf_array *array;
180862306a36Sopenharmony_ci	unsigned int type_id = targ_spec->root_type_id;
180962306a36Sopenharmony_ci	int idx, err;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/* mark root type */
181262306a36Sopenharmony_ci	btf_type = btf__type_by_id(btf, type_id);
181362306a36Sopenharmony_ci	err = btfgen_mark_type(info, type_id, false);
181462306a36Sopenharmony_ci	if (err)
181562306a36Sopenharmony_ci		return err;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	/* mark types for complex types (arrays, unions, structures) */
181862306a36Sopenharmony_ci	for (int i = 1; i < targ_spec->raw_len; i++) {
181962306a36Sopenharmony_ci		/* skip typedefs and mods */
182062306a36Sopenharmony_ci		while (btf_is_mod(btf_type) || btf_is_typedef(btf_type)) {
182162306a36Sopenharmony_ci			type_id = btf_type->type;
182262306a36Sopenharmony_ci			btf_type = btf__type_by_id(btf, type_id);
182362306a36Sopenharmony_ci		}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		switch (btf_kind(btf_type)) {
182662306a36Sopenharmony_ci		case BTF_KIND_STRUCT:
182762306a36Sopenharmony_ci		case BTF_KIND_UNION:
182862306a36Sopenharmony_ci			idx = targ_spec->raw_spec[i];
182962306a36Sopenharmony_ci			btf_member = btf_members(btf_type) + idx;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci			/* mark member */
183262306a36Sopenharmony_ci			btfgen_mark_member(info, type_id, idx);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci			/* mark member's type */
183562306a36Sopenharmony_ci			type_id = btf_member->type;
183662306a36Sopenharmony_ci			btf_type = btf__type_by_id(btf, type_id);
183762306a36Sopenharmony_ci			err = btfgen_mark_type(info, type_id, false);
183862306a36Sopenharmony_ci			if (err)
183962306a36Sopenharmony_ci				return err;
184062306a36Sopenharmony_ci			break;
184162306a36Sopenharmony_ci		case BTF_KIND_ARRAY:
184262306a36Sopenharmony_ci			array = btf_array(btf_type);
184362306a36Sopenharmony_ci			type_id = array->type;
184462306a36Sopenharmony_ci			btf_type = btf__type_by_id(btf, type_id);
184562306a36Sopenharmony_ci			break;
184662306a36Sopenharmony_ci		default:
184762306a36Sopenharmony_ci			p_err("unsupported kind: %s (%d)",
184862306a36Sopenharmony_ci			      btf_kind_str(btf_type), btf_type->type);
184962306a36Sopenharmony_ci			return -EINVAL;
185062306a36Sopenharmony_ci		}
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return 0;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci/* Mark types, members, and member types. Compared to btfgen_record_field_relo,
185762306a36Sopenharmony_ci * this function does not rely on the target spec for inferring members, but
185862306a36Sopenharmony_ci * uses the associated BTF.
185962306a36Sopenharmony_ci *
186062306a36Sopenharmony_ci * The `behind_ptr` argument is used to stop marking of composite types reached
186162306a36Sopenharmony_ci * through a pointer. This way, we can keep BTF size in check while providing
186262306a36Sopenharmony_ci * reasonable match semantics.
186362306a36Sopenharmony_ci */
186462306a36Sopenharmony_cistatic int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool behind_ptr)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	const struct btf_type *btf_type;
186762306a36Sopenharmony_ci	struct btf *btf = info->src_btf;
186862306a36Sopenharmony_ci	struct btf_type *cloned_type;
186962306a36Sopenharmony_ci	int i, err;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (type_id == 0)
187262306a36Sopenharmony_ci		return 0;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	btf_type = btf__type_by_id(btf, type_id);
187562306a36Sopenharmony_ci	/* mark type on cloned BTF as used */
187662306a36Sopenharmony_ci	cloned_type = (struct btf_type *)btf__type_by_id(info->marked_btf, type_id);
187762306a36Sopenharmony_ci	cloned_type->name_off = MARKED;
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	switch (btf_kind(btf_type)) {
188062306a36Sopenharmony_ci	case BTF_KIND_UNKN:
188162306a36Sopenharmony_ci	case BTF_KIND_INT:
188262306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
188362306a36Sopenharmony_ci	case BTF_KIND_ENUM:
188462306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
188562306a36Sopenharmony_ci		break;
188662306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
188762306a36Sopenharmony_ci	case BTF_KIND_UNION: {
188862306a36Sopenharmony_ci		struct btf_member *m = btf_members(btf_type);
188962306a36Sopenharmony_ci		__u16 vlen = btf_vlen(btf_type);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci		if (behind_ptr)
189262306a36Sopenharmony_ci			break;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci		for (i = 0; i < vlen; i++, m++) {
189562306a36Sopenharmony_ci			/* mark member */
189662306a36Sopenharmony_ci			btfgen_mark_member(info, type_id, i);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci			/* mark member's type */
189962306a36Sopenharmony_ci			err = btfgen_mark_type_match(info, m->type, false);
190062306a36Sopenharmony_ci			if (err)
190162306a36Sopenharmony_ci				return err;
190262306a36Sopenharmony_ci		}
190362306a36Sopenharmony_ci		break;
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci	case BTF_KIND_CONST:
190662306a36Sopenharmony_ci	case BTF_KIND_FWD:
190762306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
190862306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
190962306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
191062306a36Sopenharmony_ci		return btfgen_mark_type_match(info, btf_type->type, behind_ptr);
191162306a36Sopenharmony_ci	case BTF_KIND_PTR:
191262306a36Sopenharmony_ci		return btfgen_mark_type_match(info, btf_type->type, true);
191362306a36Sopenharmony_ci	case BTF_KIND_ARRAY: {
191462306a36Sopenharmony_ci		struct btf_array *array;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		array = btf_array(btf_type);
191762306a36Sopenharmony_ci		/* mark array type */
191862306a36Sopenharmony_ci		err = btfgen_mark_type_match(info, array->type, false);
191962306a36Sopenharmony_ci		/* mark array's index type */
192062306a36Sopenharmony_ci		err = err ? : btfgen_mark_type_match(info, array->index_type, false);
192162306a36Sopenharmony_ci		if (err)
192262306a36Sopenharmony_ci			return err;
192362306a36Sopenharmony_ci		break;
192462306a36Sopenharmony_ci	}
192562306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
192662306a36Sopenharmony_ci		__u16 vlen = btf_vlen(btf_type);
192762306a36Sopenharmony_ci		struct btf_param *param;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		/* mark ret type */
193062306a36Sopenharmony_ci		err = btfgen_mark_type_match(info, btf_type->type, false);
193162306a36Sopenharmony_ci		if (err)
193262306a36Sopenharmony_ci			return err;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci		/* mark parameters types */
193562306a36Sopenharmony_ci		param = btf_params(btf_type);
193662306a36Sopenharmony_ci		for (i = 0; i < vlen; i++) {
193762306a36Sopenharmony_ci			err = btfgen_mark_type_match(info, param->type, false);
193862306a36Sopenharmony_ci			if (err)
193962306a36Sopenharmony_ci				return err;
194062306a36Sopenharmony_ci			param++;
194162306a36Sopenharmony_ci		}
194262306a36Sopenharmony_ci		break;
194362306a36Sopenharmony_ci	}
194462306a36Sopenharmony_ci	/* tells if some other type needs to be handled */
194562306a36Sopenharmony_ci	default:
194662306a36Sopenharmony_ci		p_err("unsupported kind: %s (%d)", btf_kind_str(btf_type), type_id);
194762306a36Sopenharmony_ci		return -EINVAL;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	return 0;
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci/* Mark types, members, and member types. Compared to btfgen_record_field_relo,
195462306a36Sopenharmony_ci * this function does not rely on the target spec for inferring members, but
195562306a36Sopenharmony_ci * uses the associated BTF.
195662306a36Sopenharmony_ci */
195762306a36Sopenharmony_cistatic int btfgen_record_type_match_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)
195862306a36Sopenharmony_ci{
195962306a36Sopenharmony_ci	return btfgen_mark_type_match(info, targ_spec->root_type_id, false);
196062306a36Sopenharmony_ci}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_cistatic int btfgen_record_type_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	return btfgen_mark_type(info, targ_spec->root_type_id, true);
196562306a36Sopenharmony_ci}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_cistatic int btfgen_record_enumval_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)
196862306a36Sopenharmony_ci{
196962306a36Sopenharmony_ci	return btfgen_mark_type(info, targ_spec->root_type_id, false);
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cistatic int btfgen_record_reloc(struct btfgen_info *info, struct bpf_core_spec *res)
197362306a36Sopenharmony_ci{
197462306a36Sopenharmony_ci	switch (res->relo_kind) {
197562306a36Sopenharmony_ci	case BPF_CORE_FIELD_BYTE_OFFSET:
197662306a36Sopenharmony_ci	case BPF_CORE_FIELD_BYTE_SIZE:
197762306a36Sopenharmony_ci	case BPF_CORE_FIELD_EXISTS:
197862306a36Sopenharmony_ci	case BPF_CORE_FIELD_SIGNED:
197962306a36Sopenharmony_ci	case BPF_CORE_FIELD_LSHIFT_U64:
198062306a36Sopenharmony_ci	case BPF_CORE_FIELD_RSHIFT_U64:
198162306a36Sopenharmony_ci		return btfgen_record_field_relo(info, res);
198262306a36Sopenharmony_ci	case BPF_CORE_TYPE_ID_LOCAL: /* BPF_CORE_TYPE_ID_LOCAL doesn't require kernel BTF */
198362306a36Sopenharmony_ci		return 0;
198462306a36Sopenharmony_ci	case BPF_CORE_TYPE_ID_TARGET:
198562306a36Sopenharmony_ci	case BPF_CORE_TYPE_EXISTS:
198662306a36Sopenharmony_ci	case BPF_CORE_TYPE_SIZE:
198762306a36Sopenharmony_ci		return btfgen_record_type_relo(info, res);
198862306a36Sopenharmony_ci	case BPF_CORE_TYPE_MATCHES:
198962306a36Sopenharmony_ci		return btfgen_record_type_match_relo(info, res);
199062306a36Sopenharmony_ci	case BPF_CORE_ENUMVAL_EXISTS:
199162306a36Sopenharmony_ci	case BPF_CORE_ENUMVAL_VALUE:
199262306a36Sopenharmony_ci		return btfgen_record_enumval_relo(info, res);
199362306a36Sopenharmony_ci	default:
199462306a36Sopenharmony_ci		return -EINVAL;
199562306a36Sopenharmony_ci	}
199662306a36Sopenharmony_ci}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_cistatic struct bpf_core_cand_list *
199962306a36Sopenharmony_cibtfgen_find_cands(const struct btf *local_btf, const struct btf *targ_btf, __u32 local_id)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	const struct btf_type *local_type;
200262306a36Sopenharmony_ci	struct bpf_core_cand_list *cands = NULL;
200362306a36Sopenharmony_ci	struct bpf_core_cand local_cand = {};
200462306a36Sopenharmony_ci	size_t local_essent_len;
200562306a36Sopenharmony_ci	const char *local_name;
200662306a36Sopenharmony_ci	int err;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	local_cand.btf = local_btf;
200962306a36Sopenharmony_ci	local_cand.id = local_id;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	local_type = btf__type_by_id(local_btf, local_id);
201262306a36Sopenharmony_ci	if (!local_type) {
201362306a36Sopenharmony_ci		err = -EINVAL;
201462306a36Sopenharmony_ci		goto err_out;
201562306a36Sopenharmony_ci	}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	local_name = btf__name_by_offset(local_btf, local_type->name_off);
201862306a36Sopenharmony_ci	if (!local_name) {
201962306a36Sopenharmony_ci		err = -EINVAL;
202062306a36Sopenharmony_ci		goto err_out;
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci	local_essent_len = bpf_core_essential_name_len(local_name);
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	cands = calloc(1, sizeof(*cands));
202562306a36Sopenharmony_ci	if (!cands)
202662306a36Sopenharmony_ci		return NULL;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	err = bpf_core_add_cands(&local_cand, local_essent_len, targ_btf, "vmlinux", 1, cands);
202962306a36Sopenharmony_ci	if (err)
203062306a36Sopenharmony_ci		goto err_out;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	return cands;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cierr_out:
203562306a36Sopenharmony_ci	bpf_core_free_cands(cands);
203662306a36Sopenharmony_ci	errno = -err;
203762306a36Sopenharmony_ci	return NULL;
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci/* Record relocation information for a single BPF object */
204162306a36Sopenharmony_cistatic int btfgen_record_obj(struct btfgen_info *info, const char *obj_path)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	const struct btf_ext_info_sec *sec;
204462306a36Sopenharmony_ci	const struct bpf_core_relo *relo;
204562306a36Sopenharmony_ci	const struct btf_ext_info *seg;
204662306a36Sopenharmony_ci	struct hashmap_entry *entry;
204762306a36Sopenharmony_ci	struct hashmap *cand_cache = NULL;
204862306a36Sopenharmony_ci	struct btf_ext *btf_ext = NULL;
204962306a36Sopenharmony_ci	unsigned int relo_idx;
205062306a36Sopenharmony_ci	struct btf *btf = NULL;
205162306a36Sopenharmony_ci	size_t i;
205262306a36Sopenharmony_ci	int err;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	btf = btf__parse(obj_path, &btf_ext);
205562306a36Sopenharmony_ci	if (!btf) {
205662306a36Sopenharmony_ci		err = -errno;
205762306a36Sopenharmony_ci		p_err("failed to parse BPF object '%s': %s", obj_path, strerror(errno));
205862306a36Sopenharmony_ci		return err;
205962306a36Sopenharmony_ci	}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (!btf_ext) {
206262306a36Sopenharmony_ci		p_err("failed to parse BPF object '%s': section %s not found",
206362306a36Sopenharmony_ci		      obj_path, BTF_EXT_ELF_SEC);
206462306a36Sopenharmony_ci		err = -EINVAL;
206562306a36Sopenharmony_ci		goto out;
206662306a36Sopenharmony_ci	}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	if (btf_ext->core_relo_info.len == 0) {
206962306a36Sopenharmony_ci		err = 0;
207062306a36Sopenharmony_ci		goto out;
207162306a36Sopenharmony_ci	}
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	cand_cache = hashmap__new(btfgen_hash_fn, btfgen_equal_fn, NULL);
207462306a36Sopenharmony_ci	if (IS_ERR(cand_cache)) {
207562306a36Sopenharmony_ci		err = PTR_ERR(cand_cache);
207662306a36Sopenharmony_ci		goto out;
207762306a36Sopenharmony_ci	}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	seg = &btf_ext->core_relo_info;
208062306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
208162306a36Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, relo_idx, relo) {
208262306a36Sopenharmony_ci			struct bpf_core_spec specs_scratch[3] = {};
208362306a36Sopenharmony_ci			struct bpf_core_relo_res targ_res = {};
208462306a36Sopenharmony_ci			struct bpf_core_cand_list *cands = NULL;
208562306a36Sopenharmony_ci			const char *sec_name = btf__name_by_offset(btf, sec->sec_name_off);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci			if (relo->kind != BPF_CORE_TYPE_ID_LOCAL &&
208862306a36Sopenharmony_ci			    !hashmap__find(cand_cache, relo->type_id, &cands)) {
208962306a36Sopenharmony_ci				cands = btfgen_find_cands(btf, info->src_btf, relo->type_id);
209062306a36Sopenharmony_ci				if (!cands) {
209162306a36Sopenharmony_ci					err = -errno;
209262306a36Sopenharmony_ci					goto out;
209362306a36Sopenharmony_ci				}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci				err = hashmap__set(cand_cache, relo->type_id, cands,
209662306a36Sopenharmony_ci						   NULL, NULL);
209762306a36Sopenharmony_ci				if (err)
209862306a36Sopenharmony_ci					goto out;
209962306a36Sopenharmony_ci			}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci			err = bpf_core_calc_relo_insn(sec_name, relo, relo_idx, btf, cands,
210262306a36Sopenharmony_ci						      specs_scratch, &targ_res);
210362306a36Sopenharmony_ci			if (err)
210462306a36Sopenharmony_ci				goto out;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci			/* specs_scratch[2] is the target spec */
210762306a36Sopenharmony_ci			err = btfgen_record_reloc(info, &specs_scratch[2]);
210862306a36Sopenharmony_ci			if (err)
210962306a36Sopenharmony_ci				goto out;
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci	}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ciout:
211462306a36Sopenharmony_ci	btf__free(btf);
211562306a36Sopenharmony_ci	btf_ext__free(btf_ext);
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(cand_cache)) {
211862306a36Sopenharmony_ci		hashmap__for_each_entry(cand_cache, entry, i) {
211962306a36Sopenharmony_ci			bpf_core_free_cands(entry->pvalue);
212062306a36Sopenharmony_ci		}
212162306a36Sopenharmony_ci		hashmap__free(cand_cache);
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	return err;
212562306a36Sopenharmony_ci}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cistatic int btfgen_remap_id(__u32 *type_id, void *ctx)
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	unsigned int *ids = ctx;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	*type_id = ids[*type_id];
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	return 0;
213462306a36Sopenharmony_ci}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci/* Generate BTF from relocation information previously recorded */
213762306a36Sopenharmony_cistatic struct btf *btfgen_get_btf(struct btfgen_info *info)
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	struct btf *btf_new = NULL;
214062306a36Sopenharmony_ci	unsigned int *ids = NULL;
214162306a36Sopenharmony_ci	unsigned int i, n = btf__type_cnt(info->marked_btf);
214262306a36Sopenharmony_ci	int err = 0;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	btf_new = btf__new_empty();
214562306a36Sopenharmony_ci	if (!btf_new) {
214662306a36Sopenharmony_ci		err = -errno;
214762306a36Sopenharmony_ci		goto err_out;
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	ids = calloc(n, sizeof(*ids));
215162306a36Sopenharmony_ci	if (!ids) {
215262306a36Sopenharmony_ci		err = -errno;
215362306a36Sopenharmony_ci		goto err_out;
215462306a36Sopenharmony_ci	}
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	/* first pass: add all marked types to btf_new and add their new ids to the ids map */
215762306a36Sopenharmony_ci	for (i = 1; i < n; i++) {
215862306a36Sopenharmony_ci		const struct btf_type *cloned_type, *type;
215962306a36Sopenharmony_ci		const char *name;
216062306a36Sopenharmony_ci		int new_id;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci		cloned_type = btf__type_by_id(info->marked_btf, i);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		if (cloned_type->name_off != MARKED)
216562306a36Sopenharmony_ci			continue;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci		type = btf__type_by_id(info->src_btf, i);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci		/* add members for struct and union */
217062306a36Sopenharmony_ci		if (btf_is_composite(type)) {
217162306a36Sopenharmony_ci			struct btf_member *cloned_m, *m;
217262306a36Sopenharmony_ci			unsigned short vlen;
217362306a36Sopenharmony_ci			int idx_src;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci			name = btf__str_by_offset(info->src_btf, type->name_off);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci			if (btf_is_struct(type))
217862306a36Sopenharmony_ci				err = btf__add_struct(btf_new, name, type->size);
217962306a36Sopenharmony_ci			else
218062306a36Sopenharmony_ci				err = btf__add_union(btf_new, name, type->size);
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci			if (err < 0)
218362306a36Sopenharmony_ci				goto err_out;
218462306a36Sopenharmony_ci			new_id = err;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci			cloned_m = btf_members(cloned_type);
218762306a36Sopenharmony_ci			m = btf_members(type);
218862306a36Sopenharmony_ci			vlen = btf_vlen(cloned_type);
218962306a36Sopenharmony_ci			for (idx_src = 0; idx_src < vlen; idx_src++, cloned_m++, m++) {
219062306a36Sopenharmony_ci				/* add only members that are marked as used */
219162306a36Sopenharmony_ci				if (cloned_m->name_off != MARKED)
219262306a36Sopenharmony_ci					continue;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci				name = btf__str_by_offset(info->src_btf, m->name_off);
219562306a36Sopenharmony_ci				err = btf__add_field(btf_new, name, m->type,
219662306a36Sopenharmony_ci						     btf_member_bit_offset(cloned_type, idx_src),
219762306a36Sopenharmony_ci						     btf_member_bitfield_size(cloned_type, idx_src));
219862306a36Sopenharmony_ci				if (err < 0)
219962306a36Sopenharmony_ci					goto err_out;
220062306a36Sopenharmony_ci			}
220162306a36Sopenharmony_ci		} else {
220262306a36Sopenharmony_ci			err = btf__add_type(btf_new, info->src_btf, type);
220362306a36Sopenharmony_ci			if (err < 0)
220462306a36Sopenharmony_ci				goto err_out;
220562306a36Sopenharmony_ci			new_id = err;
220662306a36Sopenharmony_ci		}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci		/* add ID mapping */
220962306a36Sopenharmony_ci		ids[i] = new_id;
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	/* second pass: fix up type ids */
221362306a36Sopenharmony_ci	for (i = 1; i < btf__type_cnt(btf_new); i++) {
221462306a36Sopenharmony_ci		struct btf_type *btf_type = (struct btf_type *) btf__type_by_id(btf_new, i);
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci		err = btf_type_visit_type_ids(btf_type, btfgen_remap_id, ids);
221762306a36Sopenharmony_ci		if (err)
221862306a36Sopenharmony_ci			goto err_out;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	free(ids);
222262306a36Sopenharmony_ci	return btf_new;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_cierr_out:
222562306a36Sopenharmony_ci	btf__free(btf_new);
222662306a36Sopenharmony_ci	free(ids);
222762306a36Sopenharmony_ci	errno = -err;
222862306a36Sopenharmony_ci	return NULL;
222962306a36Sopenharmony_ci}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci/* Create minimized BTF file for a set of BPF objects.
223262306a36Sopenharmony_ci *
223362306a36Sopenharmony_ci * The BTFGen algorithm is divided in two main parts: (1) collect the
223462306a36Sopenharmony_ci * BTF types that are involved in relocations and (2) generate the BTF
223562306a36Sopenharmony_ci * object using the collected types.
223662306a36Sopenharmony_ci *
223762306a36Sopenharmony_ci * In order to collect the types involved in the relocations, we parse
223862306a36Sopenharmony_ci * the BTF and BTF.ext sections of the BPF objects and use
223962306a36Sopenharmony_ci * bpf_core_calc_relo_insn() to get the target specification, this
224062306a36Sopenharmony_ci * indicates how the types and fields are used in a relocation.
224162306a36Sopenharmony_ci *
224262306a36Sopenharmony_ci * Types are recorded in different ways according to the kind of the
224362306a36Sopenharmony_ci * relocation. For field-based relocations only the members that are
224462306a36Sopenharmony_ci * actually used are saved in order to reduce the size of the generated
224562306a36Sopenharmony_ci * BTF file. For type-based relocations empty struct / unions are
224662306a36Sopenharmony_ci * generated and for enum-based relocations the whole type is saved.
224762306a36Sopenharmony_ci *
224862306a36Sopenharmony_ci * The second part of the algorithm generates the BTF object. It creates
224962306a36Sopenharmony_ci * an empty BTF object and fills it with the types recorded in the
225062306a36Sopenharmony_ci * previous step. This function takes care of only adding the structure
225162306a36Sopenharmony_ci * and union members that were marked as used and it also fixes up the
225262306a36Sopenharmony_ci * type IDs on the generated BTF object.
225362306a36Sopenharmony_ci */
225462306a36Sopenharmony_cistatic int minimize_btf(const char *src_btf, const char *dst_btf, const char *objspaths[])
225562306a36Sopenharmony_ci{
225662306a36Sopenharmony_ci	struct btfgen_info *info;
225762306a36Sopenharmony_ci	struct btf *btf_new = NULL;
225862306a36Sopenharmony_ci	int err, i;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	info = btfgen_new_info(src_btf);
226162306a36Sopenharmony_ci	if (!info) {
226262306a36Sopenharmony_ci		err = -errno;
226362306a36Sopenharmony_ci		p_err("failed to allocate info structure: %s", strerror(errno));
226462306a36Sopenharmony_ci		goto out;
226562306a36Sopenharmony_ci	}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	for (i = 0; objspaths[i] != NULL; i++) {
226862306a36Sopenharmony_ci		err = btfgen_record_obj(info, objspaths[i]);
226962306a36Sopenharmony_ci		if (err) {
227062306a36Sopenharmony_ci			p_err("error recording relocations for %s: %s", objspaths[i],
227162306a36Sopenharmony_ci			      strerror(errno));
227262306a36Sopenharmony_ci			goto out;
227362306a36Sopenharmony_ci		}
227462306a36Sopenharmony_ci	}
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	btf_new = btfgen_get_btf(info);
227762306a36Sopenharmony_ci	if (!btf_new) {
227862306a36Sopenharmony_ci		err = -errno;
227962306a36Sopenharmony_ci		p_err("error generating BTF: %s", strerror(errno));
228062306a36Sopenharmony_ci		goto out;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	err = btf_save_raw(btf_new, dst_btf);
228462306a36Sopenharmony_ci	if (err) {
228562306a36Sopenharmony_ci		p_err("error saving btf file: %s", strerror(errno));
228662306a36Sopenharmony_ci		goto out;
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ciout:
229062306a36Sopenharmony_ci	btf__free(btf_new);
229162306a36Sopenharmony_ci	btfgen_free_info(info);
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	return err;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_cistatic int do_min_core_btf(int argc, char **argv)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	const char *input, *output, **objs;
229962306a36Sopenharmony_ci	int i, err;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (!REQ_ARGS(3)) {
230262306a36Sopenharmony_ci		usage();
230362306a36Sopenharmony_ci		return -1;
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	input = GET_ARG();
230762306a36Sopenharmony_ci	output = GET_ARG();
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	objs = (const char **) calloc(argc + 1, sizeof(*objs));
231062306a36Sopenharmony_ci	if (!objs) {
231162306a36Sopenharmony_ci		p_err("failed to allocate array for object names");
231262306a36Sopenharmony_ci		return -ENOMEM;
231362306a36Sopenharmony_ci	}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	i = 0;
231662306a36Sopenharmony_ci	while (argc)
231762306a36Sopenharmony_ci		objs[i++] = GET_ARG();
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	err = minimize_btf(input, output, objs);
232062306a36Sopenharmony_ci	free(objs);
232162306a36Sopenharmony_ci	return err;
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cistatic const struct cmd cmds[] = {
232562306a36Sopenharmony_ci	{ "object",		do_object },
232662306a36Sopenharmony_ci	{ "skeleton",		do_skeleton },
232762306a36Sopenharmony_ci	{ "subskeleton",	do_subskeleton },
232862306a36Sopenharmony_ci	{ "min_core_btf",	do_min_core_btf},
232962306a36Sopenharmony_ci	{ "help",		do_help },
233062306a36Sopenharmony_ci	{ 0 }
233162306a36Sopenharmony_ci};
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ciint do_gen(int argc, char **argv)
233462306a36Sopenharmony_ci{
233562306a36Sopenharmony_ci	return cmd_select(cmds, argc, argv, do_help);
233662306a36Sopenharmony_ci}
2337