/* SPDX-License-Identifier: Apache-2.0 */

#ifndef __MACROS_H
#define __MACROS_H

// Internal helpers to concatenate two tokens. Do not use directly
#define __CONCAT_IMPL(x, y) x##y
#define __CONCAT(x, y) __CONCAT_IMPL(x, y)

// Internal helpers to count the number of arguments. Do not use directly
#define __VA_NARGS_IMPL(_1, _2, _3, _4, N, ...) N
#define __VA_NARGS(...) __VA_NARGS_IMPL(__VA_ARGS__, 4, 3, 2, 1)

// Internal helpers to expand the snapshotter's programs. Do not use directly
#define __GADGET_ITER_PROGRAMS_EXPAND_1(name, type, programName1)    \
	const void *gadget_iter_##name##___##type##___##programName1 \
		__attribute__((unused));
#define __GADGET_ITER_PROGRAMS_EXPAND_2(name, type, programName1,                   \
					programName2)                               \
	const void *                                                                \
		gadget_iter_##name##___##type##___##programName1##___##programName2 \
		__attribute__((unused));
#define __GADGET_ITER_PROGRAMS_EXPAND_3(name, type, programName1,                                      \
					programName2, programName3)                                    \
	const void *                                                                                   \
		gadget_iter_##name##___##type##___##programName1##___##programName2##___##programName3 \
		__attribute__((unused));
#define __GADGET_ITER_PROGRAMS_EXPAND(name, type, nargs, ...) \
	__CONCAT(__GADGET_ITER_PROGRAMS_EXPAND_, nargs)       \
	(name, type, __VA_ARGS__)
#define __GADGET_ITER_IMPL(name, type, ...)                                \
	__GADGET_ITER_PROGRAMS_EXPAND(name, type, __VA_NARGS(__VA_ARGS__), \
				      __VA_ARGS__)

// Public macros. Use these in your code
// Keep this aligned with pkg/gadgets/run/types/metadata.go

// GADGET_TRACER is used to define a tracer. Currently only one tracer per eBPF object is allowed.
// name is the tracer's name
// map_name is the name of the perf event array or ring buffer maps used to send events to user
// space
// event_type is the name of the structure that describes the event
#define GADGET_TRACER(name, map_name, event_type)                        \
	const void *gadget_tracer_##name##___##map_name##___##event_type \
		__attribute__((unused));                                 \
	const struct event_type *__gadget_tracer_type_##name             \
		__attribute__((unused));

// GADGET_PARAM is used to indicate that a given variable is used as a parameter.
// Users of Inspektor Gadget can set these values from userspace
#define GADGET_PARAM(name) \
	const void *gadget_param_##name __attribute__((unused));

// GADGET_SNAPSHOTTER is used to define a snapshotter:
// name is the snapshotter's name
// type is the name of the structure that describes each element in a snapshot
// ... is the variadic list of programs (min 1, max 3) that generate a snapshot
// The snapshotter's output will be the union of the snapshots generated by the programs
// Deprecated: please use GADGET_ITER() instead
#define GADGET_SNAPSHOTTER(name, type, ...)              \
	const struct type *unusedevent_##name##___##type \
		__attribute__((unused));                 \
	__GADGET_ITER_IMPL(name, type, __VA_ARGS__)

// GADGET_ITER is used to define an iterator:
// name is the iterator's name
// type is the name of the structure that describes each element in an iterator
// ... is the variadic list of programs (min 1, max 3) that generate an iterator
// The iterator's output will be the union of the entries returned by the individual iter programs
#define GADGET_ITER(name, type, ...)                     \
	const struct type *unusedevent_##name##___##type \
		__attribute__((unused));                 \
	__GADGET_ITER_IMPL(name, type, __VA_ARGS__)

// GADGET_MAPITER defines maps that IG should periodically fetch into data sources
// - name is the name of the map iterator
// - mapname is the name of the hash map used to send events to user space.
#define GADGET_MAPITER(name, mapname) \
	const void *gadget_mapiter_##name##___##mapname __attribute__((unused));

// GADGET_ITER_TARGET_MAP binds a BPF iter program declared with
// SEC("iter/bpf_map_elem") to the map it should iterate over. The kernel
// requires the target map FD at attach time; this macro tells IG which map
// to pass to bpf_link_create's iter_info.map_fd. Use together with
// GADGET_ITER(name, event_type, prog_name).
//
// Example:
//
//   struct {
//       __uint(type, BPF_MAP_TYPE_LRU_HASH);
//       __uint(max_entries, 4096);
//       __type(key,   struct mykey);
//       __type(value, struct myval);
//       __uint(pinning, LIBBPF_PIN_BY_NAME);
//   } my_pinned_map SEC(".maps");
//
//   GADGET_ITER(my_iter, my_event, dump_my_map);
//   GADGET_ITER_TARGET_MAP(dump_my_map, my_pinned_map);
//
//   SEC("iter/bpf_map_elem")
//   int dump_my_map(struct bpf_iter__bpf_map_elem *ctx) { ... }
//
// - prog_name is the BPF iter program (SEC("iter/bpf_map_elem")).
// - mapname is the map declared in this object (commonly LIBBPF_PIN_BY_NAME).
#define GADGET_ITER_TARGET_MAP(prog_name, mapname)                       \
	const void *gadget_mapelem_iter_target_##prog_name##___##mapname \
		__attribute__((unused));

// GADGET_SK_TARGET_MAP binds an sk_skb or sk_msg program to the sockmap or
// sockhash where it should be attached.
#define GADGET_SK_TARGET_MAP(prog_name, mapname)                    \
	const void *gadget_sk_prog_target_##prog_name##___##mapname \
		__attribute__((unused));

#endif /* __MACROS_H */
