1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3 #include "vmlinux.h"
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 #include <bpf/bpf_core_read.h>
7 #include "bpf_misc.h"
8 
9 char _license[] SEC("license") = "GPL";
10 
11 static long stack[256];
12 
13 /*
14  * KPROBE contexts
15  */
16 
kprobe_typedef_ctx_subprog(bpf_user_pt_regs_t * ctx)17 __weak int kprobe_typedef_ctx_subprog(bpf_user_pt_regs_t *ctx)
18 {
19 	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
20 }
21 
22 SEC("?kprobe")
23 __success
kprobe_typedef_ctx(void * ctx)24 int kprobe_typedef_ctx(void *ctx)
25 {
26 	return kprobe_typedef_ctx_subprog(ctx);
27 }
28 
29 #define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL)))
30 
kprobe_struct_ctx_subprog(pt_regs_struct_t * ctx)31 __weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx)
32 {
33 	return bpf_get_stack((void *)ctx, &stack, sizeof(stack), 0);
34 }
35 
36 SEC("?kprobe")
37 __success
kprobe_resolved_ctx(void * ctx)38 int kprobe_resolved_ctx(void *ctx)
39 {
40 	return kprobe_struct_ctx_subprog(ctx);
41 }
42 
43 /* this is current hack to make this work on old kernels */
44 struct bpf_user_pt_regs_t {};
45 
kprobe_workaround_ctx_subprog(struct bpf_user_pt_regs_t * ctx)46 __weak int kprobe_workaround_ctx_subprog(struct bpf_user_pt_regs_t *ctx)
47 {
48 	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
49 }
50 
51 SEC("?kprobe")
52 __success
kprobe_workaround_ctx(void * ctx)53 int kprobe_workaround_ctx(void *ctx)
54 {
55 	return kprobe_workaround_ctx_subprog(ctx);
56 }
57 
58 /*
59  * RAW_TRACEPOINT contexts
60  */
61 
raw_tp_ctx_subprog(struct bpf_raw_tracepoint_args * ctx)62 __weak int raw_tp_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
63 {
64 	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
65 }
66 
67 SEC("?raw_tp")
68 __success
raw_tp_ctx(void * ctx)69 int raw_tp_ctx(void *ctx)
70 {
71 	return raw_tp_ctx_subprog(ctx);
72 }
73 
74 /*
75  * RAW_TRACEPOINT_WRITABLE contexts
76  */
77 
raw_tp_writable_ctx_subprog(struct bpf_raw_tracepoint_args * ctx)78 __weak int raw_tp_writable_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
79 {
80 	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
81 }
82 
83 SEC("?raw_tp")
84 __success
raw_tp_writable_ctx(void * ctx)85 int raw_tp_writable_ctx(void *ctx)
86 {
87 	return raw_tp_writable_ctx_subprog(ctx);
88 }
89 
90 /*
91  * PERF_EVENT contexts
92  */
93 
perf_event_ctx_subprog(struct bpf_perf_event_data * ctx)94 __weak int perf_event_ctx_subprog(struct bpf_perf_event_data *ctx)
95 {
96 	return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
97 }
98 
99 SEC("?perf_event")
100 __success
perf_event_ctx(void * ctx)101 int perf_event_ctx(void *ctx)
102 {
103 	return perf_event_ctx_subprog(ctx);
104 }
105 
106 /* this global subprog can be now called from many types of entry progs, each
107  * with different context type
108  */
subprog_ctx_tag(void * ctx __arg_ctx)109 __weak int subprog_ctx_tag(void *ctx __arg_ctx)
110 {
111 	return bpf_get_stack(ctx, stack, sizeof(stack), 0);
112 }
113 
114 struct my_struct { int x; };
115 
subprog_multi_ctx_tags(void * ctx1 __arg_ctx,struct my_struct * mem,void * ctx2 __arg_ctx)116 __weak int subprog_multi_ctx_tags(void *ctx1 __arg_ctx,
117 				  struct my_struct *mem,
118 				  void *ctx2 __arg_ctx)
119 {
120 	if (!mem)
121 		return 0;
122 
123 	return bpf_get_stack(ctx1, stack, sizeof(stack), 0) +
124 	       mem->x +
125 	       bpf_get_stack(ctx2, stack, sizeof(stack), 0);
126 }
127 
128 SEC("?raw_tp")
129 __success __log_level(2)
arg_tag_ctx_raw_tp(void * ctx)130 int arg_tag_ctx_raw_tp(void *ctx)
131 {
132 	struct my_struct x = { .x = 123 };
133 
134 	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
135 }
136 
137 SEC("?perf_event")
138 __success __log_level(2)
arg_tag_ctx_perf(void * ctx)139 int arg_tag_ctx_perf(void *ctx)
140 {
141 	struct my_struct x = { .x = 123 };
142 
143 	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
144 }
145 
146 SEC("?kprobe")
147 __success __log_level(2)
arg_tag_ctx_kprobe(void * ctx)148 int arg_tag_ctx_kprobe(void *ctx)
149 {
150 	struct my_struct x = { .x = 123 };
151 
152 	return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx);
153 }
154