// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ #include "vmlinux.h" #include #include #include #include "bpf_misc.h" char _license[] SEC("license") = "GPL"; static long stack[256]; /* * KPROBE contexts */ __weak int kprobe_typedef_ctx_subprog(bpf_user_pt_regs_t *ctx) { return bpf_get_stack(ctx, &stack, sizeof(stack), 0); } SEC("?kprobe") __success int kprobe_typedef_ctx(void *ctx) { return kprobe_typedef_ctx_subprog(ctx); } /* s390x defines: * * typedef user_pt_regs bpf_user_pt_regs_t; * typedef struct { ... } user_pt_regs; * * And so "canonical" underlying struct type is anonymous. * So on s390x only valid ways to have PTR_TO_CTX argument in global subprogs * are: * - bpf_user_pt_regs_t *ctx (typedef); * - struct bpf_user_pt_regs_t *ctx (backwards compatible struct hack); * - void *ctx __arg_ctx (arg:ctx tag) * * Other architectures also allow using underlying struct types (e.g., * `struct pt_regs *ctx` for x86-64) */ #ifndef bpf_target_s390 #define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL))) __weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx) { return bpf_get_stack((void *)ctx, &stack, sizeof(stack), 0); } SEC("?kprobe") __success int kprobe_resolved_ctx(void *ctx) { return kprobe_struct_ctx_subprog(ctx); } #endif /* this is current hack to make this work on old kernels */ struct bpf_user_pt_regs_t {}; __weak int kprobe_workaround_ctx_subprog(struct bpf_user_pt_regs_t *ctx) { return bpf_get_stack(ctx, &stack, sizeof(stack), 0); } SEC("?kprobe") __success int kprobe_workaround_ctx(void *ctx) { return kprobe_workaround_ctx_subprog(ctx); } /* * RAW_TRACEPOINT contexts */ __weak int raw_tp_ctx_subprog(struct bpf_raw_tracepoint_args *ctx) { return bpf_get_stack(ctx, &stack, sizeof(stack), 0); } SEC("?raw_tp") __success int raw_tp_ctx(void *ctx) { return raw_tp_ctx_subprog(ctx); } /* * RAW_TRACEPOINT_WRITABLE contexts */ __weak int raw_tp_writable_ctx_subprog(struct bpf_raw_tracepoint_args *ctx) { return bpf_get_stack(ctx, &stack, sizeof(stack), 0); } SEC("?raw_tp") __success int raw_tp_writable_ctx(void *ctx) { return raw_tp_writable_ctx_subprog(ctx); } /* * PERF_EVENT contexts */ __weak int perf_event_ctx_subprog(struct bpf_perf_event_data *ctx) { return bpf_get_stack(ctx, &stack, sizeof(stack), 0); } SEC("?perf_event") __success int perf_event_ctx(void *ctx) { return perf_event_ctx_subprog(ctx); } /* this global subprog can be now called from many types of entry progs, each * with different context type */ __weak int subprog_ctx_tag(void *ctx __arg_ctx) { return bpf_get_stack(ctx, stack, sizeof(stack), 0); } struct my_struct { int x; }; __weak int subprog_multi_ctx_tags(void *ctx1 __arg_ctx, struct my_struct *mem, void *ctx2 __arg_ctx) { if (!mem) return 0; return bpf_get_stack(ctx1, stack, sizeof(stack), 0) + mem->x + bpf_get_stack(ctx2, stack, sizeof(stack), 0); } SEC("?raw_tp") __success __log_level(2) int arg_tag_ctx_raw_tp(void *ctx) { struct my_struct x = { .x = 123 }; return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); } SEC("?perf_event") __success __log_level(2) int arg_tag_ctx_perf(void *ctx) { struct my_struct x = { .x = 123 }; return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); } SEC("?kprobe") __success __log_level(2) int arg_tag_ctx_kprobe(void *ctx) { struct my_struct x = { .x = 123 }; return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); }