194575Sdes// SPDX-License-Identifier: GPL-2.0
294575Sdes/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
394575Sdes#include "vmlinux.h"
494575Sdes#include <bpf/bpf_helpers.h>
594575Sdes#include <bpf/bpf_tracing.h>
694575Sdes#include <bpf/bpf_core_read.h>
794575Sdes#include "bpf_misc.h"
894575Sdes
994575Sdeschar _license[] SEC("license") = "GPL";
1094575Sdes
1194575Sdesstatic long stack[256];
1294575Sdes
1394575Sdes/*
1494575Sdes * KPROBE contexts
1594575Sdes */
1694575Sdes
1794575Sdes__weak int kprobe_typedef_ctx_subprog(bpf_user_pt_regs_t *ctx)
1894575Sdes{
1994575Sdes	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
2094575Sdes}
2194575Sdes
2294575SdesSEC("?kprobe")
2394575Sdes__success
2494575Sdesint kprobe_typedef_ctx(void *ctx)
2594575Sdes{
2694575Sdes	return kprobe_typedef_ctx_subprog(ctx);
2794575Sdes}
2894575Sdes
2994575Sdes/* s390x defines:
3094575Sdes *
3194575Sdes * typedef user_pt_regs bpf_user_pt_regs_t;
3294575Sdes * typedef struct { ... } user_pt_regs;
3394575Sdes *
3494575Sdes * And so "canonical" underlying struct type is anonymous.
3594575Sdes * So on s390x only valid ways to have PTR_TO_CTX argument in global subprogs
3694575Sdes * are:
3794577Sdes *   - bpf_user_pt_regs_t *ctx (typedef);
3894577Sdes *   - struct bpf_user_pt_regs_t *ctx (backwards compatible struct hack);
3994577Sdes *   - void *ctx __arg_ctx (arg:ctx tag)
4094577Sdes *
4194575Sdes * Other architectures also allow using underlying struct types (e.g.,
4294575Sdes * `struct pt_regs *ctx` for x86-64)
4394577Sdes */
4494577Sdes#ifndef bpf_target_s390
4594575Sdes
4694575Sdes#define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL)))
4794575Sdes
4894577Sdes__weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx)
4994575Sdes{
5094575Sdes	return bpf_get_stack((void *)ctx, &stack, sizeof(stack), 0);
5194575Sdes}
5294575Sdes
5394575SdesSEC("?kprobe")
5494577Sdes__success
5594575Sdesint kprobe_resolved_ctx(void *ctx)
5694577Sdes{
57116393Smbr	return kprobe_struct_ctx_subprog(ctx);
5894577Sdes}
5996198Sdes
6096198Sdes#endif
6196198Sdes
6296198Sdes/* this is current hack to make this work on old kernels */
6396198Sdesstruct bpf_user_pt_regs_t {};
6494575Sdes
6596198Sdes__weak int kprobe_workaround_ctx_subprog(struct bpf_user_pt_regs_t *ctx)
6694575Sdes{
67116393Smbr	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
68116393Smbr}
69116393Smbr
70116393SmbrSEC("?kprobe")
7194575Sdes__success
72116393Smbrint kprobe_workaround_ctx(void *ctx)
7394575Sdes{
7494575Sdes	return kprobe_workaround_ctx_subprog(ctx);
7594575Sdes}
7694575Sdes
7794575Sdes/*
7894575Sdes * RAW_TRACEPOINT contexts
7994577Sdes */
8094577Sdes
8196198Sdes__weak int raw_tp_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
8294577Sdes{
83116393Smbr	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
84116393Smbr}
85116393Smbr
86116393SmbrSEC("?raw_tp")
87116393Smbr__success
88116393Smbrint raw_tp_ctx(void *ctx)
8994577Sdes{
90116393Smbr	return raw_tp_ctx_subprog(ctx);
91116393Smbr}
92116393Smbr
93116393Smbr/*
94116393Smbr * RAW_TRACEPOINT_WRITABLE contexts
9594577Sdes */
96116393Smbr
97116393Smbr__weak int raw_tp_writable_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
98116393Smbr{
99116393Smbr	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
100116393Smbr}
101116393Smbr
102116393SmbrSEC("?raw_tp")
103116393Smbr__success
104116393Smbrint raw_tp_writable_ctx(void *ctx)
105116393Smbr{
106116393Smbr	return raw_tp_writable_ctx_subprog(ctx);
107116393Smbr}
108116393Smbr
109116393Smbr/*
110116393Smbr * PERF_EVENT contexts
111116393Smbr */
11294577Sdes
11394577Sdes__weak int perf_event_ctx_subprog(struct bpf_perf_event_data *ctx)
11494577Sdes{
11596198Sdes	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
11696198Sdes}
11796198Sdes
11896198SdesSEC("?perf_event")
11996198Sdes__success
12096198Sdesint perf_event_ctx(void *ctx)
12196198Sdes{
12296198Sdes	return perf_event_ctx_subprog(ctx);
12396198Sdes}
124116393Smbr
12596198Sdes/* this global subprog can be now called from many types of entry progs, each
12696198Sdes * with different context type
12796198Sdes */
12896198Sdes__weak int subprog_ctx_tag(void *ctx __arg_ctx)
12996198Sdes{
13096198Sdes	return bpf_get_stack(ctx, stack, sizeof(stack), 0);
13194577Sdes}
13294577Sdes
13394577Sdesstruct my_struct { int x; };
13494577Sdes
13594577Sdes__weak int subprog_multi_ctx_tags(void *ctx1 __arg_ctx,
13694577Sdes				  struct my_struct *mem,
137116393Smbr				  void *ctx2 __arg_ctx)
13894577Sdes{
13994577Sdes	if (!mem)
14094577Sdes		return 0;
14194577Sdes
142116393Smbr	return bpf_get_stack(ctx1, stack, sizeof(stack), 0) +
14394577Sdes	       mem->x +
14494577Sdes	       bpf_get_stack(ctx2, stack, sizeof(stack), 0);
14594577Sdes}
14694577Sdes
14794577SdesSEC("?raw_tp")
14894577Sdes__success __log_level(2)
14994577Sdesint arg_tag_ctx_raw_tp(void *ctx)
15094577Sdes{
15194577Sdes	struct my_struct x = { .x = 123 };
15294577Sdes
153116393Smbr	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
154116393Smbr}
15594577Sdes
15694577SdesSEC("?perf_event")
15794577Sdes__success __log_level(2)
15894577Sdesint arg_tag_ctx_perf(void *ctx)
15994577Sdes{
160116393Smbr	struct my_struct x = { .x = 123 };
16194577Sdes
16294577Sdes	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
16394577Sdes}
16494577Sdes
16594577SdesSEC("?kprobe")
16694577Sdes__success __log_level(2)
167116393Smbrint arg_tag_ctx_kprobe(void *ctx)
168116393Smbr{
169116393Smbr	struct my_struct x = { .x = 123 };
170116393Smbr
171116393Smbr	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
172116393Smbr}
173116393Smbr