#include <uapi/linux/bpf.h>
struct bpf_map_def {
       unsigned int type;
       unsigned int key_size;
       unsigned int value_size;
       unsigned int max_entries;
};

#define SEC(NAME) __attribute__((section(NAME), used))

#define syscall_enter(name) \
	SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name(void *__ctx__)

#define syscall_exit(name) \
	SEC("syscalls:sys_exit_" #name) syscall_exit_ ## name(void *__ctx__)

#define syscall_field_str(field, offset) \
	({ char *__ptr = *((char **)(__ctx__ + offset)); \
	   bpf_probe_read_str(field, sizeof(field), __ptr); })

#define syscall_field_int(field, offset) \
	({ int *__ptr = (int *)(__ctx__ + offset); \
	   bpf_probe_read(&field, sizeof(field), __ptr); })

#define tracepoint(name) SEC(#name) #name

static int (*get_smp_processor_id)(void) =
       (void *)BPF_FUNC_get_smp_processor_id;
static int (*perf_event_output)(void *, struct bpf_map_def *, int, void *, unsigned long) =
       (void *)BPF_FUNC_perf_event_output;
static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_addr) =
       (void *)BPF_FUNC_probe_read;
static int (*bpf_probe_read_str)(void *dst, int size, const void *unsafe_addr) =
       (void *)BPF_FUNC_probe_read_str;
static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
	(void *)BPF_FUNC_trace_printk;

#define trace_puts(fmt) ({ char __fmt[] = fmt; trace_printk(__fmt, sizeof(__fmt)); })

struct bpf_map_def SEC("maps") __bpf_stdout__ = {
       .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
       .key_size = sizeof(int),
       .value_size = sizeof(u32),
       .max_entries = __NR_CPUS__,
};

#define perf_stdout(from, len) \
	perf_event_output(__ctx__, &__bpf_stdout__, BPF_F_CURRENT_CPU, \
			  &from, len & (sizeof(from) - 1));

char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
