17c2aad20Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
27c2aad20Sopenharmony_ci/* Copyright (c) 2021 Facebook */
37c2aad20Sopenharmony_ci#include <stdio.h>
47c2aad20Sopenharmony_ci#include <stdlib.h>
57c2aad20Sopenharmony_ci#include <string.h>
67c2aad20Sopenharmony_ci#include <errno.h>
77c2aad20Sopenharmony_ci#include <linux/filter.h>
87c2aad20Sopenharmony_ci#include <sys/param.h>
97c2aad20Sopenharmony_ci#include "btf.h"
107c2aad20Sopenharmony_ci#include "bpf.h"
117c2aad20Sopenharmony_ci#include "libbpf.h"
127c2aad20Sopenharmony_ci#include "libbpf_internal.h"
137c2aad20Sopenharmony_ci#include "hashmap.h"
147c2aad20Sopenharmony_ci#include "bpf_gen_internal.h"
157c2aad20Sopenharmony_ci#include "skel_internal.h"
167c2aad20Sopenharmony_ci#include <asm/byteorder.h>
177c2aad20Sopenharmony_ci
187c2aad20Sopenharmony_ci#define MAX_USED_MAPS	64
197c2aad20Sopenharmony_ci#define MAX_USED_PROGS	32
207c2aad20Sopenharmony_ci#define MAX_KFUNC_DESCS 256
217c2aad20Sopenharmony_ci#define MAX_FD_ARRAY_SZ (MAX_USED_MAPS + MAX_KFUNC_DESCS)
227c2aad20Sopenharmony_ci
237c2aad20Sopenharmony_ci/* The following structure describes the stack layout of the loader program.
247c2aad20Sopenharmony_ci * In addition R6 contains the pointer to context.
257c2aad20Sopenharmony_ci * R7 contains the result of the last sys_bpf command (typically error or FD).
267c2aad20Sopenharmony_ci * R9 contains the result of the last sys_close command.
277c2aad20Sopenharmony_ci *
287c2aad20Sopenharmony_ci * Naming convention:
297c2aad20Sopenharmony_ci * ctx - bpf program context
307c2aad20Sopenharmony_ci * stack - bpf program stack
317c2aad20Sopenharmony_ci * blob - bpf_attr-s, strings, insns, map data.
327c2aad20Sopenharmony_ci *        All the bytes that loader prog will use for read/write.
337c2aad20Sopenharmony_ci */
347c2aad20Sopenharmony_cistruct loader_stack {
357c2aad20Sopenharmony_ci	__u32 btf_fd;
367c2aad20Sopenharmony_ci	__u32 inner_map_fd;
377c2aad20Sopenharmony_ci	__u32 prog_fd[MAX_USED_PROGS];
387c2aad20Sopenharmony_ci};
397c2aad20Sopenharmony_ci
407c2aad20Sopenharmony_ci#define stack_off(field) \
417c2aad20Sopenharmony_ci	(__s16)(-sizeof(struct loader_stack) + offsetof(struct loader_stack, field))
427c2aad20Sopenharmony_ci
437c2aad20Sopenharmony_ci#define attr_field(attr, field) (attr + offsetof(union bpf_attr, field))
447c2aad20Sopenharmony_ci
457c2aad20Sopenharmony_cistatic int blob_fd_array_off(struct bpf_gen *gen, int index)
467c2aad20Sopenharmony_ci{
477c2aad20Sopenharmony_ci	return gen->fd_array + index * sizeof(int);
487c2aad20Sopenharmony_ci}
497c2aad20Sopenharmony_ci
507c2aad20Sopenharmony_cistatic int realloc_insn_buf(struct bpf_gen *gen, __u32 size)
517c2aad20Sopenharmony_ci{
527c2aad20Sopenharmony_ci	size_t off = gen->insn_cur - gen->insn_start;
537c2aad20Sopenharmony_ci	void *insn_start;
547c2aad20Sopenharmony_ci
557c2aad20Sopenharmony_ci	if (gen->error)
567c2aad20Sopenharmony_ci		return gen->error;
577c2aad20Sopenharmony_ci	if (size > INT32_MAX || off + size > INT32_MAX) {
587c2aad20Sopenharmony_ci		gen->error = -ERANGE;
597c2aad20Sopenharmony_ci		return -ERANGE;
607c2aad20Sopenharmony_ci	}
617c2aad20Sopenharmony_ci	insn_start = realloc(gen->insn_start, off + size);
627c2aad20Sopenharmony_ci	if (!insn_start) {
637c2aad20Sopenharmony_ci		gen->error = -ENOMEM;
647c2aad20Sopenharmony_ci		free(gen->insn_start);
657c2aad20Sopenharmony_ci		gen->insn_start = NULL;
667c2aad20Sopenharmony_ci		return -ENOMEM;
677c2aad20Sopenharmony_ci	}
687c2aad20Sopenharmony_ci	gen->insn_start = insn_start;
697c2aad20Sopenharmony_ci	gen->insn_cur = insn_start + off;
707c2aad20Sopenharmony_ci	return 0;
717c2aad20Sopenharmony_ci}
727c2aad20Sopenharmony_ci
737c2aad20Sopenharmony_cistatic int realloc_data_buf(struct bpf_gen *gen, __u32 size)
747c2aad20Sopenharmony_ci{
757c2aad20Sopenharmony_ci	size_t off = gen->data_cur - gen->data_start;
767c2aad20Sopenharmony_ci	void *data_start;
777c2aad20Sopenharmony_ci
787c2aad20Sopenharmony_ci	if (gen->error)
797c2aad20Sopenharmony_ci		return gen->error;
807c2aad20Sopenharmony_ci	if (size > INT32_MAX || off + size > INT32_MAX) {
817c2aad20Sopenharmony_ci		gen->error = -ERANGE;
827c2aad20Sopenharmony_ci		return -ERANGE;
837c2aad20Sopenharmony_ci	}
847c2aad20Sopenharmony_ci	data_start = realloc(gen->data_start, off + size);
857c2aad20Sopenharmony_ci	if (!data_start) {
867c2aad20Sopenharmony_ci		gen->error = -ENOMEM;
877c2aad20Sopenharmony_ci		free(gen->data_start);
887c2aad20Sopenharmony_ci		gen->data_start = NULL;
897c2aad20Sopenharmony_ci		return -ENOMEM;
907c2aad20Sopenharmony_ci	}
917c2aad20Sopenharmony_ci	gen->data_start = data_start;
927c2aad20Sopenharmony_ci	gen->data_cur = data_start + off;
937c2aad20Sopenharmony_ci	return 0;
947c2aad20Sopenharmony_ci}
957c2aad20Sopenharmony_ci
967c2aad20Sopenharmony_cistatic void emit(struct bpf_gen *gen, struct bpf_insn insn)
977c2aad20Sopenharmony_ci{
987c2aad20Sopenharmony_ci	if (realloc_insn_buf(gen, sizeof(insn)))
997c2aad20Sopenharmony_ci		return;
1007c2aad20Sopenharmony_ci	memcpy(gen->insn_cur, &insn, sizeof(insn));
1017c2aad20Sopenharmony_ci	gen->insn_cur += sizeof(insn);
1027c2aad20Sopenharmony_ci}
1037c2aad20Sopenharmony_ci
1047c2aad20Sopenharmony_cistatic void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn insn2)
1057c2aad20Sopenharmony_ci{
1067c2aad20Sopenharmony_ci	emit(gen, insn1);
1077c2aad20Sopenharmony_ci	emit(gen, insn2);
1087c2aad20Sopenharmony_ci}
1097c2aad20Sopenharmony_ci
1107c2aad20Sopenharmony_cistatic int add_data(struct bpf_gen *gen, const void *data, __u32 size);
1117c2aad20Sopenharmony_cistatic void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
1127c2aad20Sopenharmony_ci
1137c2aad20Sopenharmony_civoid bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
1147c2aad20Sopenharmony_ci{
1157c2aad20Sopenharmony_ci	size_t stack_sz = sizeof(struct loader_stack), nr_progs_sz;
1167c2aad20Sopenharmony_ci	int i;
1177c2aad20Sopenharmony_ci
1187c2aad20Sopenharmony_ci	gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
1197c2aad20Sopenharmony_ci	gen->log_level = log_level;
1207c2aad20Sopenharmony_ci	/* save ctx pointer into R6 */
1217c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
1227c2aad20Sopenharmony_ci
1237c2aad20Sopenharmony_ci	/* bzero stack */
1247c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
1257c2aad20Sopenharmony_ci	emit(gen, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -stack_sz));
1267c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, stack_sz));
1277c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
1287c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
1297c2aad20Sopenharmony_ci
1307c2aad20Sopenharmony_ci	/* amount of stack actually used, only used to calculate iterations, not stack offset */
1317c2aad20Sopenharmony_ci	nr_progs_sz = offsetof(struct loader_stack, prog_fd[nr_progs]);
1327c2aad20Sopenharmony_ci	/* jump over cleanup code */
1337c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0,
1347c2aad20Sopenharmony_ci			      /* size of cleanup code below (including map fd cleanup) */
1357c2aad20Sopenharmony_ci			      (nr_progs_sz / 4) * 3 + 2 +
1367c2aad20Sopenharmony_ci			      /* 6 insns for emit_sys_close_blob,
1377c2aad20Sopenharmony_ci			       * 6 insns for debug_regs in emit_sys_close_blob
1387c2aad20Sopenharmony_ci			       */
1397c2aad20Sopenharmony_ci			      nr_maps * (6 + (gen->log_level ? 6 : 0))));
1407c2aad20Sopenharmony_ci
1417c2aad20Sopenharmony_ci	/* remember the label where all error branches will jump to */
1427c2aad20Sopenharmony_ci	gen->cleanup_label = gen->insn_cur - gen->insn_start;
1437c2aad20Sopenharmony_ci	/* emit cleanup code: close all temp FDs */
1447c2aad20Sopenharmony_ci	for (i = 0; i < nr_progs_sz; i += 4) {
1457c2aad20Sopenharmony_ci		emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -stack_sz + i));
1467c2aad20Sopenharmony_ci		emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0, 1));
1477c2aad20Sopenharmony_ci		emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
1487c2aad20Sopenharmony_ci	}
1497c2aad20Sopenharmony_ci	for (i = 0; i < nr_maps; i++)
1507c2aad20Sopenharmony_ci		emit_sys_close_blob(gen, blob_fd_array_off(gen, i));
1517c2aad20Sopenharmony_ci	/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
1527c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
1537c2aad20Sopenharmony_ci	emit(gen, BPF_EXIT_INSN());
1547c2aad20Sopenharmony_ci}
1557c2aad20Sopenharmony_ci
1567c2aad20Sopenharmony_cistatic int add_data(struct bpf_gen *gen, const void *data, __u32 size)
1577c2aad20Sopenharmony_ci{
1587c2aad20Sopenharmony_ci	__u32 size8 = roundup(size, 8);
1597c2aad20Sopenharmony_ci	__u64 zero = 0;
1607c2aad20Sopenharmony_ci	void *prev;
1617c2aad20Sopenharmony_ci
1627c2aad20Sopenharmony_ci	if (realloc_data_buf(gen, size8))
1637c2aad20Sopenharmony_ci		return 0;
1647c2aad20Sopenharmony_ci	prev = gen->data_cur;
1657c2aad20Sopenharmony_ci	if (data) {
1667c2aad20Sopenharmony_ci		memcpy(gen->data_cur, data, size);
1677c2aad20Sopenharmony_ci		memcpy(gen->data_cur + size, &zero, size8 - size);
1687c2aad20Sopenharmony_ci	} else {
1697c2aad20Sopenharmony_ci		memset(gen->data_cur, 0, size8);
1707c2aad20Sopenharmony_ci	}
1717c2aad20Sopenharmony_ci	gen->data_cur += size8;
1727c2aad20Sopenharmony_ci	return prev - gen->data_start;
1737c2aad20Sopenharmony_ci}
1747c2aad20Sopenharmony_ci
1757c2aad20Sopenharmony_ci/* Get index for map_fd/btf_fd slot in reserved fd_array, or in data relative
1767c2aad20Sopenharmony_ci * to start of fd_array. Caller can decide if it is usable or not.
1777c2aad20Sopenharmony_ci */
1787c2aad20Sopenharmony_cistatic int add_map_fd(struct bpf_gen *gen)
1797c2aad20Sopenharmony_ci{
1807c2aad20Sopenharmony_ci	if (gen->nr_maps == MAX_USED_MAPS) {
1817c2aad20Sopenharmony_ci		pr_warn("Total maps exceeds %d\n", MAX_USED_MAPS);
1827c2aad20Sopenharmony_ci		gen->error = -E2BIG;
1837c2aad20Sopenharmony_ci		return 0;
1847c2aad20Sopenharmony_ci	}
1857c2aad20Sopenharmony_ci	return gen->nr_maps++;
1867c2aad20Sopenharmony_ci}
1877c2aad20Sopenharmony_ci
1887c2aad20Sopenharmony_cistatic int add_kfunc_btf_fd(struct bpf_gen *gen)
1897c2aad20Sopenharmony_ci{
1907c2aad20Sopenharmony_ci	int cur;
1917c2aad20Sopenharmony_ci
1927c2aad20Sopenharmony_ci	if (gen->nr_fd_array == MAX_KFUNC_DESCS) {
1937c2aad20Sopenharmony_ci		cur = add_data(gen, NULL, sizeof(int));
1947c2aad20Sopenharmony_ci		return (cur - gen->fd_array) / sizeof(int);
1957c2aad20Sopenharmony_ci	}
1967c2aad20Sopenharmony_ci	return MAX_USED_MAPS + gen->nr_fd_array++;
1977c2aad20Sopenharmony_ci}
1987c2aad20Sopenharmony_ci
1997c2aad20Sopenharmony_cistatic int insn_bytes_to_bpf_size(__u32 sz)
2007c2aad20Sopenharmony_ci{
2017c2aad20Sopenharmony_ci	switch (sz) {
2027c2aad20Sopenharmony_ci	case 8: return BPF_DW;
2037c2aad20Sopenharmony_ci	case 4: return BPF_W;
2047c2aad20Sopenharmony_ci	case 2: return BPF_H;
2057c2aad20Sopenharmony_ci	case 1: return BPF_B;
2067c2aad20Sopenharmony_ci	default: return -1;
2077c2aad20Sopenharmony_ci	}
2087c2aad20Sopenharmony_ci}
2097c2aad20Sopenharmony_ci
2107c2aad20Sopenharmony_ci/* *(u64 *)(blob + off) = (u64)(void *)(blob + data) */
2117c2aad20Sopenharmony_cistatic void emit_rel_store(struct bpf_gen *gen, int off, int data)
2127c2aad20Sopenharmony_ci{
2137c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
2147c2aad20Sopenharmony_ci					 0, 0, 0, data));
2157c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
2167c2aad20Sopenharmony_ci					 0, 0, 0, off));
2177c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0));
2187c2aad20Sopenharmony_ci}
2197c2aad20Sopenharmony_ci
2207c2aad20Sopenharmony_cistatic void move_blob2blob(struct bpf_gen *gen, int off, int size, int blob_off)
2217c2aad20Sopenharmony_ci{
2227c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_2, BPF_PSEUDO_MAP_IDX_VALUE,
2237c2aad20Sopenharmony_ci					 0, 0, 0, blob_off));
2247c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_2, 0));
2257c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
2267c2aad20Sopenharmony_ci					 0, 0, 0, off));
2277c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_1, BPF_REG_0, 0));
2287c2aad20Sopenharmony_ci}
2297c2aad20Sopenharmony_ci
2307c2aad20Sopenharmony_cistatic void move_blob2ctx(struct bpf_gen *gen, int ctx_off, int size, int blob_off)
2317c2aad20Sopenharmony_ci{
2327c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
2337c2aad20Sopenharmony_ci					 0, 0, 0, blob_off));
2347c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_1, 0));
2357c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_6, BPF_REG_0, ctx_off));
2367c2aad20Sopenharmony_ci}
2377c2aad20Sopenharmony_ci
2387c2aad20Sopenharmony_cistatic void move_ctx2blob(struct bpf_gen *gen, int off, int size, int ctx_off,
2397c2aad20Sopenharmony_ci				   bool check_non_zero)
2407c2aad20Sopenharmony_ci{
2417c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_6, ctx_off));
2427c2aad20Sopenharmony_ci	if (check_non_zero)
2437c2aad20Sopenharmony_ci		/* If value in ctx is zero don't update the blob.
2447c2aad20Sopenharmony_ci		 * For example: when ctx->map.max_entries == 0, keep default max_entries from bpf.c
2457c2aad20Sopenharmony_ci		 */
2467c2aad20Sopenharmony_ci		emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3));
2477c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
2487c2aad20Sopenharmony_ci					 0, 0, 0, off));
2497c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_1, BPF_REG_0, 0));
2507c2aad20Sopenharmony_ci}
2517c2aad20Sopenharmony_ci
2527c2aad20Sopenharmony_cistatic void move_stack2blob(struct bpf_gen *gen, int off, int size, int stack_off)
2537c2aad20Sopenharmony_ci{
2547c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_10, stack_off));
2557c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
2567c2aad20Sopenharmony_ci					 0, 0, 0, off));
2577c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_1, BPF_REG_0, 0));
2587c2aad20Sopenharmony_ci}
2597c2aad20Sopenharmony_ci
2607c2aad20Sopenharmony_cistatic void move_stack2ctx(struct bpf_gen *gen, int ctx_off, int size, int stack_off)
2617c2aad20Sopenharmony_ci{
2627c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_10, stack_off));
2637c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_6, BPF_REG_0, ctx_off));
2647c2aad20Sopenharmony_ci}
2657c2aad20Sopenharmony_ci
2667c2aad20Sopenharmony_cistatic void emit_sys_bpf(struct bpf_gen *gen, int cmd, int attr, int attr_size)
2677c2aad20Sopenharmony_ci{
2687c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_1, cmd));
2697c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_2, BPF_PSEUDO_MAP_IDX_VALUE,
2707c2aad20Sopenharmony_ci					 0, 0, 0, attr));
2717c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_3, attr_size));
2727c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_bpf));
2737c2aad20Sopenharmony_ci	/* remember the result in R7 */
2747c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
2757c2aad20Sopenharmony_ci}
2767c2aad20Sopenharmony_ci
2777c2aad20Sopenharmony_cistatic bool is_simm16(__s64 value)
2787c2aad20Sopenharmony_ci{
2797c2aad20Sopenharmony_ci	return value == (__s64)(__s16)value;
2807c2aad20Sopenharmony_ci}
2817c2aad20Sopenharmony_ci
2827c2aad20Sopenharmony_cistatic void emit_check_err(struct bpf_gen *gen)
2837c2aad20Sopenharmony_ci{
2847c2aad20Sopenharmony_ci	__s64 off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 1;
2857c2aad20Sopenharmony_ci
2867c2aad20Sopenharmony_ci	/* R7 contains result of last sys_bpf command.
2877c2aad20Sopenharmony_ci	 * if (R7 < 0) goto cleanup;
2887c2aad20Sopenharmony_ci	 */
2897c2aad20Sopenharmony_ci	if (is_simm16(off)) {
2907c2aad20Sopenharmony_ci		emit(gen, BPF_JMP_IMM(BPF_JSLT, BPF_REG_7, 0, off));
2917c2aad20Sopenharmony_ci	} else {
2927c2aad20Sopenharmony_ci		gen->error = -ERANGE;
2937c2aad20Sopenharmony_ci		emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, -1));
2947c2aad20Sopenharmony_ci	}
2957c2aad20Sopenharmony_ci}
2967c2aad20Sopenharmony_ci
2977c2aad20Sopenharmony_ci/* reg1 and reg2 should not be R1 - R5. They can be R0, R6 - R10 */
2987c2aad20Sopenharmony_cistatic void emit_debug(struct bpf_gen *gen, int reg1, int reg2,
2997c2aad20Sopenharmony_ci		       const char *fmt, va_list args)
3007c2aad20Sopenharmony_ci{
3017c2aad20Sopenharmony_ci	char buf[1024];
3027c2aad20Sopenharmony_ci	int addr, len, ret;
3037c2aad20Sopenharmony_ci
3047c2aad20Sopenharmony_ci	if (!gen->log_level)
3057c2aad20Sopenharmony_ci		return;
3067c2aad20Sopenharmony_ci	ret = vsnprintf(buf, sizeof(buf), fmt, args);
3077c2aad20Sopenharmony_ci	if (ret < 1024 - 7 && reg1 >= 0 && reg2 < 0)
3087c2aad20Sopenharmony_ci		/* The special case to accommodate common debug_ret():
3097c2aad20Sopenharmony_ci		 * to avoid specifying BPF_REG_7 and adding " r=%%d" to
3107c2aad20Sopenharmony_ci		 * prints explicitly.
3117c2aad20Sopenharmony_ci		 */
3127c2aad20Sopenharmony_ci		strcat(buf, " r=%d");
3137c2aad20Sopenharmony_ci	len = strlen(buf) + 1;
3147c2aad20Sopenharmony_ci	addr = add_data(gen, buf, len);
3157c2aad20Sopenharmony_ci
3167c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
3177c2aad20Sopenharmony_ci					 0, 0, 0, addr));
3187c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
3197c2aad20Sopenharmony_ci	if (reg1 >= 0)
3207c2aad20Sopenharmony_ci		emit(gen, BPF_MOV64_REG(BPF_REG_3, reg1));
3217c2aad20Sopenharmony_ci	if (reg2 >= 0)
3227c2aad20Sopenharmony_ci		emit(gen, BPF_MOV64_REG(BPF_REG_4, reg2));
3237c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_trace_printk));
3247c2aad20Sopenharmony_ci}
3257c2aad20Sopenharmony_ci
3267c2aad20Sopenharmony_cistatic void debug_regs(struct bpf_gen *gen, int reg1, int reg2, const char *fmt, ...)
3277c2aad20Sopenharmony_ci{
3287c2aad20Sopenharmony_ci	va_list args;
3297c2aad20Sopenharmony_ci
3307c2aad20Sopenharmony_ci	va_start(args, fmt);
3317c2aad20Sopenharmony_ci	emit_debug(gen, reg1, reg2, fmt, args);
3327c2aad20Sopenharmony_ci	va_end(args);
3337c2aad20Sopenharmony_ci}
3347c2aad20Sopenharmony_ci
3357c2aad20Sopenharmony_cistatic void debug_ret(struct bpf_gen *gen, const char *fmt, ...)
3367c2aad20Sopenharmony_ci{
3377c2aad20Sopenharmony_ci	va_list args;
3387c2aad20Sopenharmony_ci
3397c2aad20Sopenharmony_ci	va_start(args, fmt);
3407c2aad20Sopenharmony_ci	emit_debug(gen, BPF_REG_7, -1, fmt, args);
3417c2aad20Sopenharmony_ci	va_end(args);
3427c2aad20Sopenharmony_ci}
3437c2aad20Sopenharmony_ci
3447c2aad20Sopenharmony_cistatic void __emit_sys_close(struct bpf_gen *gen)
3457c2aad20Sopenharmony_ci{
3467c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0,
3477c2aad20Sopenharmony_ci			      /* 2 is the number of the following insns
3487c2aad20Sopenharmony_ci			       * * 6 is additional insns in debug_regs
3497c2aad20Sopenharmony_ci			       */
3507c2aad20Sopenharmony_ci			      2 + (gen->log_level ? 6 : 0)));
3517c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_1));
3527c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
3537c2aad20Sopenharmony_ci	debug_regs(gen, BPF_REG_9, BPF_REG_0, "close(%%d) = %%d");
3547c2aad20Sopenharmony_ci}
3557c2aad20Sopenharmony_ci
3567c2aad20Sopenharmony_cistatic void emit_sys_close_stack(struct bpf_gen *gen, int stack_off)
3577c2aad20Sopenharmony_ci{
3587c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, stack_off));
3597c2aad20Sopenharmony_ci	__emit_sys_close(gen);
3607c2aad20Sopenharmony_ci}
3617c2aad20Sopenharmony_ci
3627c2aad20Sopenharmony_cistatic void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
3637c2aad20Sopenharmony_ci{
3647c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
3657c2aad20Sopenharmony_ci					 0, 0, 0, blob_off));
3667c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0));
3677c2aad20Sopenharmony_ci	__emit_sys_close(gen);
3687c2aad20Sopenharmony_ci}
3697c2aad20Sopenharmony_ci
3707c2aad20Sopenharmony_ciint bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
3717c2aad20Sopenharmony_ci{
3727c2aad20Sopenharmony_ci	int i;
3737c2aad20Sopenharmony_ci
3747c2aad20Sopenharmony_ci	if (nr_progs < gen->nr_progs || nr_maps != gen->nr_maps) {
3757c2aad20Sopenharmony_ci		pr_warn("nr_progs %d/%d nr_maps %d/%d mismatch\n",
3767c2aad20Sopenharmony_ci			nr_progs, gen->nr_progs, nr_maps, gen->nr_maps);
3777c2aad20Sopenharmony_ci		gen->error = -EFAULT;
3787c2aad20Sopenharmony_ci		return gen->error;
3797c2aad20Sopenharmony_ci	}
3807c2aad20Sopenharmony_ci	emit_sys_close_stack(gen, stack_off(btf_fd));
3817c2aad20Sopenharmony_ci	for (i = 0; i < gen->nr_progs; i++)
3827c2aad20Sopenharmony_ci		move_stack2ctx(gen,
3837c2aad20Sopenharmony_ci			       sizeof(struct bpf_loader_ctx) +
3847c2aad20Sopenharmony_ci			       sizeof(struct bpf_map_desc) * gen->nr_maps +
3857c2aad20Sopenharmony_ci			       sizeof(struct bpf_prog_desc) * i +
3867c2aad20Sopenharmony_ci			       offsetof(struct bpf_prog_desc, prog_fd), 4,
3877c2aad20Sopenharmony_ci			       stack_off(prog_fd[i]));
3887c2aad20Sopenharmony_ci	for (i = 0; i < gen->nr_maps; i++)
3897c2aad20Sopenharmony_ci		move_blob2ctx(gen,
3907c2aad20Sopenharmony_ci			      sizeof(struct bpf_loader_ctx) +
3917c2aad20Sopenharmony_ci			      sizeof(struct bpf_map_desc) * i +
3927c2aad20Sopenharmony_ci			      offsetof(struct bpf_map_desc, map_fd), 4,
3937c2aad20Sopenharmony_ci			      blob_fd_array_off(gen, i));
3947c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0));
3957c2aad20Sopenharmony_ci	emit(gen, BPF_EXIT_INSN());
3967c2aad20Sopenharmony_ci	pr_debug("gen: finish %d\n", gen->error);
3977c2aad20Sopenharmony_ci	if (!gen->error) {
3987c2aad20Sopenharmony_ci		struct gen_loader_opts *opts = gen->opts;
3997c2aad20Sopenharmony_ci
4007c2aad20Sopenharmony_ci		opts->insns = gen->insn_start;
4017c2aad20Sopenharmony_ci		opts->insns_sz = gen->insn_cur - gen->insn_start;
4027c2aad20Sopenharmony_ci		opts->data = gen->data_start;
4037c2aad20Sopenharmony_ci		opts->data_sz = gen->data_cur - gen->data_start;
4047c2aad20Sopenharmony_ci	}
4057c2aad20Sopenharmony_ci	return gen->error;
4067c2aad20Sopenharmony_ci}
4077c2aad20Sopenharmony_ci
4087c2aad20Sopenharmony_civoid bpf_gen__free(struct bpf_gen *gen)
4097c2aad20Sopenharmony_ci{
4107c2aad20Sopenharmony_ci	if (!gen)
4117c2aad20Sopenharmony_ci		return;
4127c2aad20Sopenharmony_ci	free(gen->data_start);
4137c2aad20Sopenharmony_ci	free(gen->insn_start);
4147c2aad20Sopenharmony_ci	free(gen);
4157c2aad20Sopenharmony_ci}
4167c2aad20Sopenharmony_ci
4177c2aad20Sopenharmony_civoid bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
4187c2aad20Sopenharmony_ci		       __u32 btf_raw_size)
4197c2aad20Sopenharmony_ci{
4207c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, btf_log_level);
4217c2aad20Sopenharmony_ci	int btf_data, btf_load_attr;
4227c2aad20Sopenharmony_ci	union bpf_attr attr;
4237c2aad20Sopenharmony_ci
4247c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
4257c2aad20Sopenharmony_ci	pr_debug("gen: load_btf: size %d\n", btf_raw_size);
4267c2aad20Sopenharmony_ci	btf_data = add_data(gen, btf_raw_data, btf_raw_size);
4277c2aad20Sopenharmony_ci
4287c2aad20Sopenharmony_ci	attr.btf_size = btf_raw_size;
4297c2aad20Sopenharmony_ci	btf_load_attr = add_data(gen, &attr, attr_size);
4307c2aad20Sopenharmony_ci
4317c2aad20Sopenharmony_ci	/* populate union bpf_attr with user provided log details */
4327c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_level), 4,
4337c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_level), false);
4347c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_size), 4,
4357c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_size), false);
4367c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_buf), 8,
4377c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_buf), false);
4387c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to the BTF data */
4397c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(btf_load_attr, btf), btf_data);
4407c2aad20Sopenharmony_ci	/* emit BTF_LOAD command */
4417c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_BTF_LOAD, btf_load_attr, attr_size);
4427c2aad20Sopenharmony_ci	debug_ret(gen, "btf_load size %d", btf_raw_size);
4437c2aad20Sopenharmony_ci	emit_check_err(gen);
4447c2aad20Sopenharmony_ci	/* remember btf_fd in the stack, if successful */
4457c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7, stack_off(btf_fd)));
4467c2aad20Sopenharmony_ci}
4477c2aad20Sopenharmony_ci
4487c2aad20Sopenharmony_civoid bpf_gen__map_create(struct bpf_gen *gen,
4497c2aad20Sopenharmony_ci			 enum bpf_map_type map_type,
4507c2aad20Sopenharmony_ci			 const char *map_name,
4517c2aad20Sopenharmony_ci			 __u32 key_size, __u32 value_size, __u32 max_entries,
4527c2aad20Sopenharmony_ci			 struct bpf_map_create_opts *map_attr, int map_idx)
4537c2aad20Sopenharmony_ci{
4547c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, map_extra);
4557c2aad20Sopenharmony_ci	bool close_inner_map_fd = false;
4567c2aad20Sopenharmony_ci	int map_create_attr, idx;
4577c2aad20Sopenharmony_ci	union bpf_attr attr;
4587c2aad20Sopenharmony_ci
4597c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
4607c2aad20Sopenharmony_ci	attr.map_type = map_type;
4617c2aad20Sopenharmony_ci	attr.key_size = key_size;
4627c2aad20Sopenharmony_ci	attr.value_size = value_size;
4637c2aad20Sopenharmony_ci	attr.map_flags = map_attr->map_flags;
4647c2aad20Sopenharmony_ci	attr.map_extra = map_attr->map_extra;
4657c2aad20Sopenharmony_ci	if (map_name)
4667c2aad20Sopenharmony_ci		libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
4677c2aad20Sopenharmony_ci	attr.numa_node = map_attr->numa_node;
4687c2aad20Sopenharmony_ci	attr.map_ifindex = map_attr->map_ifindex;
4697c2aad20Sopenharmony_ci	attr.max_entries = max_entries;
4707c2aad20Sopenharmony_ci	attr.btf_key_type_id = map_attr->btf_key_type_id;
4717c2aad20Sopenharmony_ci	attr.btf_value_type_id = map_attr->btf_value_type_id;
4727c2aad20Sopenharmony_ci
4737c2aad20Sopenharmony_ci	pr_debug("gen: map_create: %s idx %d type %d value_type_id %d\n",
4747c2aad20Sopenharmony_ci		 attr.map_name, map_idx, map_type, attr.btf_value_type_id);
4757c2aad20Sopenharmony_ci
4767c2aad20Sopenharmony_ci	map_create_attr = add_data(gen, &attr, attr_size);
4777c2aad20Sopenharmony_ci	if (attr.btf_value_type_id)
4787c2aad20Sopenharmony_ci		/* populate union bpf_attr with btf_fd saved in the stack earlier */
4797c2aad20Sopenharmony_ci		move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
4807c2aad20Sopenharmony_ci				stack_off(btf_fd));
4817c2aad20Sopenharmony_ci	switch (attr.map_type) {
4827c2aad20Sopenharmony_ci	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
4837c2aad20Sopenharmony_ci	case BPF_MAP_TYPE_HASH_OF_MAPS:
4847c2aad20Sopenharmony_ci		move_stack2blob(gen, attr_field(map_create_attr, inner_map_fd), 4,
4857c2aad20Sopenharmony_ci				stack_off(inner_map_fd));
4867c2aad20Sopenharmony_ci		close_inner_map_fd = true;
4877c2aad20Sopenharmony_ci		break;
4887c2aad20Sopenharmony_ci	default:
4897c2aad20Sopenharmony_ci		break;
4907c2aad20Sopenharmony_ci	}
4917c2aad20Sopenharmony_ci	/* conditionally update max_entries */
4927c2aad20Sopenharmony_ci	if (map_idx >= 0)
4937c2aad20Sopenharmony_ci		move_ctx2blob(gen, attr_field(map_create_attr, max_entries), 4,
4947c2aad20Sopenharmony_ci			      sizeof(struct bpf_loader_ctx) +
4957c2aad20Sopenharmony_ci			      sizeof(struct bpf_map_desc) * map_idx +
4967c2aad20Sopenharmony_ci			      offsetof(struct bpf_map_desc, max_entries),
4977c2aad20Sopenharmony_ci			      true /* check that max_entries != 0 */);
4987c2aad20Sopenharmony_ci	/* emit MAP_CREATE command */
4997c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size);
5007c2aad20Sopenharmony_ci	debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d",
5017c2aad20Sopenharmony_ci		  attr.map_name, map_idx, map_type, value_size,
5027c2aad20Sopenharmony_ci		  attr.btf_value_type_id);
5037c2aad20Sopenharmony_ci	emit_check_err(gen);
5047c2aad20Sopenharmony_ci	/* remember map_fd in the stack, if successful */
5057c2aad20Sopenharmony_ci	if (map_idx < 0) {
5067c2aad20Sopenharmony_ci		/* This bpf_gen__map_create() function is called with map_idx >= 0
5077c2aad20Sopenharmony_ci		 * for all maps that libbpf loading logic tracks.
5087c2aad20Sopenharmony_ci		 * It's called with -1 to create an inner map.
5097c2aad20Sopenharmony_ci		 */
5107c2aad20Sopenharmony_ci		emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7,
5117c2aad20Sopenharmony_ci				      stack_off(inner_map_fd)));
5127c2aad20Sopenharmony_ci	} else if (map_idx != gen->nr_maps) {
5137c2aad20Sopenharmony_ci		gen->error = -EDOM; /* internal bug */
5147c2aad20Sopenharmony_ci		return;
5157c2aad20Sopenharmony_ci	} else {
5167c2aad20Sopenharmony_ci		/* add_map_fd does gen->nr_maps++ */
5177c2aad20Sopenharmony_ci		idx = add_map_fd(gen);
5187c2aad20Sopenharmony_ci		emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
5197c2aad20Sopenharmony_ci						 0, 0, 0, blob_fd_array_off(gen, idx)));
5207c2aad20Sopenharmony_ci		emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_7, 0));
5217c2aad20Sopenharmony_ci	}
5227c2aad20Sopenharmony_ci	if (close_inner_map_fd)
5237c2aad20Sopenharmony_ci		emit_sys_close_stack(gen, stack_off(inner_map_fd));
5247c2aad20Sopenharmony_ci}
5257c2aad20Sopenharmony_ci
5267c2aad20Sopenharmony_civoid bpf_gen__record_attach_target(struct bpf_gen *gen, const char *attach_name,
5277c2aad20Sopenharmony_ci				   enum bpf_attach_type type)
5287c2aad20Sopenharmony_ci{
5297c2aad20Sopenharmony_ci	const char *prefix;
5307c2aad20Sopenharmony_ci	int kind, ret;
5317c2aad20Sopenharmony_ci
5327c2aad20Sopenharmony_ci	btf_get_kernel_prefix_kind(type, &prefix, &kind);
5337c2aad20Sopenharmony_ci	gen->attach_kind = kind;
5347c2aad20Sopenharmony_ci	ret = snprintf(gen->attach_target, sizeof(gen->attach_target), "%s%s",
5357c2aad20Sopenharmony_ci		       prefix, attach_name);
5367c2aad20Sopenharmony_ci	if (ret >= sizeof(gen->attach_target))
5377c2aad20Sopenharmony_ci		gen->error = -ENOSPC;
5387c2aad20Sopenharmony_ci}
5397c2aad20Sopenharmony_ci
5407c2aad20Sopenharmony_cistatic void emit_find_attach_target(struct bpf_gen *gen)
5417c2aad20Sopenharmony_ci{
5427c2aad20Sopenharmony_ci	int name, len = strlen(gen->attach_target) + 1;
5437c2aad20Sopenharmony_ci
5447c2aad20Sopenharmony_ci	pr_debug("gen: find_attach_tgt %s %d\n", gen->attach_target, gen->attach_kind);
5457c2aad20Sopenharmony_ci	name = add_data(gen, gen->attach_target, len);
5467c2aad20Sopenharmony_ci
5477c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
5487c2aad20Sopenharmony_ci					 0, 0, 0, name));
5497c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
5507c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_3, gen->attach_kind));
5517c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_4, 0));
5527c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_btf_find_by_name_kind));
5537c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
5547c2aad20Sopenharmony_ci	debug_ret(gen, "find_by_name_kind(%s,%d)",
5557c2aad20Sopenharmony_ci		  gen->attach_target, gen->attach_kind);
5567c2aad20Sopenharmony_ci	emit_check_err(gen);
5577c2aad20Sopenharmony_ci	/* if successful, btf_id is in lower 32-bit of R7 and
5587c2aad20Sopenharmony_ci	 * btf_obj_fd is in upper 32-bit
5597c2aad20Sopenharmony_ci	 */
5607c2aad20Sopenharmony_ci}
5617c2aad20Sopenharmony_ci
5627c2aad20Sopenharmony_civoid bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
5637c2aad20Sopenharmony_ci			    bool is_typeless, bool is_ld64, int kind, int insn_idx)
5647c2aad20Sopenharmony_ci{
5657c2aad20Sopenharmony_ci	struct ksym_relo_desc *relo;
5667c2aad20Sopenharmony_ci
5677c2aad20Sopenharmony_ci	relo = libbpf_reallocarray(gen->relos, gen->relo_cnt + 1, sizeof(*relo));
5687c2aad20Sopenharmony_ci	if (!relo) {
5697c2aad20Sopenharmony_ci		gen->error = -ENOMEM;
5707c2aad20Sopenharmony_ci		return;
5717c2aad20Sopenharmony_ci	}
5727c2aad20Sopenharmony_ci	gen->relos = relo;
5737c2aad20Sopenharmony_ci	relo += gen->relo_cnt;
5747c2aad20Sopenharmony_ci	relo->name = name;
5757c2aad20Sopenharmony_ci	relo->is_weak = is_weak;
5767c2aad20Sopenharmony_ci	relo->is_typeless = is_typeless;
5777c2aad20Sopenharmony_ci	relo->is_ld64 = is_ld64;
5787c2aad20Sopenharmony_ci	relo->kind = kind;
5797c2aad20Sopenharmony_ci	relo->insn_idx = insn_idx;
5807c2aad20Sopenharmony_ci	gen->relo_cnt++;
5817c2aad20Sopenharmony_ci}
5827c2aad20Sopenharmony_ci
5837c2aad20Sopenharmony_ci/* returns existing ksym_desc with ref incremented, or inserts a new one */
5847c2aad20Sopenharmony_cistatic struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_desc *relo)
5857c2aad20Sopenharmony_ci{
5867c2aad20Sopenharmony_ci	struct ksym_desc *kdesc;
5877c2aad20Sopenharmony_ci	int i;
5887c2aad20Sopenharmony_ci
5897c2aad20Sopenharmony_ci	for (i = 0; i < gen->nr_ksyms; i++) {
5907c2aad20Sopenharmony_ci		kdesc = &gen->ksyms[i];
5917c2aad20Sopenharmony_ci		if (kdesc->kind == relo->kind && kdesc->is_ld64 == relo->is_ld64 &&
5927c2aad20Sopenharmony_ci		    !strcmp(kdesc->name, relo->name)) {
5937c2aad20Sopenharmony_ci			kdesc->ref++;
5947c2aad20Sopenharmony_ci			return kdesc;
5957c2aad20Sopenharmony_ci		}
5967c2aad20Sopenharmony_ci	}
5977c2aad20Sopenharmony_ci	kdesc = libbpf_reallocarray(gen->ksyms, gen->nr_ksyms + 1, sizeof(*kdesc));
5987c2aad20Sopenharmony_ci	if (!kdesc) {
5997c2aad20Sopenharmony_ci		gen->error = -ENOMEM;
6007c2aad20Sopenharmony_ci		return NULL;
6017c2aad20Sopenharmony_ci	}
6027c2aad20Sopenharmony_ci	gen->ksyms = kdesc;
6037c2aad20Sopenharmony_ci	kdesc = &gen->ksyms[gen->nr_ksyms++];
6047c2aad20Sopenharmony_ci	kdesc->name = relo->name;
6057c2aad20Sopenharmony_ci	kdesc->kind = relo->kind;
6067c2aad20Sopenharmony_ci	kdesc->ref = 1;
6077c2aad20Sopenharmony_ci	kdesc->off = 0;
6087c2aad20Sopenharmony_ci	kdesc->insn = 0;
6097c2aad20Sopenharmony_ci	kdesc->is_ld64 = relo->is_ld64;
6107c2aad20Sopenharmony_ci	return kdesc;
6117c2aad20Sopenharmony_ci}
6127c2aad20Sopenharmony_ci
6137c2aad20Sopenharmony_ci/* Overwrites BPF_REG_{0, 1, 2, 3, 4, 7}
6147c2aad20Sopenharmony_ci * Returns result in BPF_REG_7
6157c2aad20Sopenharmony_ci */
6167c2aad20Sopenharmony_cistatic void emit_bpf_find_by_name_kind(struct bpf_gen *gen, struct ksym_relo_desc *relo)
6177c2aad20Sopenharmony_ci{
6187c2aad20Sopenharmony_ci	int name_off, len = strlen(relo->name) + 1;
6197c2aad20Sopenharmony_ci
6207c2aad20Sopenharmony_ci	name_off = add_data(gen, relo->name, len);
6217c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
6227c2aad20Sopenharmony_ci					 0, 0, 0, name_off));
6237c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
6247c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_3, relo->kind));
6257c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_4, 0));
6267c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_btf_find_by_name_kind));
6277c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
6287c2aad20Sopenharmony_ci	debug_ret(gen, "find_by_name_kind(%s,%d)", relo->name, relo->kind);
6297c2aad20Sopenharmony_ci}
6307c2aad20Sopenharmony_ci
6317c2aad20Sopenharmony_ci/* Overwrites BPF_REG_{0, 1, 2, 3, 4, 7}
6327c2aad20Sopenharmony_ci * Returns result in BPF_REG_7
6337c2aad20Sopenharmony_ci * Returns u64 symbol addr in BPF_REG_9
6347c2aad20Sopenharmony_ci */
6357c2aad20Sopenharmony_cistatic void emit_bpf_kallsyms_lookup_name(struct bpf_gen *gen, struct ksym_relo_desc *relo)
6367c2aad20Sopenharmony_ci{
6377c2aad20Sopenharmony_ci	int name_off, len = strlen(relo->name) + 1, res_off;
6387c2aad20Sopenharmony_ci
6397c2aad20Sopenharmony_ci	name_off = add_data(gen, relo->name, len);
6407c2aad20Sopenharmony_ci	res_off = add_data(gen, NULL, 8); /* res is u64 */
6417c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
6427c2aad20Sopenharmony_ci					 0, 0, 0, name_off));
6437c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
6447c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
6457c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_4, BPF_PSEUDO_MAP_IDX_VALUE,
6467c2aad20Sopenharmony_ci					 0, 0, 0, res_off));
6477c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_4));
6487c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_kallsyms_lookup_name));
6497c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0));
6507c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
6517c2aad20Sopenharmony_ci	debug_ret(gen, "kallsyms_lookup_name(%s,%d)", relo->name, relo->kind);
6527c2aad20Sopenharmony_ci}
6537c2aad20Sopenharmony_ci
6547c2aad20Sopenharmony_ci/* Expects:
6557c2aad20Sopenharmony_ci * BPF_REG_8 - pointer to instruction
6567c2aad20Sopenharmony_ci *
6577c2aad20Sopenharmony_ci * We need to reuse BTF fd for same symbol otherwise each relocation takes a new
6587c2aad20Sopenharmony_ci * index, while kernel limits total kfunc BTFs to 256. For duplicate symbols,
6597c2aad20Sopenharmony_ci * this would mean a new BTF fd index for each entry. By pairing symbol name
6607c2aad20Sopenharmony_ci * with index, we get the insn->imm, insn->off pairing that kernel uses for
6617c2aad20Sopenharmony_ci * kfunc_tab, which becomes the effective limit even though all of them may
6627c2aad20Sopenharmony_ci * share same index in fd_array (such that kfunc_btf_tab has 1 element).
6637c2aad20Sopenharmony_ci */
6647c2aad20Sopenharmony_cistatic void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn)
6657c2aad20Sopenharmony_ci{
6667c2aad20Sopenharmony_ci	struct ksym_desc *kdesc;
6677c2aad20Sopenharmony_ci	int btf_fd_idx;
6687c2aad20Sopenharmony_ci
6697c2aad20Sopenharmony_ci	kdesc = get_ksym_desc(gen, relo);
6707c2aad20Sopenharmony_ci	if (!kdesc)
6717c2aad20Sopenharmony_ci		return;
6727c2aad20Sopenharmony_ci	/* try to copy from existing bpf_insn */
6737c2aad20Sopenharmony_ci	if (kdesc->ref > 1) {
6747c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
6757c2aad20Sopenharmony_ci			       kdesc->insn + offsetof(struct bpf_insn, imm));
6767c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + offsetof(struct bpf_insn, off), 2,
6777c2aad20Sopenharmony_ci			       kdesc->insn + offsetof(struct bpf_insn, off));
6787c2aad20Sopenharmony_ci		goto log;
6797c2aad20Sopenharmony_ci	}
6807c2aad20Sopenharmony_ci	/* remember insn offset, so we can copy BTF ID and FD later */
6817c2aad20Sopenharmony_ci	kdesc->insn = insn;
6827c2aad20Sopenharmony_ci	emit_bpf_find_by_name_kind(gen, relo);
6837c2aad20Sopenharmony_ci	if (!relo->is_weak)
6847c2aad20Sopenharmony_ci		emit_check_err(gen);
6857c2aad20Sopenharmony_ci	/* get index in fd_array to store BTF FD at */
6867c2aad20Sopenharmony_ci	btf_fd_idx = add_kfunc_btf_fd(gen);
6877c2aad20Sopenharmony_ci	if (btf_fd_idx > INT16_MAX) {
6887c2aad20Sopenharmony_ci		pr_warn("BTF fd off %d for kfunc %s exceeds INT16_MAX, cannot process relocation\n",
6897c2aad20Sopenharmony_ci			btf_fd_idx, relo->name);
6907c2aad20Sopenharmony_ci		gen->error = -E2BIG;
6917c2aad20Sopenharmony_ci		return;
6927c2aad20Sopenharmony_ci	}
6937c2aad20Sopenharmony_ci	kdesc->off = btf_fd_idx;
6947c2aad20Sopenharmony_ci	/* jump to success case */
6957c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
6967c2aad20Sopenharmony_ci	/* set value for imm, off as 0 */
6977c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, offsetof(struct bpf_insn, imm), 0));
6987c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
6997c2aad20Sopenharmony_ci	/* skip success case for ret < 0 */
7007c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 10));
7017c2aad20Sopenharmony_ci	/* store btf_id into insn[insn_idx].imm */
7027c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7, offsetof(struct bpf_insn, imm)));
7037c2aad20Sopenharmony_ci	/* obtain fd in BPF_REG_9 */
7047c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7));
7057c2aad20Sopenharmony_ci	emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
7067c2aad20Sopenharmony_ci	/* load fd_array slot pointer */
7077c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
7087c2aad20Sopenharmony_ci					 0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
7097c2aad20Sopenharmony_ci	/* store BTF fd in slot, 0 for vmlinux */
7107c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
7117c2aad20Sopenharmony_ci	/* jump to insn[insn_idx].off store if fd denotes module BTF */
7127c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
7137c2aad20Sopenharmony_ci	/* set the default value for off */
7147c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
7157c2aad20Sopenharmony_ci	/* skip BTF fd store for vmlinux BTF */
7167c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
7177c2aad20Sopenharmony_ci	/* store index into insn[insn_idx].off */
7187c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx));
7197c2aad20Sopenharmony_cilog:
7207c2aad20Sopenharmony_ci	if (!gen->log_level)
7217c2aad20Sopenharmony_ci		return;
7227c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_8,
7237c2aad20Sopenharmony_ci			      offsetof(struct bpf_insn, imm)));
7247c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_H, BPF_REG_9, BPF_REG_8,
7257c2aad20Sopenharmony_ci			      offsetof(struct bpf_insn, off)));
7267c2aad20Sopenharmony_ci	debug_regs(gen, BPF_REG_7, BPF_REG_9, " func (%s:count=%d): imm: %%d, off: %%d",
7277c2aad20Sopenharmony_ci		   relo->name, kdesc->ref);
7287c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
7297c2aad20Sopenharmony_ci					 0, 0, 0, blob_fd_array_off(gen, kdesc->off)));
7307c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_0, 0));
7317c2aad20Sopenharmony_ci	debug_regs(gen, BPF_REG_9, -1, " func (%s:count=%d): btf_fd",
7327c2aad20Sopenharmony_ci		   relo->name, kdesc->ref);
7337c2aad20Sopenharmony_ci}
7347c2aad20Sopenharmony_ci
7357c2aad20Sopenharmony_cistatic void emit_ksym_relo_log(struct bpf_gen *gen, struct ksym_relo_desc *relo,
7367c2aad20Sopenharmony_ci			       int ref)
7377c2aad20Sopenharmony_ci{
7387c2aad20Sopenharmony_ci	if (!gen->log_level)
7397c2aad20Sopenharmony_ci		return;
7407c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_8,
7417c2aad20Sopenharmony_ci			      offsetof(struct bpf_insn, imm)));
7427c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_H, BPF_REG_9, BPF_REG_8, sizeof(struct bpf_insn) +
7437c2aad20Sopenharmony_ci			      offsetof(struct bpf_insn, imm)));
7447c2aad20Sopenharmony_ci	debug_regs(gen, BPF_REG_7, BPF_REG_9, " var t=%d w=%d (%s:count=%d): imm[0]: %%d, imm[1]: %%d",
7457c2aad20Sopenharmony_ci		   relo->is_typeless, relo->is_weak, relo->name, ref);
7467c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code)));
7477c2aad20Sopenharmony_ci	debug_regs(gen, BPF_REG_9, -1, " var t=%d w=%d (%s:count=%d): insn.reg",
7487c2aad20Sopenharmony_ci		   relo->is_typeless, relo->is_weak, relo->name, ref);
7497c2aad20Sopenharmony_ci}
7507c2aad20Sopenharmony_ci
7517c2aad20Sopenharmony_ci/* Expects:
7527c2aad20Sopenharmony_ci * BPF_REG_8 - pointer to instruction
7537c2aad20Sopenharmony_ci */
7547c2aad20Sopenharmony_cistatic void emit_relo_ksym_typeless(struct bpf_gen *gen,
7557c2aad20Sopenharmony_ci				    struct ksym_relo_desc *relo, int insn)
7567c2aad20Sopenharmony_ci{
7577c2aad20Sopenharmony_ci	struct ksym_desc *kdesc;
7587c2aad20Sopenharmony_ci
7597c2aad20Sopenharmony_ci	kdesc = get_ksym_desc(gen, relo);
7607c2aad20Sopenharmony_ci	if (!kdesc)
7617c2aad20Sopenharmony_ci		return;
7627c2aad20Sopenharmony_ci	/* try to copy from existing ldimm64 insn */
7637c2aad20Sopenharmony_ci	if (kdesc->ref > 1) {
7647c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
7657c2aad20Sopenharmony_ci			       kdesc->insn + offsetof(struct bpf_insn, imm));
7667c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
7677c2aad20Sopenharmony_ci			       kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
7687c2aad20Sopenharmony_ci		goto log;
7697c2aad20Sopenharmony_ci	}
7707c2aad20Sopenharmony_ci	/* remember insn offset, so we can copy ksym addr later */
7717c2aad20Sopenharmony_ci	kdesc->insn = insn;
7727c2aad20Sopenharmony_ci	/* skip typeless ksym_desc in fd closing loop in cleanup_relos */
7737c2aad20Sopenharmony_ci	kdesc->typeless = true;
7747c2aad20Sopenharmony_ci	emit_bpf_kallsyms_lookup_name(gen, relo);
7757c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, -ENOENT, 1));
7767c2aad20Sopenharmony_ci	emit_check_err(gen);
7777c2aad20Sopenharmony_ci	/* store lower half of addr into insn[insn_idx].imm */
7787c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9, offsetof(struct bpf_insn, imm)));
7797c2aad20Sopenharmony_ci	/* store upper half of addr into insn[insn_idx + 1].imm */
7807c2aad20Sopenharmony_ci	emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
7817c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9,
7827c2aad20Sopenharmony_ci		      sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
7837c2aad20Sopenharmony_cilog:
7847c2aad20Sopenharmony_ci	emit_ksym_relo_log(gen, relo, kdesc->ref);
7857c2aad20Sopenharmony_ci}
7867c2aad20Sopenharmony_ci
7877c2aad20Sopenharmony_cistatic __u32 src_reg_mask(void)
7887c2aad20Sopenharmony_ci{
7897c2aad20Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD)
7907c2aad20Sopenharmony_ci	return 0x0f; /* src_reg,dst_reg,... */
7917c2aad20Sopenharmony_ci#elif defined(__BIG_ENDIAN_BITFIELD)
7927c2aad20Sopenharmony_ci	return 0xf0; /* dst_reg,src_reg,... */
7937c2aad20Sopenharmony_ci#else
7947c2aad20Sopenharmony_ci#error "Unsupported bit endianness, cannot proceed"
7957c2aad20Sopenharmony_ci#endif
7967c2aad20Sopenharmony_ci}
7977c2aad20Sopenharmony_ci
7987c2aad20Sopenharmony_ci/* Expects:
7997c2aad20Sopenharmony_ci * BPF_REG_8 - pointer to instruction
8007c2aad20Sopenharmony_ci */
8017c2aad20Sopenharmony_cistatic void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn)
8027c2aad20Sopenharmony_ci{
8037c2aad20Sopenharmony_ci	struct ksym_desc *kdesc;
8047c2aad20Sopenharmony_ci	__u32 reg_mask;
8057c2aad20Sopenharmony_ci
8067c2aad20Sopenharmony_ci	kdesc = get_ksym_desc(gen, relo);
8077c2aad20Sopenharmony_ci	if (!kdesc)
8087c2aad20Sopenharmony_ci		return;
8097c2aad20Sopenharmony_ci	/* try to copy from existing ldimm64 insn */
8107c2aad20Sopenharmony_ci	if (kdesc->ref > 1) {
8117c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
8127c2aad20Sopenharmony_ci			       kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
8137c2aad20Sopenharmony_ci		move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
8147c2aad20Sopenharmony_ci			       kdesc->insn + offsetof(struct bpf_insn, imm));
8157c2aad20Sopenharmony_ci		/* jump over src_reg adjustment if imm (btf_id) is not 0, reuse BPF_REG_0 from move_blob2blob
8167c2aad20Sopenharmony_ci		 * If btf_id is zero, clear BPF_PSEUDO_BTF_ID flag in src_reg of ld_imm64 insn
8177c2aad20Sopenharmony_ci		 */
8187c2aad20Sopenharmony_ci		emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 3));
8197c2aad20Sopenharmony_ci		goto clear_src_reg;
8207c2aad20Sopenharmony_ci	}
8217c2aad20Sopenharmony_ci	/* remember insn offset, so we can copy BTF ID and FD later */
8227c2aad20Sopenharmony_ci	kdesc->insn = insn;
8237c2aad20Sopenharmony_ci	emit_bpf_find_by_name_kind(gen, relo);
8247c2aad20Sopenharmony_ci	if (!relo->is_weak)
8257c2aad20Sopenharmony_ci		emit_check_err(gen);
8267c2aad20Sopenharmony_ci	/* jump to success case */
8277c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
8287c2aad20Sopenharmony_ci	/* set values for insn[insn_idx].imm, insn[insn_idx + 1].imm as 0 */
8297c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, offsetof(struct bpf_insn, imm), 0));
8307c2aad20Sopenharmony_ci	emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 0));
8317c2aad20Sopenharmony_ci	/* skip success case for ret < 0 */
8327c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 4));
8337c2aad20Sopenharmony_ci	/* store btf_id into insn[insn_idx].imm */
8347c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7, offsetof(struct bpf_insn, imm)));
8357c2aad20Sopenharmony_ci	/* store btf_obj_fd into insn[insn_idx + 1].imm */
8367c2aad20Sopenharmony_ci	emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 32));
8377c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7,
8387c2aad20Sopenharmony_ci			      sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
8397c2aad20Sopenharmony_ci	/* skip src_reg adjustment */
8407c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 3));
8417c2aad20Sopenharmony_ciclear_src_reg:
8427c2aad20Sopenharmony_ci	/* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */
8437c2aad20Sopenharmony_ci	reg_mask = src_reg_mask();
8447c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code)));
8457c2aad20Sopenharmony_ci	emit(gen, BPF_ALU32_IMM(BPF_AND, BPF_REG_9, reg_mask));
8467c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, offsetofend(struct bpf_insn, code)));
8477c2aad20Sopenharmony_ci
8487c2aad20Sopenharmony_ci	emit_ksym_relo_log(gen, relo, kdesc->ref);
8497c2aad20Sopenharmony_ci}
8507c2aad20Sopenharmony_ci
8517c2aad20Sopenharmony_civoid bpf_gen__record_relo_core(struct bpf_gen *gen,
8527c2aad20Sopenharmony_ci			       const struct bpf_core_relo *core_relo)
8537c2aad20Sopenharmony_ci{
8547c2aad20Sopenharmony_ci	struct bpf_core_relo *relos;
8557c2aad20Sopenharmony_ci
8567c2aad20Sopenharmony_ci	relos = libbpf_reallocarray(gen->core_relos, gen->core_relo_cnt + 1, sizeof(*relos));
8577c2aad20Sopenharmony_ci	if (!relos) {
8587c2aad20Sopenharmony_ci		gen->error = -ENOMEM;
8597c2aad20Sopenharmony_ci		return;
8607c2aad20Sopenharmony_ci	}
8617c2aad20Sopenharmony_ci	gen->core_relos = relos;
8627c2aad20Sopenharmony_ci	relos += gen->core_relo_cnt;
8637c2aad20Sopenharmony_ci	memcpy(relos, core_relo, sizeof(*relos));
8647c2aad20Sopenharmony_ci	gen->core_relo_cnt++;
8657c2aad20Sopenharmony_ci}
8667c2aad20Sopenharmony_ci
8677c2aad20Sopenharmony_cistatic void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insns)
8687c2aad20Sopenharmony_ci{
8697c2aad20Sopenharmony_ci	int insn;
8707c2aad20Sopenharmony_ci
8717c2aad20Sopenharmony_ci	pr_debug("gen: emit_relo (%d): %s at %d %s\n",
8727c2aad20Sopenharmony_ci		 relo->kind, relo->name, relo->insn_idx, relo->is_ld64 ? "ld64" : "call");
8737c2aad20Sopenharmony_ci	insn = insns + sizeof(struct bpf_insn) * relo->insn_idx;
8747c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn));
8757c2aad20Sopenharmony_ci	if (relo->is_ld64) {
8767c2aad20Sopenharmony_ci		if (relo->is_typeless)
8777c2aad20Sopenharmony_ci			emit_relo_ksym_typeless(gen, relo, insn);
8787c2aad20Sopenharmony_ci		else
8797c2aad20Sopenharmony_ci			emit_relo_ksym_btf(gen, relo, insn);
8807c2aad20Sopenharmony_ci	} else {
8817c2aad20Sopenharmony_ci		emit_relo_kfunc_btf(gen, relo, insn);
8827c2aad20Sopenharmony_ci	}
8837c2aad20Sopenharmony_ci}
8847c2aad20Sopenharmony_ci
8857c2aad20Sopenharmony_cistatic void emit_relos(struct bpf_gen *gen, int insns)
8867c2aad20Sopenharmony_ci{
8877c2aad20Sopenharmony_ci	int i;
8887c2aad20Sopenharmony_ci
8897c2aad20Sopenharmony_ci	for (i = 0; i < gen->relo_cnt; i++)
8907c2aad20Sopenharmony_ci		emit_relo(gen, gen->relos + i, insns);
8917c2aad20Sopenharmony_ci}
8927c2aad20Sopenharmony_ci
8937c2aad20Sopenharmony_cistatic void cleanup_core_relo(struct bpf_gen *gen)
8947c2aad20Sopenharmony_ci{
8957c2aad20Sopenharmony_ci	if (!gen->core_relo_cnt)
8967c2aad20Sopenharmony_ci		return;
8977c2aad20Sopenharmony_ci	free(gen->core_relos);
8987c2aad20Sopenharmony_ci	gen->core_relo_cnt = 0;
8997c2aad20Sopenharmony_ci	gen->core_relos = NULL;
9007c2aad20Sopenharmony_ci}
9017c2aad20Sopenharmony_ci
9027c2aad20Sopenharmony_cistatic void cleanup_relos(struct bpf_gen *gen, int insns)
9037c2aad20Sopenharmony_ci{
9047c2aad20Sopenharmony_ci	struct ksym_desc *kdesc;
9057c2aad20Sopenharmony_ci	int i, insn;
9067c2aad20Sopenharmony_ci
9077c2aad20Sopenharmony_ci	for (i = 0; i < gen->nr_ksyms; i++) {
9087c2aad20Sopenharmony_ci		kdesc = &gen->ksyms[i];
9097c2aad20Sopenharmony_ci		/* only close fds for typed ksyms and kfuncs */
9107c2aad20Sopenharmony_ci		if (kdesc->is_ld64 && !kdesc->typeless) {
9117c2aad20Sopenharmony_ci			/* close fd recorded in insn[insn_idx + 1].imm */
9127c2aad20Sopenharmony_ci			insn = kdesc->insn;
9137c2aad20Sopenharmony_ci			insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm);
9147c2aad20Sopenharmony_ci			emit_sys_close_blob(gen, insn);
9157c2aad20Sopenharmony_ci		} else if (!kdesc->is_ld64) {
9167c2aad20Sopenharmony_ci			emit_sys_close_blob(gen, blob_fd_array_off(gen, kdesc->off));
9177c2aad20Sopenharmony_ci			if (kdesc->off < MAX_FD_ARRAY_SZ)
9187c2aad20Sopenharmony_ci				gen->nr_fd_array--;
9197c2aad20Sopenharmony_ci		}
9207c2aad20Sopenharmony_ci	}
9217c2aad20Sopenharmony_ci	if (gen->nr_ksyms) {
9227c2aad20Sopenharmony_ci		free(gen->ksyms);
9237c2aad20Sopenharmony_ci		gen->nr_ksyms = 0;
9247c2aad20Sopenharmony_ci		gen->ksyms = NULL;
9257c2aad20Sopenharmony_ci	}
9267c2aad20Sopenharmony_ci	if (gen->relo_cnt) {
9277c2aad20Sopenharmony_ci		free(gen->relos);
9287c2aad20Sopenharmony_ci		gen->relo_cnt = 0;
9297c2aad20Sopenharmony_ci		gen->relos = NULL;
9307c2aad20Sopenharmony_ci	}
9317c2aad20Sopenharmony_ci	cleanup_core_relo(gen);
9327c2aad20Sopenharmony_ci}
9337c2aad20Sopenharmony_ci
9347c2aad20Sopenharmony_civoid bpf_gen__prog_load(struct bpf_gen *gen,
9357c2aad20Sopenharmony_ci			enum bpf_prog_type prog_type, const char *prog_name,
9367c2aad20Sopenharmony_ci			const char *license, struct bpf_insn *insns, size_t insn_cnt,
9377c2aad20Sopenharmony_ci			struct bpf_prog_load_opts *load_attr, int prog_idx)
9387c2aad20Sopenharmony_ci{
9397c2aad20Sopenharmony_ci	int prog_load_attr, license_off, insns_off, func_info, line_info, core_relos;
9407c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, core_relo_rec_size);
9417c2aad20Sopenharmony_ci	union bpf_attr attr;
9427c2aad20Sopenharmony_ci
9437c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
9447c2aad20Sopenharmony_ci	pr_debug("gen: prog_load: type %d insns_cnt %zd progi_idx %d\n",
9457c2aad20Sopenharmony_ci		 prog_type, insn_cnt, prog_idx);
9467c2aad20Sopenharmony_ci	/* add license string to blob of bytes */
9477c2aad20Sopenharmony_ci	license_off = add_data(gen, license, strlen(license) + 1);
9487c2aad20Sopenharmony_ci	/* add insns to blob of bytes */
9497c2aad20Sopenharmony_ci	insns_off = add_data(gen, insns, insn_cnt * sizeof(struct bpf_insn));
9507c2aad20Sopenharmony_ci
9517c2aad20Sopenharmony_ci	attr.prog_type = prog_type;
9527c2aad20Sopenharmony_ci	attr.expected_attach_type = load_attr->expected_attach_type;
9537c2aad20Sopenharmony_ci	attr.attach_btf_id = load_attr->attach_btf_id;
9547c2aad20Sopenharmony_ci	attr.prog_ifindex = load_attr->prog_ifindex;
9557c2aad20Sopenharmony_ci	attr.kern_version = 0;
9567c2aad20Sopenharmony_ci	attr.insn_cnt = (__u32)insn_cnt;
9577c2aad20Sopenharmony_ci	attr.prog_flags = load_attr->prog_flags;
9587c2aad20Sopenharmony_ci
9597c2aad20Sopenharmony_ci	attr.func_info_rec_size = load_attr->func_info_rec_size;
9607c2aad20Sopenharmony_ci	attr.func_info_cnt = load_attr->func_info_cnt;
9617c2aad20Sopenharmony_ci	func_info = add_data(gen, load_attr->func_info,
9627c2aad20Sopenharmony_ci			     attr.func_info_cnt * attr.func_info_rec_size);
9637c2aad20Sopenharmony_ci
9647c2aad20Sopenharmony_ci	attr.line_info_rec_size = load_attr->line_info_rec_size;
9657c2aad20Sopenharmony_ci	attr.line_info_cnt = load_attr->line_info_cnt;
9667c2aad20Sopenharmony_ci	line_info = add_data(gen, load_attr->line_info,
9677c2aad20Sopenharmony_ci			     attr.line_info_cnt * attr.line_info_rec_size);
9687c2aad20Sopenharmony_ci
9697c2aad20Sopenharmony_ci	attr.core_relo_rec_size = sizeof(struct bpf_core_relo);
9707c2aad20Sopenharmony_ci	attr.core_relo_cnt = gen->core_relo_cnt;
9717c2aad20Sopenharmony_ci	core_relos = add_data(gen, gen->core_relos,
9727c2aad20Sopenharmony_ci			     attr.core_relo_cnt * attr.core_relo_rec_size);
9737c2aad20Sopenharmony_ci
9747c2aad20Sopenharmony_ci	libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
9757c2aad20Sopenharmony_ci	prog_load_attr = add_data(gen, &attr, attr_size);
9767c2aad20Sopenharmony_ci
9777c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to license */
9787c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, license), license_off);
9797c2aad20Sopenharmony_ci
9807c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to instructions */
9817c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, insns), insns_off);
9827c2aad20Sopenharmony_ci
9837c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to func_info */
9847c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, func_info), func_info);
9857c2aad20Sopenharmony_ci
9867c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to line_info */
9877c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, line_info), line_info);
9887c2aad20Sopenharmony_ci
9897c2aad20Sopenharmony_ci	/* populate union bpf_attr with a pointer to core_relos */
9907c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, core_relos), core_relos);
9917c2aad20Sopenharmony_ci
9927c2aad20Sopenharmony_ci	/* populate union bpf_attr fd_array with a pointer to data where map_fds are saved */
9937c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(prog_load_attr, fd_array), gen->fd_array);
9947c2aad20Sopenharmony_ci
9957c2aad20Sopenharmony_ci	/* populate union bpf_attr with user provided log details */
9967c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(prog_load_attr, log_level), 4,
9977c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_level), false);
9987c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(prog_load_attr, log_size), 4,
9997c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_size), false);
10007c2aad20Sopenharmony_ci	move_ctx2blob(gen, attr_field(prog_load_attr, log_buf), 8,
10017c2aad20Sopenharmony_ci		      offsetof(struct bpf_loader_ctx, log_buf), false);
10027c2aad20Sopenharmony_ci	/* populate union bpf_attr with btf_fd saved in the stack earlier */
10037c2aad20Sopenharmony_ci	move_stack2blob(gen, attr_field(prog_load_attr, prog_btf_fd), 4,
10047c2aad20Sopenharmony_ci			stack_off(btf_fd));
10057c2aad20Sopenharmony_ci	if (gen->attach_kind) {
10067c2aad20Sopenharmony_ci		emit_find_attach_target(gen);
10077c2aad20Sopenharmony_ci		/* populate union bpf_attr with btf_id and btf_obj_fd found by helper */
10087c2aad20Sopenharmony_ci		emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
10097c2aad20Sopenharmony_ci						 0, 0, 0, prog_load_attr));
10107c2aad20Sopenharmony_ci		emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7,
10117c2aad20Sopenharmony_ci				      offsetof(union bpf_attr, attach_btf_id)));
10127c2aad20Sopenharmony_ci		emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 32));
10137c2aad20Sopenharmony_ci		emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7,
10147c2aad20Sopenharmony_ci				      offsetof(union bpf_attr, attach_btf_obj_fd)));
10157c2aad20Sopenharmony_ci	}
10167c2aad20Sopenharmony_ci	emit_relos(gen, insns_off);
10177c2aad20Sopenharmony_ci	/* emit PROG_LOAD command */
10187c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_PROG_LOAD, prog_load_attr, attr_size);
10197c2aad20Sopenharmony_ci	debug_ret(gen, "prog_load %s insn_cnt %d", attr.prog_name, attr.insn_cnt);
10207c2aad20Sopenharmony_ci	/* successful or not, close btf module FDs used in extern ksyms and attach_btf_obj_fd */
10217c2aad20Sopenharmony_ci	cleanup_relos(gen, insns_off);
10227c2aad20Sopenharmony_ci	if (gen->attach_kind) {
10237c2aad20Sopenharmony_ci		emit_sys_close_blob(gen,
10247c2aad20Sopenharmony_ci				    attr_field(prog_load_attr, attach_btf_obj_fd));
10257c2aad20Sopenharmony_ci		gen->attach_kind = 0;
10267c2aad20Sopenharmony_ci	}
10277c2aad20Sopenharmony_ci	emit_check_err(gen);
10287c2aad20Sopenharmony_ci	/* remember prog_fd in the stack, if successful */
10297c2aad20Sopenharmony_ci	emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7,
10307c2aad20Sopenharmony_ci			      stack_off(prog_fd[gen->nr_progs])));
10317c2aad20Sopenharmony_ci	gen->nr_progs++;
10327c2aad20Sopenharmony_ci}
10337c2aad20Sopenharmony_ci
10347c2aad20Sopenharmony_civoid bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
10357c2aad20Sopenharmony_ci			      __u32 value_size)
10367c2aad20Sopenharmony_ci{
10377c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, flags);
10387c2aad20Sopenharmony_ci	int map_update_attr, value, key;
10397c2aad20Sopenharmony_ci	union bpf_attr attr;
10407c2aad20Sopenharmony_ci	int zero = 0;
10417c2aad20Sopenharmony_ci
10427c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
10437c2aad20Sopenharmony_ci	pr_debug("gen: map_update_elem: idx %d\n", map_idx);
10447c2aad20Sopenharmony_ci
10457c2aad20Sopenharmony_ci	value = add_data(gen, pvalue, value_size);
10467c2aad20Sopenharmony_ci	key = add_data(gen, &zero, sizeof(zero));
10477c2aad20Sopenharmony_ci
10487c2aad20Sopenharmony_ci	/* if (map_desc[map_idx].initial_value) {
10497c2aad20Sopenharmony_ci	 *    if (ctx->flags & BPF_SKEL_KERNEL)
10507c2aad20Sopenharmony_ci	 *        bpf_probe_read_kernel(value, value_size, initial_value);
10517c2aad20Sopenharmony_ci	 *    else
10527c2aad20Sopenharmony_ci	 *        bpf_copy_from_user(value, value_size, initial_value);
10537c2aad20Sopenharmony_ci	 * }
10547c2aad20Sopenharmony_ci	 */
10557c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_6,
10567c2aad20Sopenharmony_ci			      sizeof(struct bpf_loader_ctx) +
10577c2aad20Sopenharmony_ci			      sizeof(struct bpf_map_desc) * map_idx +
10587c2aad20Sopenharmony_ci			      offsetof(struct bpf_map_desc, initial_value)));
10597c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 8));
10607c2aad20Sopenharmony_ci	emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
10617c2aad20Sopenharmony_ci					 0, 0, 0, value));
10627c2aad20Sopenharmony_ci	emit(gen, BPF_MOV64_IMM(BPF_REG_2, value_size));
10637c2aad20Sopenharmony_ci	emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6,
10647c2aad20Sopenharmony_ci			      offsetof(struct bpf_loader_ctx, flags)));
10657c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JSET, BPF_REG_0, BPF_SKEL_KERNEL, 2));
10667c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_copy_from_user));
10677c2aad20Sopenharmony_ci	emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
10687c2aad20Sopenharmony_ci	emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
10697c2aad20Sopenharmony_ci
10707c2aad20Sopenharmony_ci	map_update_attr = add_data(gen, &attr, attr_size);
10717c2aad20Sopenharmony_ci	move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4,
10727c2aad20Sopenharmony_ci		       blob_fd_array_off(gen, map_idx));
10737c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(map_update_attr, key), key);
10747c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(map_update_attr, value), value);
10757c2aad20Sopenharmony_ci	/* emit MAP_UPDATE_ELEM command */
10767c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_MAP_UPDATE_ELEM, map_update_attr, attr_size);
10777c2aad20Sopenharmony_ci	debug_ret(gen, "update_elem idx %d value_size %d", map_idx, value_size);
10787c2aad20Sopenharmony_ci	emit_check_err(gen);
10797c2aad20Sopenharmony_ci}
10807c2aad20Sopenharmony_ci
10817c2aad20Sopenharmony_civoid bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int slot,
10827c2aad20Sopenharmony_ci				 int inner_map_idx)
10837c2aad20Sopenharmony_ci{
10847c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, flags);
10857c2aad20Sopenharmony_ci	int map_update_attr, key;
10867c2aad20Sopenharmony_ci	union bpf_attr attr;
10877c2aad20Sopenharmony_ci
10887c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
10897c2aad20Sopenharmony_ci	pr_debug("gen: populate_outer_map: outer %d key %d inner %d\n",
10907c2aad20Sopenharmony_ci		 outer_map_idx, slot, inner_map_idx);
10917c2aad20Sopenharmony_ci
10927c2aad20Sopenharmony_ci	key = add_data(gen, &slot, sizeof(slot));
10937c2aad20Sopenharmony_ci
10947c2aad20Sopenharmony_ci	map_update_attr = add_data(gen, &attr, attr_size);
10957c2aad20Sopenharmony_ci	move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4,
10967c2aad20Sopenharmony_ci		       blob_fd_array_off(gen, outer_map_idx));
10977c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(map_update_attr, key), key);
10987c2aad20Sopenharmony_ci	emit_rel_store(gen, attr_field(map_update_attr, value),
10997c2aad20Sopenharmony_ci		       blob_fd_array_off(gen, inner_map_idx));
11007c2aad20Sopenharmony_ci
11017c2aad20Sopenharmony_ci	/* emit MAP_UPDATE_ELEM command */
11027c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_MAP_UPDATE_ELEM, map_update_attr, attr_size);
11037c2aad20Sopenharmony_ci	debug_ret(gen, "populate_outer_map outer %d key %d inner %d",
11047c2aad20Sopenharmony_ci		  outer_map_idx, slot, inner_map_idx);
11057c2aad20Sopenharmony_ci	emit_check_err(gen);
11067c2aad20Sopenharmony_ci}
11077c2aad20Sopenharmony_ci
11087c2aad20Sopenharmony_civoid bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx)
11097c2aad20Sopenharmony_ci{
11107c2aad20Sopenharmony_ci	int attr_size = offsetofend(union bpf_attr, map_fd);
11117c2aad20Sopenharmony_ci	int map_freeze_attr;
11127c2aad20Sopenharmony_ci	union bpf_attr attr;
11137c2aad20Sopenharmony_ci
11147c2aad20Sopenharmony_ci	memset(&attr, 0, attr_size);
11157c2aad20Sopenharmony_ci	pr_debug("gen: map_freeze: idx %d\n", map_idx);
11167c2aad20Sopenharmony_ci	map_freeze_attr = add_data(gen, &attr, attr_size);
11177c2aad20Sopenharmony_ci	move_blob2blob(gen, attr_field(map_freeze_attr, map_fd), 4,
11187c2aad20Sopenharmony_ci		       blob_fd_array_off(gen, map_idx));
11197c2aad20Sopenharmony_ci	/* emit MAP_FREEZE command */
11207c2aad20Sopenharmony_ci	emit_sys_bpf(gen, BPF_MAP_FREEZE, map_freeze_attr, attr_size);
11217c2aad20Sopenharmony_ci	debug_ret(gen, "map_freeze");
11227c2aad20Sopenharmony_ci	emit_check_err(gen);
11237c2aad20Sopenharmony_ci}
1124