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