Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2019 Facebook */
   3
   4#ifndef _GNU_SOURCE
   5#define _GNU_SOURCE
   6#endif
   7#include <ctype.h>
   8#include <errno.h>
   9#include <fcntl.h>
  10#include <linux/err.h>
  11#include <stdbool.h>
  12#include <stdio.h>
  13#include <string.h>
  14#include <unistd.h>
  15#include <bpf/bpf.h>
  16#include <bpf/libbpf.h>
  17#include <sys/types.h>
  18#include <sys/stat.h>
  19#include <sys/mman.h>
  20#include <bpf/btf.h>
  21#include <bpf/bpf_gen_internal.h>
  22
  23#include "json_writer.h"
  24#include "main.h"
  25
  26#define MAX_OBJ_NAME_LEN 64
  27
  28static void sanitize_identifier(char *name)
  29{
  30	int i;
  31
  32	for (i = 0; name[i]; i++)
  33		if (!isalnum(name[i]) && name[i] != '_')
  34			name[i] = '_';
  35}
  36
  37static bool str_has_suffix(const char *str, const char *suffix)
  38{
  39	size_t i, n1 = strlen(str), n2 = strlen(suffix);
  40
  41	if (n1 < n2)
  42		return false;
  43
  44	for (i = 0; i < n2; i++) {
  45		if (str[n1 - i - 1] != suffix[n2 - i - 1])
  46			return false;
  47	}
  48
  49	return true;
  50}
  51
  52static void get_obj_name(char *name, const char *file)
  53{
  54	/* Using basename() GNU version which doesn't modify arg. */
  55	strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1);
  56	name[MAX_OBJ_NAME_LEN - 1] = '\0';
  57	if (str_has_suffix(name, ".o"))
  58		name[strlen(name) - 2] = '\0';
  59	sanitize_identifier(name);
  60}
  61
  62static void get_header_guard(char *guard, const char *obj_name)
  63{
  64	int i;
  65
  66	sprintf(guard, "__%s_SKEL_H__", obj_name);
  67	for (i = 0; guard[i]; i++)
  68		guard[i] = toupper(guard[i]);
  69}
  70
  71static const char *get_map_ident(const struct bpf_map *map)
  72{
  73	const char *name = bpf_map__name(map);
  74
  75	if (!bpf_map__is_internal(map))
  76		return name;
  77
  78	if (str_has_suffix(name, ".data"))
  79		return "data";
  80	else if (str_has_suffix(name, ".rodata"))
  81		return "rodata";
  82	else if (str_has_suffix(name, ".bss"))
  83		return "bss";
  84	else if (str_has_suffix(name, ".kconfig"))
  85		return "kconfig";
  86	else
  87		return NULL;
  88}
  89
  90static void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args)
  91{
  92	vprintf(fmt, args);
  93}
  94
  95static int codegen_datasec_def(struct bpf_object *obj,
  96			       struct btf *btf,
  97			       struct btf_dump *d,
  98			       const struct btf_type *sec,
  99			       const char *obj_name)
 100{
 101	const char *sec_name = btf__name_by_offset(btf, sec->name_off);
 102	const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec);
 103	int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec);
 104	const char *sec_ident;
 105	char var_ident[256];
 106	bool strip_mods = false;
 107
 108	if (strcmp(sec_name, ".data") == 0) {
 109		sec_ident = "data";
 110		strip_mods = true;
 111	} else if (strcmp(sec_name, ".bss") == 0) {
 112		sec_ident = "bss";
 113		strip_mods = true;
 114	} else if (strcmp(sec_name, ".rodata") == 0) {
 115		sec_ident = "rodata";
 116		strip_mods = true;
 117	} else if (strcmp(sec_name, ".kconfig") == 0) {
 118		sec_ident = "kconfig";
 119	} else {
 120		return 0;
 121	}
 122
 123	printf("	struct %s__%s {\n", obj_name, sec_ident);
 124	for (i = 0; i < vlen; i++, sec_var++) {
 125		const struct btf_type *var = btf__type_by_id(btf, sec_var->type);
 126		const char *var_name = btf__name_by_offset(btf, var->name_off);
 127		DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,
 128			.field_name = var_ident,
 129			.indent_level = 2,
 130			.strip_mods = strip_mods,
 131		);
 132		int need_off = sec_var->offset, align_off, align;
 133		__u32 var_type_id = var->type;
 134
 135		/* static variables are not exposed through BPF skeleton */
 136		if (btf_var(var)->linkage == BTF_VAR_STATIC)
 137			continue;
 138
 139		if (off > need_off) {
 140			p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n",
 141			      sec_name, i, need_off, off);
 142			return -EINVAL;
 143		}
 144
 145		align = btf__align_of(btf, var->type);
 146		if (align <= 0) {
 147			p_err("Failed to determine alignment of variable '%s': %d",
 148			      var_name, align);
 149			return -EINVAL;
 150		}
 151		/* Assume 32-bit architectures when generating data section
 152		 * struct memory layout. Given bpftool can't know which target
 153		 * host architecture it's emitting skeleton for, we need to be
 154		 * conservative and assume 32-bit one to ensure enough padding
 155		 * bytes are generated for pointer and long types. This will
 156		 * still work correctly for 64-bit architectures, because in
 157		 * the worst case we'll generate unnecessary padding field,
 158		 * which on 64-bit architectures is not strictly necessary and
 159		 * would be handled by natural 8-byte alignment. But it still
 160		 * will be a correct memory layout, based on recorded offsets
 161		 * in BTF.
 162		 */
 163		if (align > 4)
 164			align = 4;
 165
 166		align_off = (off + align - 1) / align * align;
 167		if (align_off != need_off) {
 168			printf("\t\tchar __pad%d[%d];\n",
 169			       pad_cnt, need_off - off);
 170			pad_cnt++;
 171		}
 172
 173		/* sanitize variable name, e.g., for static vars inside
 174		 * a function, it's name is '<function name>.<variable name>',
 175		 * which we'll turn into a '<function name>_<variable name>'
 176		 */
 177		var_ident[0] = '\0';
 178		strncat(var_ident, var_name, sizeof(var_ident) - 1);
 179		sanitize_identifier(var_ident);
 180
 181		printf("\t\t");
 182		err = btf_dump__emit_type_decl(d, var_type_id, &opts);
 183		if (err)
 184			return err;
 185		printf(";\n");
 186
 187		off = sec_var->offset + sec_var->size;
 188	}
 189	printf("	} *%s;\n", sec_ident);
 190	return 0;
 191}
 192
 193static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
 194{
 195	struct btf *btf = bpf_object__btf(obj);
 196	int n = btf__get_nr_types(btf);
 197	struct btf_dump *d;
 198	int i, err = 0;
 199
 200	d = btf_dump__new(btf, NULL, NULL, codegen_btf_dump_printf);
 201	if (IS_ERR(d))
 202		return PTR_ERR(d);
 203
 204	for (i = 1; i <= n; i++) {
 205		const struct btf_type *t = btf__type_by_id(btf, i);
 206
 207		if (!btf_is_datasec(t))
 208			continue;
 209
 210		err = codegen_datasec_def(obj, btf, d, t, obj_name);
 211		if (err)
 212			goto out;
 213	}
 214out:
 215	btf_dump__free(d);
 216	return err;
 217}
 218
 219static void codegen(const char *template, ...)
 220{
 221	const char *src, *end;
 222	int skip_tabs = 0, n;
 223	char *s, *dst;
 224	va_list args;
 225	char c;
 226
 227	n = strlen(template);
 228	s = malloc(n + 1);
 229	if (!s)
 230		exit(-1);
 231	src = template;
 232	dst = s;
 233
 234	/* find out "baseline" indentation to skip */
 235	while ((c = *src++)) {
 236		if (c == '\t') {
 237			skip_tabs++;
 238		} else if (c == '\n') {
 239			break;
 240		} else {
 241			p_err("unrecognized character at pos %td in template '%s'",
 242			      src - template - 1, template);
 243			free(s);
 244			exit(-1);
 245		}
 246	}
 247
 248	while (*src) {
 249		/* skip baseline indentation tabs */
 250		for (n = skip_tabs; n > 0; n--, src++) {
 251			if (*src != '\t') {
 252				p_err("not enough tabs at pos %td in template '%s'",
 253				      src - template - 1, template);
 254				free(s);
 255				exit(-1);
 256			}
 257		}
 258		/* trim trailing whitespace */
 259		end = strchrnul(src, '\n');
 260		for (n = end - src; n > 0 && isspace(src[n - 1]); n--)
 261			;
 262		memcpy(dst, src, n);
 263		dst += n;
 264		if (*end)
 265			*dst++ = '\n';
 266		src = *end ? end + 1 : end;
 267	}
 268	*dst++ = '\0';
 269
 270	/* print out using adjusted template */
 271	va_start(args, template);
 272	n = vprintf(s, args);
 273	va_end(args);
 274
 275	free(s);
 276}
 277
 278static void print_hex(const char *data, int data_sz)
 279{
 280	int i, len;
 281
 282	for (i = 0, len = 0; i < data_sz; i++) {
 283		int w = data[i] ? 4 : 2;
 284
 285		len += w;
 286		if (len > 78) {
 287			printf("\\\n");
 288			len = w;
 289		}
 290		if (!data[i])
 291			printf("\\0");
 292		else
 293			printf("\\x%02x", (unsigned char)data[i]);
 294	}
 295}
 296
 297static size_t bpf_map_mmap_sz(const struct bpf_map *map)
 298{
 299	long page_sz = sysconf(_SC_PAGE_SIZE);
 300	size_t map_sz;
 301
 302	map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);
 303	map_sz = roundup(map_sz, page_sz);
 304	return map_sz;
 305}
 306
 307static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
 308{
 309	struct bpf_program *prog;
 310
 311	bpf_object__for_each_program(prog, obj) {
 312		const char *tp_name;
 313
 314		codegen("\
 315			\n\
 316			\n\
 317			static inline int					    \n\
 318			%1$s__%2$s__attach(struct %1$s *skel)			    \n\
 319			{							    \n\
 320				int prog_fd = skel->progs.%2$s.prog_fd;		    \n\
 321			", obj_name, bpf_program__name(prog));
 322
 323		switch (bpf_program__get_type(prog)) {
 324		case BPF_PROG_TYPE_RAW_TRACEPOINT:
 325			tp_name = strchr(bpf_program__section_name(prog), '/') + 1;
 326			printf("\tint fd = bpf_raw_tracepoint_open(\"%s\", prog_fd);\n", tp_name);
 327			break;
 328		case BPF_PROG_TYPE_TRACING:
 329			printf("\tint fd = bpf_raw_tracepoint_open(NULL, prog_fd);\n");
 330			break;
 331		default:
 332			printf("\tint fd = ((void)prog_fd, 0); /* auto-attach not supported */\n");
 333			break;
 334		}
 335		codegen("\
 336			\n\
 337										    \n\
 338				if (fd > 0)					    \n\
 339					skel->links.%1$s_fd = fd;		    \n\
 340				return fd;					    \n\
 341			}							    \n\
 342			", bpf_program__name(prog));
 343	}
 344
 345	codegen("\
 346		\n\
 347									    \n\
 348		static inline int					    \n\
 349		%1$s__attach(struct %1$s *skel)				    \n\
 350		{							    \n\
 351			int ret = 0;					    \n\
 352									    \n\
 353		", obj_name);
 354
 355	bpf_object__for_each_program(prog, obj) {
 356		codegen("\
 357			\n\
 358				ret = ret < 0 ? ret : %1$s__%2$s__attach(skel);   \n\
 359			", obj_name, bpf_program__name(prog));
 360	}
 361
 362	codegen("\
 363		\n\
 364			return ret < 0 ? ret : 0;			    \n\
 365		}							    \n\
 366									    \n\
 367		static inline void					    \n\
 368		%1$s__detach(struct %1$s *skel)				    \n\
 369		{							    \n\
 370		", obj_name);
 371
 372	bpf_object__for_each_program(prog, obj) {
 373		codegen("\
 374			\n\
 375				skel_closenz(skel->links.%1$s_fd);	    \n\
 376			", bpf_program__name(prog));
 377	}
 378
 379	codegen("\
 380		\n\
 381		}							    \n\
 382		");
 383}
 384
 385static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 386{
 387	struct bpf_program *prog;
 388	struct bpf_map *map;
 389
 390	codegen("\
 391		\n\
 392		static void						    \n\
 393		%1$s__destroy(struct %1$s *skel)			    \n\
 394		{							    \n\
 395			if (!skel)					    \n\
 396				return;					    \n\
 397			%1$s__detach(skel);				    \n\
 398		",
 399		obj_name);
 400
 401	bpf_object__for_each_program(prog, obj) {
 402		codegen("\
 403			\n\
 404				skel_closenz(skel->progs.%1$s.prog_fd);	    \n\
 405			", bpf_program__name(prog));
 406	}
 407
 408	bpf_object__for_each_map(map, obj) {
 409		const char * ident;
 410
 411		ident = get_map_ident(map);
 412		if (!ident)
 413			continue;
 414		if (bpf_map__is_internal(map) &&
 415		    (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 416			printf("\tmunmap(skel->%1$s, %2$zd);\n",
 417			       ident, bpf_map_mmap_sz(map));
 418		codegen("\
 419			\n\
 420				skel_closenz(skel->maps.%1$s.map_fd);	    \n\
 421			", ident);
 422	}
 423	codegen("\
 424		\n\
 425			free(skel);					    \n\
 426		}							    \n\
 427		",
 428		obj_name);
 429}
 430
 431static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)
 432{
 433	struct bpf_object_load_attr load_attr = {};
 434	DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);
 435	struct bpf_map *map;
 436	int err = 0;
 437
 438	err = bpf_object__gen_loader(obj, &opts);
 439	if (err)
 440		return err;
 441
 442	load_attr.obj = obj;
 443	if (verifier_logs)
 444		/* log_level1 + log_level2 + stats, but not stable UAPI */
 445		load_attr.log_level = 1 + 2 + 4;
 446
 447	err = bpf_object__load_xattr(&load_attr);
 448	if (err) {
 449		p_err("failed to load object file");
 450		goto out;
 451	}
 452	/* If there was no error during load then gen_loader_opts
 453	 * are populated with the loader program.
 454	 */
 455
 456	/* finish generating 'struct skel' */
 457	codegen("\
 458		\n\
 459		};							    \n\
 460		", obj_name);
 461
 462
 463	codegen_attach_detach(obj, obj_name);
 464
 465	codegen_destroy(obj, obj_name);
 466
 467	codegen("\
 468		\n\
 469		static inline struct %1$s *				    \n\
 470		%1$s__open(void)					    \n\
 471		{							    \n\
 472			struct %1$s *skel;				    \n\
 473									    \n\
 474			skel = calloc(sizeof(*skel), 1);		    \n\
 475			if (!skel)					    \n\
 476				goto cleanup;				    \n\
 477			skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
 478		",
 479		obj_name, opts.data_sz);
 480	bpf_object__for_each_map(map, obj) {
 481		const char *ident;
 482		const void *mmap_data = NULL;
 483		size_t mmap_size = 0;
 484
 485		ident = get_map_ident(map);
 486		if (!ident)
 487			continue;
 488
 489		if (!bpf_map__is_internal(map) ||
 490		    !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 491			continue;
 492
 493		codegen("\
 494			\n\
 495				skel->%1$s =					 \n\
 496					mmap(NULL, %2$zd, PROT_READ | PROT_WRITE,\n\
 497					     MAP_SHARED | MAP_ANONYMOUS, -1, 0); \n\
 498				if (skel->%1$s == (void *) -1)			 \n\
 499					goto cleanup;				 \n\
 500				memcpy(skel->%1$s, (void *)\"\\			 \n\
 501			", ident, bpf_map_mmap_sz(map));
 502		mmap_data = bpf_map__initial_value(map, &mmap_size);
 503		print_hex(mmap_data, mmap_size);
 504		printf("\", %2$zd);\n"
 505		       "\tskel->maps.%1$s.initial_value = (__u64)(long)skel->%1$s;\n",
 506		       ident, mmap_size);
 507	}
 508	codegen("\
 509		\n\
 510			return skel;					    \n\
 511		cleanup:						    \n\
 512			%1$s__destroy(skel);				    \n\
 513			return NULL;					    \n\
 514		}							    \n\
 515									    \n\
 516		static inline int					    \n\
 517		%1$s__load(struct %1$s *skel)				    \n\
 518		{							    \n\
 519			struct bpf_load_and_run_opts opts = {};		    \n\
 520			int err;					    \n\
 521									    \n\
 522			opts.ctx = (struct bpf_loader_ctx *)skel;	    \n\
 523			opts.data_sz = %2$d;				    \n\
 524			opts.data = (void *)\"\\			    \n\
 525		",
 526		obj_name, opts.data_sz);
 527	print_hex(opts.data, opts.data_sz);
 528	codegen("\
 529		\n\
 530		\";							    \n\
 531		");
 532
 533	codegen("\
 534		\n\
 535			opts.insns_sz = %d;				    \n\
 536			opts.insns = (void *)\"\\			    \n\
 537		",
 538		opts.insns_sz);
 539	print_hex(opts.insns, opts.insns_sz);
 540	codegen("\
 541		\n\
 542		\";							    \n\
 543			err = bpf_load_and_run(&opts);			    \n\
 544			if (err < 0)					    \n\
 545				return err;				    \n\
 546		", obj_name);
 547	bpf_object__for_each_map(map, obj) {
 548		const char *ident, *mmap_flags;
 549
 550		ident = get_map_ident(map);
 551		if (!ident)
 552			continue;
 553
 554		if (!bpf_map__is_internal(map) ||
 555		    !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 556			continue;
 557		if (bpf_map__def(map)->map_flags & BPF_F_RDONLY_PROG)
 558			mmap_flags = "PROT_READ";
 559		else
 560			mmap_flags = "PROT_READ | PROT_WRITE";
 561
 562		printf("\tskel->%1$s =\n"
 563		       "\t\tmmap(skel->%1$s, %2$zd, %3$s, MAP_SHARED | MAP_FIXED,\n"
 564		       "\t\t\tskel->maps.%1$s.map_fd, 0);\n",
 565		       ident, bpf_map_mmap_sz(map), mmap_flags);
 566	}
 567	codegen("\
 568		\n\
 569			return 0;					    \n\
 570		}							    \n\
 571									    \n\
 572		static inline struct %1$s *				    \n\
 573		%1$s__open_and_load(void)				    \n\
 574		{							    \n\
 575			struct %1$s *skel;				    \n\
 576									    \n\
 577			skel = %1$s__open();				    \n\
 578			if (!skel)					    \n\
 579				return NULL;				    \n\
 580			if (%1$s__load(skel)) {				    \n\
 581				%1$s__destroy(skel);			    \n\
 582				return NULL;				    \n\
 583			}						    \n\
 584			return skel;					    \n\
 585		}							    \n\
 586		", obj_name);
 587
 588	codegen("\
 589		\n\
 590									    \n\
 591		#endif /* %s */						    \n\
 592		",
 593		header_guard);
 594	err = 0;
 595out:
 596	return err;
 597}
 598
 599static int do_skeleton(int argc, char **argv)
 600{
 601	char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
 602	size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
 603	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
 604	char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
 605	struct bpf_object *obj = NULL;
 606	const char *file, *ident;
 607	struct bpf_program *prog;
 608	int fd, err = -1;
 609	struct bpf_map *map;
 610	struct btf *btf;
 611	struct stat st;
 612
 613	if (!REQ_ARGS(1)) {
 614		usage();
 615		return -1;
 616	}
 617	file = GET_ARG();
 618
 619	while (argc) {
 620		if (!REQ_ARGS(2))
 621			return -1;
 622
 623		if (is_prefix(*argv, "name")) {
 624			NEXT_ARG();
 625
 626			if (obj_name[0] != '\0') {
 627				p_err("object name already specified");
 628				return -1;
 629			}
 630
 631			strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);
 632			obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';
 633		} else {
 634			p_err("unknown arg %s", *argv);
 635			return -1;
 636		}
 637
 638		NEXT_ARG();
 639	}
 640
 641	if (argc) {
 642		p_err("extra unknown arguments");
 643		return -1;
 644	}
 645
 646	if (stat(file, &st)) {
 647		p_err("failed to stat() %s: %s", file, strerror(errno));
 648		return -1;
 649	}
 650	file_sz = st.st_size;
 651	mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
 652	fd = open(file, O_RDONLY);
 653	if (fd < 0) {
 654		p_err("failed to open() %s: %s", file, strerror(errno));
 655		return -1;
 656	}
 657	obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
 658	if (obj_data == MAP_FAILED) {
 659		obj_data = NULL;
 660		p_err("failed to mmap() %s: %s", file, strerror(errno));
 661		goto out;
 662	}
 663	if (obj_name[0] == '\0')
 664		get_obj_name(obj_name, file);
 665	opts.object_name = obj_name;
 666	obj = bpf_object__open_mem(obj_data, file_sz, &opts);
 667	if (IS_ERR(obj)) {
 668		char err_buf[256];
 669
 670		libbpf_strerror(PTR_ERR(obj), err_buf, sizeof(err_buf));
 671		p_err("failed to open BPF object file: %s", err_buf);
 672		obj = NULL;
 673		goto out;
 674	}
 675
 676	bpf_object__for_each_map(map, obj) {
 677		ident = get_map_ident(map);
 678		if (!ident) {
 679			p_err("ignoring unrecognized internal map '%s'...",
 680			      bpf_map__name(map));
 681			continue;
 682		}
 683		map_cnt++;
 684	}
 685	bpf_object__for_each_program(prog, obj) {
 686		prog_cnt++;
 687	}
 688
 689	get_header_guard(header_guard, obj_name);
 690	if (use_loader) {
 691		codegen("\
 692		\n\
 693		/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
 694		/* THIS FILE IS AUTOGENERATED! */			    \n\
 695		#ifndef %2$s						    \n\
 696		#define %2$s						    \n\
 697									    \n\
 698		#include <stdlib.h>					    \n\
 699		#include <bpf/bpf.h>					    \n\
 700		#include <bpf/skel_internal.h>				    \n\
 701									    \n\
 702		struct %1$s {						    \n\
 703			struct bpf_loader_ctx ctx;			    \n\
 704		",
 705		obj_name, header_guard
 706		);
 707	} else {
 708		codegen("\
 709		\n\
 710		/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
 711									    \n\
 712		/* THIS FILE IS AUTOGENERATED! */			    \n\
 713		#ifndef %2$s						    \n\
 714		#define %2$s						    \n\
 715									    \n\
 716		#include <errno.h>					    \n\
 717		#include <stdlib.h>					    \n\
 718		#include <bpf/libbpf.h>					    \n\
 719									    \n\
 720		struct %1$s {						    \n\
 721			struct bpf_object_skeleton *skeleton;		    \n\
 722			struct bpf_object *obj;				    \n\
 723		",
 724		obj_name, header_guard
 725		);
 726	}
 727
 728	if (map_cnt) {
 729		printf("\tstruct {\n");
 730		bpf_object__for_each_map(map, obj) {
 731			ident = get_map_ident(map);
 732			if (!ident)
 733				continue;
 734			if (use_loader)
 735				printf("\t\tstruct bpf_map_desc %s;\n", ident);
 736			else
 737				printf("\t\tstruct bpf_map *%s;\n", ident);
 738		}
 739		printf("\t} maps;\n");
 740	}
 741
 742	if (prog_cnt) {
 743		printf("\tstruct {\n");
 744		bpf_object__for_each_program(prog, obj) {
 745			if (use_loader)
 746				printf("\t\tstruct bpf_prog_desc %s;\n",
 747				       bpf_program__name(prog));
 748			else
 749				printf("\t\tstruct bpf_program *%s;\n",
 750				       bpf_program__name(prog));
 751		}
 752		printf("\t} progs;\n");
 753		printf("\tstruct {\n");
 754		bpf_object__for_each_program(prog, obj) {
 755			if (use_loader)
 756				printf("\t\tint %s_fd;\n",
 757				       bpf_program__name(prog));
 758			else
 759				printf("\t\tstruct bpf_link *%s;\n",
 760				       bpf_program__name(prog));
 761		}
 762		printf("\t} links;\n");
 763	}
 764
 765	btf = bpf_object__btf(obj);
 766	if (btf) {
 767		err = codegen_datasecs(obj, obj_name);
 768		if (err)
 769			goto out;
 770	}
 771	if (use_loader) {
 772		err = gen_trace(obj, obj_name, header_guard);
 773		goto out;
 774	}
 775
 776	codegen("\
 777		\n\
 778		};							    \n\
 779									    \n\
 780		static void						    \n\
 781		%1$s__destroy(struct %1$s *obj)				    \n\
 782		{							    \n\
 783			if (!obj)					    \n\
 784				return;					    \n\
 785			if (obj->skeleton)				    \n\
 786				bpf_object__destroy_skeleton(obj->skeleton);\n\
 787			free(obj);					    \n\
 788		}							    \n\
 789									    \n\
 790		static inline int					    \n\
 791		%1$s__create_skeleton(struct %1$s *obj);		    \n\
 792									    \n\
 793		static inline struct %1$s *				    \n\
 794		%1$s__open_opts(const struct bpf_object_open_opts *opts)    \n\
 795		{							    \n\
 796			struct %1$s *obj;				    \n\
 797			int err;					    \n\
 798									    \n\
 799			obj = (struct %1$s *)calloc(1, sizeof(*obj));	    \n\
 800			if (!obj) {					    \n\
 801				errno = ENOMEM;				    \n\
 802				return NULL;				    \n\
 803			}						    \n\
 804									    \n\
 805			err = %1$s__create_skeleton(obj);		    \n\
 806			err = err ?: bpf_object__open_skeleton(obj->skeleton, opts);\n\
 807			if (err)					    \n\
 808				goto err_out;				    \n\
 809									    \n\
 810			return obj;					    \n\
 811		err_out:						    \n\
 812			%1$s__destroy(obj);				    \n\
 813			errno = -err;					    \n\
 814			return NULL;					    \n\
 815		}							    \n\
 816									    \n\
 817		static inline struct %1$s *				    \n\
 818		%1$s__open(void)					    \n\
 819		{							    \n\
 820			return %1$s__open_opts(NULL);			    \n\
 821		}							    \n\
 822									    \n\
 823		static inline int					    \n\
 824		%1$s__load(struct %1$s *obj)				    \n\
 825		{							    \n\
 826			return bpf_object__load_skeleton(obj->skeleton);    \n\
 827		}							    \n\
 828									    \n\
 829		static inline struct %1$s *				    \n\
 830		%1$s__open_and_load(void)				    \n\
 831		{							    \n\
 832			struct %1$s *obj;				    \n\
 833			int err;					    \n\
 834									    \n\
 835			obj = %1$s__open();				    \n\
 836			if (!obj)					    \n\
 837				return NULL;				    \n\
 838			err = %1$s__load(obj);				    \n\
 839			if (err) {					    \n\
 840				%1$s__destroy(obj);			    \n\
 841				errno = -err;				    \n\
 842				return NULL;				    \n\
 843			}						    \n\
 844			return obj;					    \n\
 845		}							    \n\
 846									    \n\
 847		static inline int					    \n\
 848		%1$s__attach(struct %1$s *obj)				    \n\
 849		{							    \n\
 850			return bpf_object__attach_skeleton(obj->skeleton);  \n\
 851		}							    \n\
 852									    \n\
 853		static inline void					    \n\
 854		%1$s__detach(struct %1$s *obj)				    \n\
 855		{							    \n\
 856			return bpf_object__detach_skeleton(obj->skeleton);  \n\
 857		}							    \n\
 858		",
 859		obj_name
 860	);
 861
 862	codegen("\
 863		\n\
 864									    \n\
 865		static inline int					    \n\
 866		%1$s__create_skeleton(struct %1$s *obj)			    \n\
 867		{							    \n\
 868			struct bpf_object_skeleton *s;			    \n\
 869									    \n\
 870			s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\
 871			if (!s)						    \n\
 872				goto err;				    \n\
 873			obj->skeleton = s;				    \n\
 874									    \n\
 875			s->sz = sizeof(*s);				    \n\
 876			s->name = \"%1$s\";				    \n\
 877			s->obj = &obj->obj;				    \n\
 878		",
 879		obj_name
 880	);
 881	if (map_cnt) {
 882		codegen("\
 883			\n\
 884									    \n\
 885				/* maps */				    \n\
 886				s->map_cnt = %zu;			    \n\
 887				s->map_skel_sz = sizeof(*s->maps);	    \n\
 888				s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);\n\
 889				if (!s->maps)				    \n\
 890					goto err;			    \n\
 891			",
 892			map_cnt
 893		);
 894		i = 0;
 895		bpf_object__for_each_map(map, obj) {
 896			ident = get_map_ident(map);
 897
 898			if (!ident)
 899				continue;
 900
 901			codegen("\
 902				\n\
 903									    \n\
 904					s->maps[%zu].name = \"%s\";	    \n\
 905					s->maps[%zu].map = &obj->maps.%s;   \n\
 906				",
 907				i, bpf_map__name(map), i, ident);
 908			/* memory-mapped internal maps */
 909			if (bpf_map__is_internal(map) &&
 910			    (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) {
 911				printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n",
 912				       i, ident);
 913			}
 914			i++;
 915		}
 916	}
 917	if (prog_cnt) {
 918		codegen("\
 919			\n\
 920									    \n\
 921				/* programs */				    \n\
 922				s->prog_cnt = %zu;			    \n\
 923				s->prog_skel_sz = sizeof(*s->progs);	    \n\
 924				s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);\n\
 925				if (!s->progs)				    \n\
 926					goto err;			    \n\
 927			",
 928			prog_cnt
 929		);
 930		i = 0;
 931		bpf_object__for_each_program(prog, obj) {
 932			codegen("\
 933				\n\
 934									    \n\
 935					s->progs[%1$zu].name = \"%2$s\";    \n\
 936					s->progs[%1$zu].prog = &obj->progs.%2$s;\n\
 937					s->progs[%1$zu].link = &obj->links.%2$s;\n\
 938				",
 939				i, bpf_program__name(prog));
 940			i++;
 941		}
 942	}
 943	codegen("\
 944		\n\
 945									    \n\
 946			s->data_sz = %d;				    \n\
 947			s->data = (void *)\"\\				    \n\
 948		",
 949		file_sz);
 950
 951	/* embed contents of BPF object file */
 952	print_hex(obj_data, file_sz);
 953
 954	codegen("\
 955		\n\
 956		\";							    \n\
 957									    \n\
 958			return 0;					    \n\
 959		err:							    \n\
 960			bpf_object__destroy_skeleton(s);		    \n\
 961			return -ENOMEM;					    \n\
 962		}							    \n\
 963									    \n\
 964		#endif /* %s */						    \n\
 965		",
 966		header_guard);
 967	err = 0;
 968out:
 969	bpf_object__close(obj);
 970	if (obj_data)
 971		munmap(obj_data, mmap_sz);
 972	close(fd);
 973	return err;
 974}
 975
 976static int do_object(int argc, char **argv)
 977{
 978	struct bpf_linker *linker;
 979	const char *output_file, *file;
 980	int err = 0;
 981
 982	if (!REQ_ARGS(2)) {
 983		usage();
 984		return -1;
 985	}
 986
 987	output_file = GET_ARG();
 988
 989	linker = bpf_linker__new(output_file, NULL);
 990	if (!linker) {
 991		p_err("failed to create BPF linker instance");
 992		return -1;
 993	}
 994
 995	while (argc) {
 996		file = GET_ARG();
 997
 998		err = bpf_linker__add_file(linker, file, NULL);
 999		if (err) {
1000			p_err("failed to link '%s': %s (%d)", file, strerror(err), err);
1001			goto out;
1002		}
1003	}
1004
1005	err = bpf_linker__finalize(linker);
1006	if (err) {
1007		p_err("failed to finalize ELF file: %s (%d)", strerror(err), err);
1008		goto out;
1009	}
1010
1011	err = 0;
1012out:
1013	bpf_linker__free(linker);
1014	return err;
1015}
1016
1017static int do_help(int argc, char **argv)
1018{
1019	if (json_output) {
1020		jsonw_null(json_wtr);
1021		return 0;
1022	}
1023
1024	fprintf(stderr,
1025		"Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n"
1026		"       %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"
1027		"       %1$s %2$s help\n"
1028		"\n"
1029		"       " HELP_SPEC_OPTIONS "\n"
1030		"",
1031		bin_name, "gen");
1032
1033	return 0;
1034}
1035
1036static const struct cmd cmds[] = {
1037	{ "object",	do_object },
1038	{ "skeleton",	do_skeleton },
1039	{ "help",	do_help },
1040	{ 0 }
1041};
1042
1043int do_gen(int argc, char **argv)
1044{
1045	return cmd_select(cmds, argc, argv, do_help);
1046}